--- a/drivers/mtd/maps/lantiq.c +++ b/drivers/mtd/maps/lantiq.c @@ -24,6 +24,10 @@ #include #include +#ifdef CONFIG_SOC_LANTIQ_XWAY +#include +#endif + static map_word lq_read16(struct map_info *map, unsigned long adr) { @@ -77,6 +81,75 @@ lq_copy_to(struct map_info *map, unsigne spin_unlock_irqrestore(&ebu_lock, flags); } +static unsigned long +find_uImage_size(struct map_info *map, unsigned long offset) +{ +#define UBOOT_MAGIC 0x56190527 + unsigned long magic; + unsigned long temp; + map->copy_from(map, &magic, offset, 4); + if (le32_to_cpu(magic) != UBOOT_MAGIC) + return 0; + map->copy_from(map, &temp, offset + 12, 4); + return temp + 0x40; +} + +static int +detect_squashfs_partition(struct map_info *map, unsigned long offset) +{ + unsigned long temp; + map->copy_from(map, &temp, offset, 4); + return le32_to_cpu(temp) == SQUASHFS_MAGIC; +} + +static struct mtd_partition split_partitions[] = { + { + .name = "kernel", + .offset = 0x0, + .size = 0x0, + }, { + .name = "rootfs", + .offset = 0x0, + .size = 0x0, + }, +}; + +static int +mtd_split_linux(struct map_info *map, struct mtd_info *mtd, + struct mtd_partition *parts, int nr_parts) +{ + int base_part = 0; + int i; + for (i = 0; i < nr_parts && !base_part; i++) { + if(!strcmp("linux", parts[i].name)) + base_part = i; + } + if (!base_part) + return 0; + split_partitions[0].size = find_uImage_size(map, parts[base_part].offset); + if (!split_partitions[0].size) { + printk(KERN_INFO "lq_nor: no uImage found in linux partition"); + return -1; + } + if (!detect_squashfs_partition(map, + parts[base_part].offset + split_partitions[0].size)) { + split_partitions[0].size &= ~(mtd->erasesize - 1); + split_partitions[0].size += mtd->erasesize; + } + split_partitions[0].offset = parts[base_part].offset; + split_partitions[1].offset = + parts[base_part].offset + split_partitions[0].size; + split_partitions[1].size = + parts[base_part].size - split_partitions[0].size; + + base_part++; + add_mtd_partitions(mtd, parts, base_part); + add_mtd_partitions(mtd, split_partitions, 2); + if(nr_parts != base_part) + add_mtd_partitions(mtd, &parts[base_part], nr_parts - base_part); + return nr_parts + 2; +} + static const char *part_probe_types[] = { "cmdlinepart", NULL }; static struct map_info lq_map = { @@ -142,7 +215,8 @@ lq_mtd_probe(struct platform_device *pde parts = lq_mtd_data->parts; } - add_mtd_partitions(lq_mtd, parts, nr_parts); + if (!mtd_split_linux(&lq_map, lq_mtd, parts, nr_parts)) + add_mtd_partitions(lq_mtd, parts, nr_parts); return 0; }