⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipaq-flash.c

📁 linux-2.6.15.6
💻 C
字号:
/* * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based) * * (C) 2000 Nicolas Pitre <nico@cam.org> * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com> * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes * * $Id: ipaq-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $ */#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/spinlock.h>#include <linux/init.h>#include <linux/slab.h>#include <asm/page.h>#include <asm/mach-types.h>#include <asm/system.h>#include <asm/errno.h>#include <linux/mtd/mtd.h>#include <linux/mtd/map.h>#include <linux/mtd/partitions.h>#ifdef CONFIG_MTD_CONCAT#include <linux/mtd/concat.h>#endif#include <asm/hardware.h>#include <asm/arch-sa1100/h3600.h>#include <asm/io.h>#ifndef CONFIG_IPAQ_HANDHELD#error This is for iPAQ Handhelds only#endif#ifdef CONFIG_SA1100_JORNADA56Xstatic void jornada56x_set_vpp(struct map_info *map, int vpp){	if (vpp)		GPSR = GPIO_GPIO26;	else		GPCR = GPIO_GPIO26;	GPDR |= GPIO_GPIO26;}#endif#ifdef CONFIG_SA1100_JORNADA720static void jornada720_set_vpp(struct map_info *map, int vpp){	if (vpp)		PPSR |= 0x80;	else		PPSR &= ~0x80;	PPDR |= 0x80;}#endif#define MAX_IPAQ_CS 2		/* Number of CS we are going to test */#define IPAQ_MAP_INIT(X) \	{ \		name:		"IPAQ flash " X, \	}static struct map_info ipaq_map[MAX_IPAQ_CS] = {	IPAQ_MAP_INIT("bank 1"),	IPAQ_MAP_INIT("bank 2")};static struct mtd_info *my_sub_mtd[MAX_IPAQ_CS] = {	NULL,	NULL};/* * Here are partition information for all known IPAQ-based devices. * See include/linux/mtd/partitions.h for definition of the mtd_partition * structure. * * The *_max_flash_size is the maximum possible mapped flash size which * is not necessarily the actual flash size.  It must be no more than * the value specified in the "struct map_desc *_io_desc" mapping * definition for the corresponding machine. * * Please keep these in alphabetical order, and formatted as per existing * entries.  Thanks. */#ifdef CONFIG_IPAQ_HANDHELDstatic unsigned long h3xxx_max_flash_size = 0x04000000;static struct mtd_partition h3xxx_partitions[] = {	{		name:		"H3XXX boot firmware",#ifndef CONFIG_LAB		size:		0x00040000,#else		size:		0x00080000,#endif		offset:		0,#ifndef CONFIG_LAB		mask_flags:	MTD_WRITEABLE,  /* force read-only */#endif	},	{		name:		"H3XXX root jffs2",#ifndef CONFIG_LAB		size:		0x2000000 - 2*0x40000, /* Warning, this is fixed later */		offset:		0x00040000,#else		size:		0x2000000 - 0x40000 - 0x80000, /* Warning, this is fixed later */		offset:		0x00080000,#endif	},	{		name:		"asset",		size:		0x40000,		offset:		0x2000000 - 0x40000, /* Warning, this is fixed later */		mask_flags:	MTD_WRITEABLE,  /* force read-only */	}};#ifndef CONFIG_MTD_CONCATstatic struct mtd_partition h3xxx_partitions_bank2[] = {	/* this is used only on 2 CS machines when concat is not present */	{		name:		"second H3XXX root jffs2",		size:		0x1000000 - 0x40000, /* Warning, this is fixed later */		offset:		0x00000000,	},	{		name:		"second asset",		size:		0x40000,		offset:		0x1000000 - 0x40000, /* Warning, this is fixed later */		mask_flags:	MTD_WRITEABLE,  /* force read-only */	}};#endifstatic DEFINE_SPINLOCK(ipaq_vpp_lock);static void h3xxx_set_vpp(struct map_info *map, int vpp){	static int nest = 0;	spin_lock(&ipaq_vpp_lock);	if (vpp)		nest++;	else		nest--;	if (nest)		assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, 1);	else		assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, 0);	spin_unlock(&ipaq_vpp_lock);}#endif#if defined(CONFIG_SA1100_JORNADA56X) || defined(CONFIG_SA1100_JORNADA720)static unsigned long jornada_max_flash_size = 0x02000000;static struct mtd_partition jornada_partitions[] = {	{		name:		"Jornada boot firmware",		size:		0x00040000,		offset:		0,		mask_flags:	MTD_WRITEABLE,  /* force read-only */	}, {		name:		"Jornada root jffs2",		size:		MTDPART_SIZ_FULL,		offset:		0x00040000,	}};#endifstatic struct mtd_partition *parsed_parts;static struct mtd_info *mymtd;static unsigned long cs_phys[] = {#ifdef CONFIG_ARCH_SA1100	SA1100_CS0_PHYS,	SA1100_CS1_PHYS,	SA1100_CS2_PHYS,	SA1100_CS3_PHYS,	SA1100_CS4_PHYS,	SA1100_CS5_PHYS,#else	PXA_CS0_PHYS,	PXA_CS1_PHYS,	PXA_CS2_PHYS,	PXA_CS3_PHYS,	PXA_CS4_PHYS,	PXA_CS5_PHYS,#endif};static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };static int __init h1900_special_case(void);int __init ipaq_mtd_init(void){	struct mtd_partition *parts = NULL;	int nb_parts = 0;	int parsed_nr_parts = 0;	const char *part_type;	int i; /* used when we have >1 flash chips */	unsigned long tot_flashsize = 0; /* used when we have >1 flash chips */	/* Default flash bankwidth */	// ipaq_map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;	if (machine_is_h1900())	{		/* For our intents, the h1900 is not a real iPAQ, so we special-case it. */		return h1900_special_case();	}	if (machine_is_h3100() || machine_is_h1900())		for(i=0; i<MAX_IPAQ_CS; i++)			ipaq_map[i].bankwidth = 2;	else		for(i=0; i<MAX_IPAQ_CS; i++)			ipaq_map[i].bankwidth = 4;	/*	 * Static partition definition selection	 */	part_type = "static";	simple_map_init(&ipaq_map[0]);	simple_map_init(&ipaq_map[1]);#ifdef CONFIG_IPAQ_HANDHELD	if (machine_is_ipaq()) {		parts = h3xxx_partitions;		nb_parts = ARRAY_SIZE(h3xxx_partitions);		for(i=0; i<MAX_IPAQ_CS; i++) {			ipaq_map[i].size = h3xxx_max_flash_size;			ipaq_map[i].set_vpp = h3xxx_set_vpp;			ipaq_map[i].phys = cs_phys[i];			ipaq_map[i].virt = ioremap(cs_phys[i], 0x04000000);			if (machine_is_h3100 () || machine_is_h1900())				ipaq_map[i].bankwidth = 2;		}		if (machine_is_h3600()) {			/* No asset partition here */			h3xxx_partitions[1].size += 0x40000;			nb_parts--;		}	}#endif#ifdef CONFIG_ARCH_H5400	if (machine_is_h5400()) {		ipaq_map[0].size = 0x02000000;		ipaq_map[1].size = 0x02000000;		ipaq_map[1].phys = 0x02000000;		ipaq_map[1].virt = ipaq_map[0].virt + 0x02000000;	}#endif#ifdef CONFIG_ARCH_H1900	if (machine_is_h1900()) {		ipaq_map[0].size = 0x00400000;		ipaq_map[1].size = 0x02000000;		ipaq_map[1].phys = 0x00080000;		ipaq_map[1].virt = ipaq_map[0].virt + 0x00080000;	}#endif#ifdef CONFIG_SA1100_JORNADA56X	if (machine_is_jornada56x()) {		parts = jornada_partitions;		nb_parts = ARRAY_SIZE(jornada_partitions);		ipaq_map[0].size = jornada_max_flash_size;		ipaq_map[0].set_vpp = jornada56x_set_vpp;		ipaq_map[0].virt = (__u32)ioremap(0x0, 0x04000000);	}#endif#ifdef CONFIG_SA1100_JORNADA720	if (machine_is_jornada720()) {		parts = jornada_partitions;		nb_parts = ARRAY_SIZE(jornada_partitions);		ipaq_map[0].size = jornada_max_flash_size;		ipaq_map[0].set_vpp = jornada720_set_vpp;	}#endif	if (machine_is_ipaq()) { /* for iPAQs only */		for(i=0; i<MAX_IPAQ_CS; i++) {			printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with CFI.\n", ipaq_map[i].bankwidth*8, ipaq_map[i].virt);			my_sub_mtd[i] = do_map_probe("cfi_probe", &ipaq_map[i]);			if (!my_sub_mtd[i]) {				printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[i].bankwidth*8, ipaq_map[i].virt);				my_sub_mtd[i] = do_map_probe("jedec_probe", &ipaq_map[i]);			}			if (!my_sub_mtd[i]) {				printk(KERN_NOTICE "iPAQ flash: failed to find flash.\n");				if (i)					break;				else					return -ENXIO;			} else				printk(KERN_NOTICE "iPAQ flash: found %d bytes\n", my_sub_mtd[i]->size);			/* do we really need this debugging? --joshua 20030703 */			// printk("my_sub_mtd[%d]=%p\n", i, my_sub_mtd[i]);			my_sub_mtd[i]->owner = THIS_MODULE;			tot_flashsize += my_sub_mtd[i]->size;		}#ifdef CONFIG_MTD_CONCAT		/* fix the asset location */#	ifdef CONFIG_LAB		h3xxx_partitions[1].size = tot_flashsize - 0x40000 - 0x80000 /* extra big boot block */;#	else		h3xxx_partitions[1].size = tot_flashsize - 2 * 0x40000;#	endif		h3xxx_partitions[2].offset = tot_flashsize - 0x40000;		/* and concat the devices */		mymtd = mtd_concat_create(&my_sub_mtd[0], i,					  "ipaq");		if (!mymtd) {			printk("Cannot create iPAQ concat device\n");			return -ENXIO;		}#else		mymtd = my_sub_mtd[0];		/*		 *In the very near future, command line partition parsing		 * will use the device name as 'mtd-id' instead of a value		 * passed to the parse_cmdline_partitions() routine. Since		 * the bootldr says 'ipaq', make sure it continues to work.		 */		mymtd->name = "ipaq";		if ((machine_is_h3600())) {#	ifdef CONFIG_LAB			h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x80000;#	else			h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x40000;#	endif			nb_parts = 2;		} else {#	ifdef CONFIG_LAB			h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x40000 - 0x80000; /* extra big boot block */#	else			h3xxx_partitions[1].size = my_sub_mtd[0]->size - 2*0x40000;#	endif			h3xxx_partitions[2].offset = my_sub_mtd[0]->size - 0x40000;		}		if (my_sub_mtd[1]) {#	ifdef CONFIG_LAB			h3xxx_partitions_bank2[0].size = my_sub_mtd[1]->size - 0x80000;#	else			h3xxx_partitions_bank2[0].size = my_sub_mtd[1]->size - 0x40000;#	endif			h3xxx_partitions_bank2[1].offset = my_sub_mtd[1]->size - 0x40000;		}#endif	}	else {		/*		 * Now let's probe for the actual flash.  Do it here since		 * specific machine settings might have been set above.		 */		printk(KERN_NOTICE "IPAQ flash: probing %d-bit flash bus, window=%lx\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt);		mymtd = do_map_probe("cfi_probe", &ipaq_map[0]);		if (!mymtd)			return -ENXIO;		mymtd->owner = THIS_MODULE;	}	/*	 * Dynamic partition selection stuff (might override the static ones)	 */	 i = parse_mtd_partitions(mymtd, part_probes, &parsed_parts, 0);	 if (i > 0) {		 nb_parts = parsed_nr_parts = i;		 parts = parsed_parts;		 part_type = "dynamic";	 }	 if (!parts) {		 printk(KERN_NOTICE "IPAQ flash: no partition info available, registering whole flash at once\n");		 add_mtd_device(mymtd);#ifndef CONFIG_MTD_CONCAT		 if (my_sub_mtd[1])			 add_mtd_device(my_sub_mtd[1]);#endif	 } else {		 printk(KERN_NOTICE "Using %s partition definition\n", part_type);		 add_mtd_partitions(mymtd, parts, nb_parts);#ifndef CONFIG_MTD_CONCAT		 if (my_sub_mtd[1])			 add_mtd_partitions(my_sub_mtd[1], h3xxx_partitions_bank2, ARRAY_SIZE(h3xxx_partitions_bank2));#endif	 }	 return 0;}static void __exit ipaq_mtd_cleanup(void){	int i;	if (mymtd) {		del_mtd_partitions(mymtd);#ifndef CONFIG_MTD_CONCAT		if (my_sub_mtd[1])			del_mtd_partitions(my_sub_mtd[1]);#endif		map_destroy(mymtd);#ifdef CONFIG_MTD_CONCAT		for(i=0; i<MAX_IPAQ_CS; i++)#else			for(i=1; i<MAX_IPAQ_CS; i++)#endif			{				if (my_sub_mtd[i])					map_destroy(my_sub_mtd[i]);			}		kfree(parsed_parts);	}}static int __init h1900_special_case(void){	/* The iPAQ h1900 is a special case - it has weird ROM. */	simple_map_init(&ipaq_map[0]);	ipaq_map[0].size = 0x80000;	ipaq_map[0].set_vpp = h3xxx_set_vpp;	ipaq_map[0].phys = 0x0;	ipaq_map[0].virt = ioremap(0x0, 0x04000000);	ipaq_map[0].bankwidth = 2;	printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt);	mymtd = do_map_probe("jedec_probe", &ipaq_map[0]);	if (!mymtd)		return -ENODEV;	add_mtd_device(mymtd);	printk(KERN_NOTICE "iPAQ flash: registered h1910 flash\n");	return 0;}module_init(ipaq_mtd_init);module_exit(ipaq_mtd_cleanup);MODULE_AUTHOR("Jamey Hicks");MODULE_DESCRIPTION("IPAQ CFI map driver");MODULE_LICENSE("MIT");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -