diff options
Diffstat (limited to 'target/linux/ar7/files')
| -rw-r--r-- | target/linux/ar7/files/drivers/mtd/ac49xpart.c | 220 | 
1 files changed, 220 insertions, 0 deletions
| diff --git a/target/linux/ar7/files/drivers/mtd/ac49xpart.c b/target/linux/ar7/files/drivers/mtd/ac49xpart.c new file mode 100644 index 000000000..1f937f0f7 --- /dev/null +++ b/target/linux/ar7/files/drivers/mtd/ac49xpart.c @@ -0,0 +1,220 @@ +/* + * AudioCodes AC49x PSPBoot-based flash partition table + * Copyright 2012 Daniel Golle <daniel.golle@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + * + */ + +#include <linux/kernel.h> +#include <linux/slab.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/bootmem.h> +#include <linux/magic.h> +#include <linux/module.h> + +#include <asm/mach-ar7/prom.h> + +#define AC49X_MAXENVPARTS	8 + +#define AC49X_PARTTYPE_LOADER	0 +#define AC49X_PARTTYPE_BOOTENV	1 +#define AC49X_PARTTYPE_LINUX	2 +#define AC49X_PARTTYPE_ROOTFS	3 +#define AC49X_PARTTYPE_UNKNOWN	4 +#define AC49X_NUM_PARTTYPES	5 + +#define AC49X_FLASH_ADDRMASK	0x00FFFFFF + +#define AC49X_LOADER_MAGIC	0x40809000 +#define AC49X_LINUX_MAGIC	0x464c457f /*  ELF */ +#define AC49X_BOOTENV_MAGIC	0x4578614d /* MaxE */ + +#define ROOTFS_MIN_OFFSET	0xC0000 + +int parse_partvar(const unsigned char *partvar, struct mtd_partition *part) +{ +	unsigned int partstart, partend; +	unsigned int pnum; + +	pnum = sscanf(partvar, "0x%x,0x%x", &partstart, &partend); +	if (pnum != 2) +		return 1; + +	part->offset = partstart & AC49X_FLASH_ADDRMASK; +	part->size = partend - partstart; + +	return 0; +} + +int detect_parttype(struct mtd_info *master, struct mtd_partition part) +{ +	unsigned int magic; +	size_t len; + +	if (part.size < 4) +		return -1; + +	mtd_read(master, part.offset, sizeof(magic), &len, +		 (uint8_t *)&magic); + +	if (len != sizeof(magic)) +		return -1; + +	switch (magic) { +	case AC49X_LOADER_MAGIC: +		return AC49X_PARTTYPE_LOADER; +	case AC49X_LINUX_MAGIC: +		return AC49X_PARTTYPE_LINUX; +	case SQUASHFS_MAGIC: +	case CRAMFS_MAGIC: +	case CRAMFS_MAGIC_WEND: +		return AC49X_PARTTYPE_ROOTFS; +	case AC49X_BOOTENV_MAGIC: +		return AC49X_PARTTYPE_BOOTENV; +	default: +		switch (magic & 0xFF) { +		case JFFS2_SUPER_MAGIC: +			return AC49X_PARTTYPE_ROOTFS; +		} +		switch (magic >> 8) { +		case JFFS2_SUPER_MAGIC: +			return AC49X_PARTTYPE_ROOTFS; +		} +		return AC49X_PARTTYPE_UNKNOWN; +	} +} + +const char *partnames[] = { +	"loader", +	"config", +	"linux", +	"rootfs", +	"data" +}; + +void gen_partname(unsigned int type, +		  unsigned int *typenumeration, +		  struct mtd_partition *part) +{ +	char *s  = kzalloc(sizeof(char) * 8, GFP_KERNEL); + +	(typenumeration[type])++; +	if (typenumeration[type] == 1) +		sprintf(s, "%s", partnames[type]); +	else +		sprintf(s, "%s%d", partnames[type], typenumeration[type]); + +	part->name = s; +} + +static int create_mtd_partitions(struct mtd_info *master, +				 struct mtd_partition **pparts, +				 struct mtd_part_parser_data *data) +{ +	unsigned int envpartnum = 0, linuxpartnum = 0; +	unsigned int typenumeration[5] = { 0, 0, 0, 0, 0 }; +	unsigned char evn[5]; +	const unsigned char *partvar = NULL; + +	struct mtd_partition *ac49x_parts; + +	ac49x_parts = kzalloc(sizeof(*ac49x_parts) * AC49X_MAXENVPARTS, +				GFP_KERNEL); + +	if (!ac49x_parts) +		return -ENOMEM; + +	linuxpartnum = 0; +	for (envpartnum = 0; envpartnum < AC49X_MAXENVPARTS; envpartnum++) { +		struct mtd_partition parsepart; +		unsigned int offset, size, type; +		int err; +		sprintf(evn, "mtd%d", envpartnum); +		partvar = prom_getenv(evn); +		if (!partvar) +			continue; +		err = parse_partvar(partvar, &parsepart); +		if (err) +			continue; +		offset = parsepart.offset; +		size = parsepart.size; +		type = detect_parttype(master, parsepart); +		gen_partname(type, typenumeration, &parsepart); +		/* protect loader */ +		if (type == AC49X_PARTTYPE_LOADER) +			parsepart.mask_flags = MTD_WRITEABLE; +		else +			parsepart.mask_flags = 0; + +		memcpy(&(ac49x_parts[linuxpartnum]), &parsepart, +			sizeof(struct mtd_partition)); + +		/* scan for contained rootfs */ +		if (type == AC49X_PARTTYPE_LINUX) { +			parsepart.offset += ROOTFS_MIN_OFFSET & +						~(master->erasesize - 1); +			parsepart.size -= ROOTFS_MIN_OFFSET & +						~(master->erasesize - 1); +			do { +				unsigned int size, offset; +				size = parsepart.size; +				offset = parsepart.offset; + +				type = detect_parttype(master, parsepart); +				if (type == AC49X_PARTTYPE_ROOTFS) { +					gen_partname(type, typenumeration, +							&parsepart); +					printk(KERN_INFO +						"%s %s: 0x%08x@0x%08x\n", +						"detected sub-partition", +						parsepart.name, +						(unsigned int)parsepart.size, +						(unsigned int)parsepart.offset); +					linuxpartnum++; +					memcpy(&(ac49x_parts[linuxpartnum]), +						&parsepart, +						sizeof(struct mtd_partition)); +					break; +				} +				parsepart.offset += master->erasesize; +				parsepart.size -= master->erasesize; +			} while (parsepart.size >= master->erasesize); +		} +		linuxpartnum++; +	} + +	*pparts = ac49x_parts; +	return linuxpartnum; +} + +static struct mtd_part_parser ac49x_parser = { +	.owner = THIS_MODULE, +	.parse_fn = create_mtd_partitions, +	.name = "ac49xpart", +}; + +static int __init ac49x_parser_init(void) +{ +	return register_mtd_parser(&ac49x_parser); +} + +module_init(ac49x_parser_init); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Daniel Golle <daniel.golle@gmail.com>"); +MODULE_DESCRIPTION("MTD partitioning for AudioCodes AC49x"); | 
