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