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