diff options
-rw-r--r-- | target/linux/adm5120-2.6/config/default | 25 | ||||
-rw-r--r-- | target/linux/adm5120-2.6/files/drivers/mtd/maps/adm5120_mtd.c | 197 |
2 files changed, 188 insertions, 34 deletions
diff --git a/target/linux/adm5120-2.6/config/default b/target/linux/adm5120-2.6/config/default index e5894fc..bbf6d8b 100644 --- a/target/linux/adm5120-2.6/config/default +++ b/target/linux/adm5120-2.6/config/default @@ -76,26 +76,10 @@ CONFIG_CRYPTO_HASH=y CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_SHA1=y # CONFIG_DDB5477 is not set -# CONFIG_DEBUG_DRIVER is not set -# CONFIG_DEBUG_INFO is not set -CONFIG_DEBUG_KERNEL=y -# CONFIG_DEBUG_KOBJECT is not set -# CONFIG_DEBUG_LIST is not set -CONFIG_DEBUG_LOCKING_API_SELFTESTS=y -# CONFIG_DEBUG_LOCK_ALLOC is not set -# CONFIG_DEBUG_MUTEXES is not set -# CONFIG_DEBUG_RT_MUTEXES is not set -# CONFIG_DEBUG_RWSEMS is not set -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_SPINLOCK_SLEEP is not set -# CONFIG_DEBUG_STACK_USAGE is not set -# CONFIG_DEBUG_VM is not set CONFIG_DEFAULT_CFQ=y # CONFIG_DEFAULT_DEADLINE is not set CONFIG_DEFAULT_IOSCHED="cfq" CONFIG_DEFAULT_TCP_CONG="cubic" -CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_DM9000 is not set CONFIG_DMA_NEED_PCI_MAP_STATE=y CONFIG_DMA_NONCOHERENT=y @@ -103,7 +87,6 @@ CONFIG_ELF_CORE=y # CONFIG_EXT2_FS is not set # CONFIG_EXT3_FS is not set CONFIG_FIRMWARE_EDID=y -CONFIG_FORCED_INLINING=y CONFIG_FS_POSIX_ACL=y CONFIG_FW_LOADER=m CONFIG_GENERIC_ACL=y @@ -166,7 +149,6 @@ CONFIG_JFFS2_FS_SECURITY=y CONFIG_JFFS2_FS_XATTR=y CONFIG_JFFS2_SUMMARY=y # CONFIG_JFS_FS is not set -# CONFIG_KGDB is not set CONFIG_LEDS_CLASS=m CONFIG_LEDS_TRIGGER_HEARTBEAT=m CONFIG_LEDS_TRIGGER_TIMER=m @@ -206,7 +188,6 @@ CONFIG_MIPS_MT_DISABLED=y # CONFIG_MIPS_PB1550 is not set # CONFIG_MIPS_SEAD is not set # CONFIG_MIPS_SIM is not set -# CONFIG_MIPS_UNCACHED is not set # CONFIG_MIPS_VPE_LOADER is not set # CONFIG_MIPS_XXS1500 is not set CONFIG_MODULE_FORCE_UNLOAD=y @@ -320,7 +301,6 @@ CONFIG_PAGE_SIZE_4KB=y # CONFIG_PARTITION_ADVANCED is not set # CONFIG_PCCARD is not set CONFIG_PCI_ADM5120=y -# CONFIG_PCI_DEBUG is not set # CONFIG_PMC_YOSEMITE is not set # CONFIG_PNX8550_JBS is not set # CONFIG_PNX8550_V2PCI is not set @@ -333,16 +313,11 @@ CONFIG_PPPOE=y # CONFIG_PPP_MPPE is not set # CONFIG_PPP_MULTILINK is not set # CONFIG_PPP_SYNC_TTY is not set -# CONFIG_PROVE_LOCKING is not set -# CONFIG_RCU_TORTURE_TEST is not set # CONFIG_REISERFS_FS is not set CONFIG_RELAY=y # CONFIG_ROMFS_FS is not set # CONFIG_RTC is not set -# CONFIG_RT_MUTEX_TESTER is not set -# CONFIG_RUNTIME_DEBUG is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_SCHEDSTATS is not set CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y # CONFIG_SCSI is not set # CONFIG_SENSORS_ABITUGURU is not set diff --git a/target/linux/adm5120-2.6/files/drivers/mtd/maps/adm5120_mtd.c b/target/linux/adm5120-2.6/files/drivers/mtd/maps/adm5120_mtd.c index a9e97cb..2bbb238 100644 --- a/target/linux/adm5120-2.6/files/drivers/mtd/maps/adm5120_mtd.c +++ b/target/linux/adm5120-2.6/files/drivers/mtd/maps/adm5120_mtd.c @@ -1,7 +1,8 @@ /* * Flash device on the ADM5120 board * - * Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005 + * Copyright Florian Fainelli <florian@openwrt.org> + * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version @@ -13,43 +14,221 @@ #include <linux/kernel.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/vmalloc.h> + #define FLASH_PHYS_ADDR 0x1FC00000 -#define FLASH_SIZE 0x200000 +#define FLASH_SIZE 0x400000 + +#define IMAGE_LEN 10 /* Length of Length Field */ +#define ADDRESS_LEN 12 /* Length of Address field */ +#define EXTENDED_SIZE 0xBFC00000 /* Extended flash address */ +#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) + static struct mtd_info *adm5120_mtd; +static struct mtd_partition *parsed_parts; static struct map_info adm5120_mtd_map = { - .name = "ADM5120", + .name = "adm5120", .size = FLASH_SIZE, .bankwidth = 2, .phys = FLASH_PHYS_ADDR, }; +static int parse_cfe_partitions( struct mtd_info *master, struct mtd_partition **pparts) +{ + int nrparts = 2, curpart = 0; // CFE and NVRAM always present. + struct adm5120_cfe_map { + unsigned char tagVersion[4]; // Version of the image tag + unsigned char sig_1[20]; // Company Line 1 + unsigned char sig_2[14]; // Company Line 2 + unsigned char chipid[6]; // Chip this image is for + unsigned char boardid[16]; // Board name + unsigned char bigEndian[2]; // Map endianness -- 1 BE 0 LE + unsigned char totalLength[IMAGE_LEN]; //Total length of image + unsigned char cfeAddress[ADDRESS_LEN]; // Address in memory of CFE + unsigned char cfeLength[IMAGE_LEN]; // Size of CFE + unsigned char rootAddress[ADDRESS_LEN]; // Address in memory of rootfs + unsigned char rootLength[IMAGE_LEN]; // Size of rootfs + unsigned char kernelAddress[ADDRESS_LEN]; // Address in memory of kernel + unsigned char kernelLength[IMAGE_LEN]; // Size of kernel + unsigned char dualImage[2]; // Unused at present + unsigned char inactiveFlag[2]; // Unused at present + unsigned char reserved1[74]; // Reserved area not in use + unsigned char imageCRC[4]; // CRC32 of images + unsigned char reserved2[16]; // Unused at present + unsigned char headerCRC[4]; // CRC32 of header excluding tagVersion + unsigned char reserved3[16]; // Unused at present + } *buf; + struct mtd_partition *parts; + int ret; + size_t retlen; + unsigned int rootfsaddr, kerneladdr, spareaddr; + unsigned int rootfslen, kernellen, sparelen, totallen; + int namelen = 0; + int i; + // Allocate memory for buffer + buf = vmalloc(sizeof(struct adm5120_cfe_map)); + + if (!buf) + return -ENOMEM; + + // Get the tag + ret = master->read(master,master->erasesize,sizeof(struct adm5120_cfe_map), &retlen, (void *)buf); + + if (retlen != sizeof(struct adm5120_cfe_map)){ + vfree(buf); + return -EIO; + }; + + printk("adm5120: CFE boot tag found with version %s and board type %s.\n",buf->tagVersion,buf->boardid); + // Get the values and calculate + sscanf(buf->rootAddress,"%u", &rootfsaddr); + rootfsaddr = rootfsaddr - EXTENDED_SIZE; + sscanf(buf->rootLength, "%u", &rootfslen); + sscanf(buf->kernelAddress, "%u", &kerneladdr); + kerneladdr = kerneladdr - EXTENDED_SIZE; + sscanf(buf->kernelLength, "%u", &kernellen); + sscanf(buf->totalLength, "%u", &totallen); + spareaddr = ROUNDUP(totallen,master->erasesize) + master->erasesize; + sparelen = master->size - spareaddr - master->erasesize; + // Determine number of partitions + namelen = 8; + if (rootfslen > 0){ + nrparts++; + namelen =+ 6; + }; + + if (kernellen > 0){ + nrparts++; + namelen =+ 6; + }; + if (sparelen > 0){ + nrparts++; + namelen =+ 6; + }; + // Ask kernel for more memory. + parts = kmalloc(sizeof(*parts)*nrparts+10*nrparts, GFP_KERNEL); + if (!parts){ + vfree(buf); + return -ENOMEM; + }; + memset(parts,0,sizeof(*parts)*nrparts+10*nrparts); + // Start building partition list + parts[curpart].name = "CFE"; + parts[curpart].offset = 0; + parts[curpart].size = master->erasesize; + curpart++; + if (kernellen > 0) { + parts[curpart].name = "Kernel"; + parts[curpart].offset = kerneladdr; + parts[curpart].size = kernellen; + curpart++; + }; + if (rootfslen > 0) { + parts[curpart].name = "Rootfs"; + parts[curpart].offset = rootfsaddr; + parts[curpart].size = rootfslen; + curpart++; + }; + if (sparelen > 0){ + parts[curpart].name = "OpenWrt"; + parts[curpart].offset = spareaddr; + parts[curpart].size = sparelen; + curpart++; + }; + parts[curpart].name = "NVRAM"; + parts[curpart].offset = master->size - master->erasesize; + parts[curpart].size = master->erasesize; + for (i = 0; i < nrparts; i++) { + printk("adm5120: Partition %d is %s offset %x and length %x\n", i, parts[i].name, parts[i].offset, parts[i].size); + } + *pparts = parts; + vfree(buf); + return nrparts; +}; + +static int adm5120_detect_cfe(struct mtd_info *master) +{ + int idoffset = 0x4e0; +#ifdef CONFIG_CPU_BIG_ENDIAN + static char idstring[8] = "CFE1CFE1"; +#else + static char idstring[8] = "1EFC1EFC"; +#endif + char buf[8]; + int ret; + size_t retlen; + + ret = master->read(master, idoffset, 8, &retlen, (void *)buf); + printk("adm5120: Read Signature value of %s\n", buf); + return strcmp(idstring,buf); +} + static int __init adm5120_mtd_init(void) { - printk(KERN_INFO "ADM5120 board flash (0x%x at 0x%x)\n", FLASH_SIZE, + printk(KERN_INFO "ADM5120 board flash (0x%08x at 0x%08x)\n", FLASH_SIZE, FLASH_PHYS_ADDR); - adm5120_mtd_map.virt = ioremap_nocache(FLASH_PHYS_ADDR, FLASH_SIZE); + + adm5120_mtd_map.virt = ioremap(FLASH_PHYS_ADDR, FLASH_SIZE); + + if (!adm5120_mtd_map.virt) { + printk("ADM5120: failed to ioremap\n"); + return -EIO; + } + simple_map_init(&adm5120_mtd_map); + adm5120_mtd = do_map_probe("cfi_probe", &adm5120_mtd_map); + if (adm5120_mtd) { adm5120_mtd->owner = THIS_MODULE; - add_mtd_device(adm5120_mtd); + + if (adm5120_detect_cfe(adm5120_mtd) == 0) + { + int parsed_nr_parts = 0; + char * part_type; + + printk("adm5120: CFE bootloader detected\n"); + + if (parsed_nr_parts == 0) { + int ret = parse_cfe_partitions(adm5120_mtd, &parsed_parts); + + if (ret > 0) { + part_type = "CFE"; + parsed_nr_parts = ret; + } + } + add_mtd_partitions(adm5120_mtd, parsed_parts, parsed_nr_parts); + return 0; + } else { + add_mtd_device(adm5120_mtd); + } return 0; } + iounmap(adm5120_mtd); return -ENXIO; } static void __exit adm5120_mtd_exit(void) { - del_mtd_device(adm5120_mtd); - map_destroy(adm5120_mtd); + if (adm5120_mtd) { + del_mtd_device(adm5120_mtd); + map_destroy(adm5120_mtd); + } + + if (adm5120_mtd_map.virt) { + iounmap(adm5120_mtd_map.virt); + adm5120_mtd_map.virt = 0; + } + } module_init(adm5120_mtd_init); module_exit(adm5120_mtd_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jeroen Vreeken (pe1rxq@amsat.org)"); +MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); MODULE_DESCRIPTION("MTD map driver for ADM5120 boards"); |