diff -urN bcm963xx-flash.c.orig bcm963xx-flash.c --- bcm963xx-flash.c.orig 2006-11-03 21:10:12.000000000 +0000 +++ bcm963xx-flash.c 2006-11-06 17:44:50.000000000 +0000 @@ -31,15 +31,20 @@ #include #include +#include #include #include #include +#include #include #define WINDOW_ADDR 0x1FC00000 /* Real address of the flash */ #define WINDOW_SIZE 0x400000 /* Size of flash */ #define BUSWIDTH 2 /* Buswidth */ -#define EXTENDED_SIZE 0xBFC00000 /* Extended flash addresse */ +#define EXTENDED_SIZE 0xBFC00000 /* Extended flash address */ +#define IMAGE_LEN 10 /* Length of Length Field */ +#define ADDRESS_LEN 12 /* Length of Address field */ +#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) extern int boot_loader_type; /* For RedBoot / CFE detection */ extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts, unsigned long fis_origin); @@ -56,6 +61,117 @@ .phys = WINDOW_ADDR, }; + +int parse_cfe_partitions( struct mtd_info *master, struct mtd_partition **pparts) +{ + int nrparts = 2, curpart = 0; // CFE and NVRAM always present. + struct bcm963xx_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 bcm963xx_cfe_map)); + + if (!buf) + return -ENOMEM; + + // Get the tag + ret = master->read(master,master->erasesize,sizeof(struct bcm963xx_cfe_map), &retlen, (void *)buf); + if (retlen != sizeof(struct bcm963xx_cfe_map)){ + vfree(buf); + return -EIO; + }; + printk("bcm963xx: 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; + }; + // Start building partition list + parts[curpart].name = "CFE"; + parts[curpart].offset = 0; + parts[curpart].size = master->erasesize; + curpart++; + + if (rootfslen > 0){ + parts[curpart].name = "Rootfs"; + parts[curpart].offset = rootfsaddr; + parts[curpart].size = rootfslen -1; + curpart++; + }; + if (kernellen > 0){ + parts[curpart].name = "Kernel"; + parts[curpart].offset = kerneladdr; + parts[curpart].size = kernellen -1; + 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("bcm963xx: 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 struct mtd_partition bcm963xx_parts[] = { { name: "bootloader", size: 0, offset: 0, mask_flags: MTD_WRITEABLE }, { name: "rootfs", size: 0, offset: 0}, @@ -64,6 +180,19 @@ static int bcm963xx_parts_size = sizeof(bcm963xx_parts) / sizeof(bcm963xx_parts[0]); +static int bcm963xx_detect_cfe(struct mtd_info *master) +{ + int idoffset = 0x4e0; + static char idstring[8] = "CFE1CFE1"; + char buf[8]; + int ret; + size_t retlen; + + ret = master->read(master, idoffset, 8, &retlen, (void *)buf); + printk("bcm963xx: Read Signature value of %s\n", buf); + return strcmp(idstring,buf); +} + static int __init bcm963xx_mtd_init(void) { printk("bcm963xx: 0x%08x at 0x%08x\n", WINDOW_SIZE, WINDOW_ADDR); @@ -81,10 +210,22 @@ if (bcm963xx_mtd_info) { bcm963xx_mtd_info->owner = THIS_MODULE; - if (boot_loader_type == BOOT_CFE) + //if (boot_loader_type == BOOT_CFE) + if (bcm963xx_detect_cfe(bcm963xx_mtd_info) == 0) { - add_mtd_device(bcm963xx_mtd_info); - add_mtd_partitions(bcm963xx_mtd_info, bcm963xx_parts, bcm963xx_parts_size); + int parsed_nr_parts = 0; + char * part_type; + printk("bcm963xx: CFE bootloader detected\n"); + //add_mtd_device(bcm963xx_mtd_info); + //add_mtd_partitions(bcm963xx_mtd_info, bcm963xx_parts, bcm963xx_parts_size); + if (parsed_nr_parts == 0) { + int ret = parse_cfe_partitions(bcm963xx_mtd_info, &parsed_parts); + if (ret > 0) { + part_type = "CFE"; + parsed_nr_parts = ret; + } + } + add_mtd_partitions(bcm963xx_mtd_info, parsed_parts, parsed_nr_parts); return 0; } else