Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.31-rc2 460 lines 12 kB view raw
1/* 2 * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based) 3 * 4 * (C) 2000 Nicolas Pitre <nico@cam.org> 5 * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com> 6 * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes 7 */ 8 9#include <linux/module.h> 10#include <linux/types.h> 11#include <linux/kernel.h> 12#include <linux/spinlock.h> 13#include <linux/init.h> 14#include <linux/slab.h> 15#include <asm/page.h> 16#include <asm/mach-types.h> 17#include <asm/system.h> 18#include <asm/errno.h> 19 20#include <linux/mtd/mtd.h> 21#include <linux/mtd/map.h> 22#include <linux/mtd/partitions.h> 23#ifdef CONFIG_MTD_CONCAT 24#include <linux/mtd/concat.h> 25#endif 26 27#include <mach/hardware.h> 28#include <mach/h3600.h> 29#include <asm/io.h> 30 31 32#ifndef CONFIG_IPAQ_HANDHELD 33#error This is for iPAQ Handhelds only 34#endif 35#ifdef CONFIG_SA1100_JORNADA56X 36 37static void jornada56x_set_vpp(struct map_info *map, int vpp) 38{ 39 if (vpp) 40 GPSR = GPIO_GPIO26; 41 else 42 GPCR = GPIO_GPIO26; 43 GPDR |= GPIO_GPIO26; 44} 45 46#endif 47 48#ifdef CONFIG_SA1100_JORNADA720 49 50static void jornada720_set_vpp(struct map_info *map, int vpp) 51{ 52 if (vpp) 53 PPSR |= 0x80; 54 else 55 PPSR &= ~0x80; 56 PPDR |= 0x80; 57} 58 59#endif 60 61#define MAX_IPAQ_CS 2 /* Number of CS we are going to test */ 62 63#define IPAQ_MAP_INIT(X) \ 64 { \ 65 name: "IPAQ flash " X, \ 66 } 67 68 69static struct map_info ipaq_map[MAX_IPAQ_CS] = { 70 IPAQ_MAP_INIT("bank 1"), 71 IPAQ_MAP_INIT("bank 2") 72}; 73 74static struct mtd_info *my_sub_mtd[MAX_IPAQ_CS] = { 75 NULL, 76 NULL 77}; 78 79/* 80 * Here are partition information for all known IPAQ-based devices. 81 * See include/linux/mtd/partitions.h for definition of the mtd_partition 82 * structure. 83 * 84 * The *_max_flash_size is the maximum possible mapped flash size which 85 * is not necessarily the actual flash size. It must be no more than 86 * the value specified in the "struct map_desc *_io_desc" mapping 87 * definition for the corresponding machine. 88 * 89 * Please keep these in alphabetical order, and formatted as per existing 90 * entries. Thanks. 91 */ 92 93#ifdef CONFIG_IPAQ_HANDHELD 94static unsigned long h3xxx_max_flash_size = 0x04000000; 95static struct mtd_partition h3xxx_partitions[] = { 96 { 97 name: "H3XXX boot firmware", 98#ifndef CONFIG_LAB 99 size: 0x00040000, 100#else 101 size: 0x00080000, 102#endif 103 offset: 0, 104#ifndef CONFIG_LAB 105 mask_flags: MTD_WRITEABLE, /* force read-only */ 106#endif 107 }, 108 { 109 name: "H3XXX root jffs2", 110#ifndef CONFIG_LAB 111 size: 0x2000000 - 2*0x40000, /* Warning, this is fixed later */ 112 offset: 0x00040000, 113#else 114 size: 0x2000000 - 0x40000 - 0x80000, /* Warning, this is fixed later */ 115 offset: 0x00080000, 116#endif 117 }, 118 { 119 name: "asset", 120 size: 0x40000, 121 offset: 0x2000000 - 0x40000, /* Warning, this is fixed later */ 122 mask_flags: MTD_WRITEABLE, /* force read-only */ 123 } 124}; 125 126#ifndef CONFIG_MTD_CONCAT 127static struct mtd_partition h3xxx_partitions_bank2[] = { 128 /* this is used only on 2 CS machines when concat is not present */ 129 { 130 name: "second H3XXX root jffs2", 131 size: 0x1000000 - 0x40000, /* Warning, this is fixed later */ 132 offset: 0x00000000, 133 }, 134 { 135 name: "second asset", 136 size: 0x40000, 137 offset: 0x1000000 - 0x40000, /* Warning, this is fixed later */ 138 mask_flags: MTD_WRITEABLE, /* force read-only */ 139 } 140}; 141#endif 142 143static DEFINE_SPINLOCK(ipaq_vpp_lock); 144 145static void h3xxx_set_vpp(struct map_info *map, int vpp) 146{ 147 static int nest = 0; 148 149 spin_lock(&ipaq_vpp_lock); 150 if (vpp) 151 nest++; 152 else 153 nest--; 154 if (nest) 155 assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, 1); 156 else 157 assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, 0); 158 spin_unlock(&ipaq_vpp_lock); 159} 160 161#endif 162 163#if defined(CONFIG_SA1100_JORNADA56X) || defined(CONFIG_SA1100_JORNADA720) 164static unsigned long jornada_max_flash_size = 0x02000000; 165static struct mtd_partition jornada_partitions[] = { 166 { 167 name: "Jornada boot firmware", 168 size: 0x00040000, 169 offset: 0, 170 mask_flags: MTD_WRITEABLE, /* force read-only */ 171 }, { 172 name: "Jornada root jffs2", 173 size: MTDPART_SIZ_FULL, 174 offset: 0x00040000, 175 } 176}; 177#endif 178 179 180static struct mtd_partition *parsed_parts; 181static struct mtd_info *mymtd; 182 183static unsigned long cs_phys[] = { 184#ifdef CONFIG_ARCH_SA1100 185 SA1100_CS0_PHYS, 186 SA1100_CS1_PHYS, 187 SA1100_CS2_PHYS, 188 SA1100_CS3_PHYS, 189 SA1100_CS4_PHYS, 190 SA1100_CS5_PHYS, 191#else 192 PXA_CS0_PHYS, 193 PXA_CS1_PHYS, 194 PXA_CS2_PHYS, 195 PXA_CS3_PHYS, 196 PXA_CS4_PHYS, 197 PXA_CS5_PHYS, 198#endif 199}; 200 201static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; 202 203static int __init h1900_special_case(void); 204 205static int __init ipaq_mtd_init(void) 206{ 207 struct mtd_partition *parts = NULL; 208 int nb_parts = 0; 209 int parsed_nr_parts = 0; 210 const char *part_type; 211 int i; /* used when we have >1 flash chips */ 212 unsigned long tot_flashsize = 0; /* used when we have >1 flash chips */ 213 214 /* Default flash bankwidth */ 215 // ipaq_map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4; 216 217 if (machine_is_h1900()) 218 { 219 /* For our intents, the h1900 is not a real iPAQ, so we special-case it. */ 220 return h1900_special_case(); 221 } 222 223 if (machine_is_h3100() || machine_is_h1900()) 224 for(i=0; i<MAX_IPAQ_CS; i++) 225 ipaq_map[i].bankwidth = 2; 226 else 227 for(i=0; i<MAX_IPAQ_CS; i++) 228 ipaq_map[i].bankwidth = 4; 229 230 /* 231 * Static partition definition selection 232 */ 233 part_type = "static"; 234 235 simple_map_init(&ipaq_map[0]); 236 simple_map_init(&ipaq_map[1]); 237 238#ifdef CONFIG_IPAQ_HANDHELD 239 if (machine_is_ipaq()) { 240 parts = h3xxx_partitions; 241 nb_parts = ARRAY_SIZE(h3xxx_partitions); 242 for(i=0; i<MAX_IPAQ_CS; i++) { 243 ipaq_map[i].size = h3xxx_max_flash_size; 244 ipaq_map[i].set_vpp = h3xxx_set_vpp; 245 ipaq_map[i].phys = cs_phys[i]; 246 ipaq_map[i].virt = ioremap(cs_phys[i], 0x04000000); 247 if (machine_is_h3100 () || machine_is_h1900()) 248 ipaq_map[i].bankwidth = 2; 249 } 250 if (machine_is_h3600()) { 251 /* No asset partition here */ 252 h3xxx_partitions[1].size += 0x40000; 253 nb_parts--; 254 } 255 } 256#endif 257#ifdef CONFIG_ARCH_H5400 258 if (machine_is_h5400()) { 259 ipaq_map[0].size = 0x02000000; 260 ipaq_map[1].size = 0x02000000; 261 ipaq_map[1].phys = 0x02000000; 262 ipaq_map[1].virt = ipaq_map[0].virt + 0x02000000; 263 } 264#endif 265#ifdef CONFIG_ARCH_H1900 266 if (machine_is_h1900()) { 267 ipaq_map[0].size = 0x00400000; 268 ipaq_map[1].size = 0x02000000; 269 ipaq_map[1].phys = 0x00080000; 270 ipaq_map[1].virt = ipaq_map[0].virt + 0x00080000; 271 } 272#endif 273 274#ifdef CONFIG_SA1100_JORNADA56X 275 if (machine_is_jornada56x()) { 276 parts = jornada_partitions; 277 nb_parts = ARRAY_SIZE(jornada_partitions); 278 ipaq_map[0].size = jornada_max_flash_size; 279 ipaq_map[0].set_vpp = jornada56x_set_vpp; 280 ipaq_map[0].virt = (__u32)ioremap(0x0, 0x04000000); 281 } 282#endif 283#ifdef CONFIG_SA1100_JORNADA720 284 if (machine_is_jornada720()) { 285 parts = jornada_partitions; 286 nb_parts = ARRAY_SIZE(jornada_partitions); 287 ipaq_map[0].size = jornada_max_flash_size; 288 ipaq_map[0].set_vpp = jornada720_set_vpp; 289 } 290#endif 291 292 293 if (machine_is_ipaq()) { /* for iPAQs only */ 294 for(i=0; i<MAX_IPAQ_CS; i++) { 295 printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with CFI.\n", ipaq_map[i].bankwidth*8, ipaq_map[i].virt); 296 my_sub_mtd[i] = do_map_probe("cfi_probe", &ipaq_map[i]); 297 if (!my_sub_mtd[i]) { 298 printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[i].bankwidth*8, ipaq_map[i].virt); 299 my_sub_mtd[i] = do_map_probe("jedec_probe", &ipaq_map[i]); 300 } 301 if (!my_sub_mtd[i]) { 302 printk(KERN_NOTICE "iPAQ flash: failed to find flash.\n"); 303 if (i) 304 break; 305 else 306 return -ENXIO; 307 } else 308 printk(KERN_NOTICE "iPAQ flash: found %d bytes\n", my_sub_mtd[i]->size); 309 310 /* do we really need this debugging? --joshua 20030703 */ 311 // printk("my_sub_mtd[%d]=%p\n", i, my_sub_mtd[i]); 312 my_sub_mtd[i]->owner = THIS_MODULE; 313 tot_flashsize += my_sub_mtd[i]->size; 314 } 315#ifdef CONFIG_MTD_CONCAT 316 /* fix the asset location */ 317# ifdef CONFIG_LAB 318 h3xxx_partitions[1].size = tot_flashsize - 0x40000 - 0x80000 /* extra big boot block */; 319# else 320 h3xxx_partitions[1].size = tot_flashsize - 2 * 0x40000; 321# endif 322 h3xxx_partitions[2].offset = tot_flashsize - 0x40000; 323 /* and concat the devices */ 324 mymtd = mtd_concat_create(&my_sub_mtd[0], i, 325 "ipaq"); 326 if (!mymtd) { 327 printk("Cannot create iPAQ concat device\n"); 328 return -ENXIO; 329 } 330#else 331 mymtd = my_sub_mtd[0]; 332 333 /* 334 *In the very near future, command line partition parsing 335 * will use the device name as 'mtd-id' instead of a value 336 * passed to the parse_cmdline_partitions() routine. Since 337 * the bootldr says 'ipaq', make sure it continues to work. 338 */ 339 mymtd->name = "ipaq"; 340 341 if ((machine_is_h3600())) { 342# ifdef CONFIG_LAB 343 h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x80000; 344# else 345 h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x40000; 346# endif 347 nb_parts = 2; 348 } else { 349# ifdef CONFIG_LAB 350 h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x40000 - 0x80000; /* extra big boot block */ 351# else 352 h3xxx_partitions[1].size = my_sub_mtd[0]->size - 2*0x40000; 353# endif 354 h3xxx_partitions[2].offset = my_sub_mtd[0]->size - 0x40000; 355 } 356 357 if (my_sub_mtd[1]) { 358# ifdef CONFIG_LAB 359 h3xxx_partitions_bank2[0].size = my_sub_mtd[1]->size - 0x80000; 360# else 361 h3xxx_partitions_bank2[0].size = my_sub_mtd[1]->size - 0x40000; 362# endif 363 h3xxx_partitions_bank2[1].offset = my_sub_mtd[1]->size - 0x40000; 364 } 365#endif 366 } 367 else { 368 /* 369 * Now let's probe for the actual flash. Do it here since 370 * specific machine settings might have been set above. 371 */ 372 printk(KERN_NOTICE "IPAQ flash: probing %d-bit flash bus, window=%lx\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt); 373 mymtd = do_map_probe("cfi_probe", &ipaq_map[0]); 374 if (!mymtd) 375 return -ENXIO; 376 mymtd->owner = THIS_MODULE; 377 } 378 379 380 /* 381 * Dynamic partition selection stuff (might override the static ones) 382 */ 383 384 i = parse_mtd_partitions(mymtd, part_probes, &parsed_parts, 0); 385 386 if (i > 0) { 387 nb_parts = parsed_nr_parts = i; 388 parts = parsed_parts; 389 part_type = "dynamic"; 390 } 391 392 if (!parts) { 393 printk(KERN_NOTICE "IPAQ flash: no partition info available, registering whole flash at once\n"); 394 add_mtd_device(mymtd); 395#ifndef CONFIG_MTD_CONCAT 396 if (my_sub_mtd[1]) 397 add_mtd_device(my_sub_mtd[1]); 398#endif 399 } else { 400 printk(KERN_NOTICE "Using %s partition definition\n", part_type); 401 add_mtd_partitions(mymtd, parts, nb_parts); 402#ifndef CONFIG_MTD_CONCAT 403 if (my_sub_mtd[1]) 404 add_mtd_partitions(my_sub_mtd[1], h3xxx_partitions_bank2, ARRAY_SIZE(h3xxx_partitions_bank2)); 405#endif 406 } 407 408 return 0; 409} 410 411static void __exit ipaq_mtd_cleanup(void) 412{ 413 int i; 414 415 if (mymtd) { 416 del_mtd_partitions(mymtd); 417#ifndef CONFIG_MTD_CONCAT 418 if (my_sub_mtd[1]) 419 del_mtd_partitions(my_sub_mtd[1]); 420#endif 421 map_destroy(mymtd); 422#ifdef CONFIG_MTD_CONCAT 423 for(i=0; i<MAX_IPAQ_CS; i++) 424#else 425 for(i=1; i<MAX_IPAQ_CS; i++) 426#endif 427 { 428 if (my_sub_mtd[i]) 429 map_destroy(my_sub_mtd[i]); 430 } 431 kfree(parsed_parts); 432 } 433} 434 435static int __init h1900_special_case(void) 436{ 437 /* The iPAQ h1900 is a special case - it has weird ROM. */ 438 simple_map_init(&ipaq_map[0]); 439 ipaq_map[0].size = 0x80000; 440 ipaq_map[0].set_vpp = h3xxx_set_vpp; 441 ipaq_map[0].phys = 0x0; 442 ipaq_map[0].virt = ioremap(0x0, 0x04000000); 443 ipaq_map[0].bankwidth = 2; 444 445 printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt); 446 mymtd = do_map_probe("jedec_probe", &ipaq_map[0]); 447 if (!mymtd) 448 return -ENODEV; 449 add_mtd_device(mymtd); 450 printk(KERN_NOTICE "iPAQ flash: registered h1910 flash\n"); 451 452 return 0; 453} 454 455module_init(ipaq_mtd_init); 456module_exit(ipaq_mtd_cleanup); 457 458MODULE_AUTHOR("Jamey Hicks"); 459MODULE_DESCRIPTION("IPAQ CFI map driver"); 460MODULE_LICENSE("MIT");