Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: add Broadcom BCM63xx image tag partition parser

This patch adds support for parsing Broadcom BCM63xx image tag format and
creating MTD partitions accordingly. This driver is a platform_device which
can be instantiated accordingly by bcm63xx board support code.

Signed-off-by: Daniel Dickinson <cshore@csolve.net>
Signed-off-by: Mike Albon <malbon@openwrt.org>
Signed-off-by: Florian Fainelli <florian@openwrt.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>

authored by

Florian Fainelli and committed by
David Woodhouse
bc49c289 5e59be1f

+378
+97
arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h
··· 1 + #ifndef __BCM963XX_TAG_H 2 + #define __BCM963XX_TAG_H 3 + 4 + #define TAGVER_LEN 4 /* Length of Tag Version */ 5 + #define TAGLAYOUT_LEN 4 /* Length of FlashLayoutVer */ 6 + #define SIG1_LEN 20 /* Company Signature 1 Length */ 7 + #define SIG2_LEN 14 /* Company Signature 2 Lenght */ 8 + #define BOARDID_LEN 16 /* Length of BoardId */ 9 + #define ENDIANFLAG_LEN 2 /* Endian Flag Length */ 10 + #define CHIPID_LEN 6 /* Chip Id Length */ 11 + #define IMAGE_LEN 10 /* Length of Length Field */ 12 + #define ADDRESS_LEN 12 /* Length of Address field */ 13 + #define DUALFLAG_LEN 2 /* Dual Image flag Length */ 14 + #define INACTIVEFLAG_LEN 2 /* Inactie Flag Length */ 15 + #define RSASIG_LEN 20 /* Length of RSA Signature in tag */ 16 + #define TAGINFO1_LEN 30 /* Length of vendor information field1 in tag */ 17 + #define FLASHLAYOUTVER_LEN 4 /* Length of Flash Layout Version String tag */ 18 + #define TAGINFO2_LEN 16 /* Length of vendor information field2 in tag */ 19 + #define CRC_LEN 4 /* Length of CRC in bytes */ 20 + #define ALTTAGINFO_LEN 54 /* Alternate length for vendor information; Pirelli */ 21 + 22 + #define NUM_PIRELLI 2 23 + #define IMAGETAG_CRC_START 0xFFFFFFFF 24 + 25 + #define PIRELLI_BOARDS { \ 26 + "AGPF-S0", \ 27 + "DWV-S0", \ 28 + } 29 + 30 + /* 31 + * The broadcom firmware assumes the rootfs starts the image, 32 + * therefore uses the rootfs start (flash_image_address) 33 + * to determine where to flash the image. Since we have the kernel first 34 + * we have to give it the kernel address, but the crc uses the length 35 + * associated with this address (root_length), which is added to the kernel 36 + * length (kernel_length) to determine the length of image to flash and thus 37 + * needs to be rootfs + deadcode (jffs2 EOF marker) 38 + */ 39 + 40 + struct bcm_tag { 41 + /* 0-3: Version of the image tag */ 42 + char tag_version[TAGVER_LEN]; 43 + /* 4-23: Company Line 1 */ 44 + char sig_1[SIG1_LEN]; 45 + /* 24-37: Company Line 2 */ 46 + char sig_2[SIG2_LEN]; 47 + /* 38-43: Chip this image is for */ 48 + char chip_id[CHIPID_LEN]; 49 + /* 44-59: Board name */ 50 + char board_id[BOARDID_LEN]; 51 + /* 60-61: Map endianness -- 1 BE 0 LE */ 52 + char big_endian[ENDIANFLAG_LEN]; 53 + /* 62-71: Total length of image */ 54 + char total_length[IMAGE_LEN]; 55 + /* 72-83: Address in memory of CFE */ 56 + char cfe__address[ADDRESS_LEN]; 57 + /* 84-93: Size of CFE */ 58 + char cfe_length[IMAGE_LEN]; 59 + /* 94-105: Address in memory of image start 60 + * (kernel for OpenWRT, rootfs for stock firmware) 61 + */ 62 + char flash_image_start[ADDRESS_LEN]; 63 + /* 106-115: Size of rootfs */ 64 + char root_length[IMAGE_LEN]; 65 + /* 116-127: Address in memory of kernel */ 66 + char kernel_address[ADDRESS_LEN]; 67 + /* 128-137: Size of kernel */ 68 + char kernel_length[IMAGE_LEN]; 69 + /* 138-139: Unused at the moment */ 70 + char dual_image[DUALFLAG_LEN]; 71 + /* 140-141: Unused at the moment */ 72 + char inactive_flag[INACTIVEFLAG_LEN]; 73 + /* 142-161: RSA Signature (not used; some vendors may use this) */ 74 + char rsa_signature[RSASIG_LEN]; 75 + /* 162-191: Compilation and related information (not used in OpenWrt) */ 76 + char information1[TAGINFO1_LEN]; 77 + /* 192-195: Version flash layout */ 78 + char flash_layout_ver[FLASHLAYOUTVER_LEN]; 79 + /* 196-199: kernel+rootfs CRC32 */ 80 + char fskernel_crc[CRC_LEN]; 81 + /* 200-215: Unused except on Alice Gate where is is information */ 82 + char information2[TAGINFO2_LEN]; 83 + /* 216-219: CRC32 of image less imagetag (kernel for Alice Gate) */ 84 + char image_crc[CRC_LEN]; 85 + /* 220-223: CRC32 of rootfs partition */ 86 + char rootfs_crc[CRC_LEN]; 87 + /* 224-227: CRC32 of kernel partition */ 88 + char kernel_crc[CRC_LEN]; 89 + /* 228-235: Unused at present */ 90 + char reserved1[8]; 91 + /* 236-239: CRC32 of header excluding tagVersion */ 92 + char header_crc[CRC_LEN]; 93 + /* 240-255: Unused at present */ 94 + char reserved2[16]; 95 + }; 96 + 97 + #endif /* __BCM63XX_TAG_H */
+9
drivers/mtd/maps/Kconfig
··· 251 251 help 252 252 Support for flash chips on NETtel/SecureEdge/SnapGear boards. 253 253 254 + config MTD_BCM963XX 255 + tristate "Map driver for Broadcom BCM963xx boards" 256 + depends on BCM63XX 257 + select MTD_MAP_BANK_WIDTH_2 258 + select MTD_CFI_I1 259 + help 260 + Support for parsing CFE image tag and creating MTD partitions on 261 + Broadcom BCM63xx boards. 262 + 254 263 config MTD_DILNETPC 255 264 tristate "CFI Flash device mapped on DIL/Net PC" 256 265 depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
+1
drivers/mtd/maps/Makefile
··· 58 58 obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o 59 59 obj-$(CONFIG_MTD_VMU) += vmu-flash.o 60 60 obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o 61 + obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o
+271
drivers/mtd/maps/bcm963xx-flash.c
··· 1 + /* 2 + * Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org> 3 + * Mike Albon <malbon@openwrt.org> 4 + * Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19 + */ 20 + 21 + #include <linux/init.h> 22 + #include <linux/kernel.h> 23 + #include <linux/slab.h> 24 + #include <linux/mtd/map.h> 25 + #include <linux/mtd/mtd.h> 26 + #include <linux/mtd/partitions.h> 27 + #include <linux/vmalloc.h> 28 + #include <linux/platform_device.h> 29 + #include <linux/io.h> 30 + 31 + #include <asm/mach-bcm63xx/bcm963xx_tag.h> 32 + 33 + #define BCM63XX_BUSWIDTH 2 /* Buswidth */ 34 + #define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */ 35 + 36 + #define PFX KBUILD_MODNAME ": " 37 + 38 + static struct mtd_partition *parsed_parts; 39 + 40 + static struct mtd_info *bcm963xx_mtd_info; 41 + 42 + static struct map_info bcm963xx_map = { 43 + .name = "bcm963xx", 44 + .bankwidth = BCM63XX_BUSWIDTH, 45 + }; 46 + 47 + static int parse_cfe_partitions(struct mtd_info *master, 48 + struct mtd_partition **pparts) 49 + { 50 + /* CFE, NVRAM and global Linux are always present */ 51 + int nrparts = 3, curpart = 0; 52 + struct bcm_tag *buf; 53 + struct mtd_partition *parts; 54 + int ret; 55 + size_t retlen; 56 + unsigned int rootfsaddr, kerneladdr, spareaddr; 57 + unsigned int rootfslen, kernellen, sparelen, totallen; 58 + int namelen = 0; 59 + int i; 60 + char *boardid; 61 + char *tagversion; 62 + 63 + /* Allocate memory for buffer */ 64 + buf = vmalloc(sizeof(struct bcm_tag)); 65 + if (!buf) 66 + return -ENOMEM; 67 + 68 + /* Get the tag */ 69 + ret = master->read(master, master->erasesize, sizeof(struct bcm_tag), 70 + &retlen, (void *)buf); 71 + if (retlen != sizeof(struct bcm_tag)) { 72 + vfree(buf); 73 + return -EIO; 74 + } 75 + 76 + sscanf(buf->kernel_address, "%u", &kerneladdr); 77 + sscanf(buf->kernel_length, "%u", &kernellen); 78 + sscanf(buf->total_length, "%u", &totallen); 79 + tagversion = &(buf->tag_version[0]); 80 + boardid = &(buf->board_id[0]); 81 + 82 + printk(KERN_INFO PFX "CFE boot tag found with version %s " 83 + "and board type %s\n", tagversion, boardid); 84 + 85 + kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE; 86 + rootfsaddr = kerneladdr + kernellen; 87 + spareaddr = roundup(totallen, master->erasesize) + master->erasesize; 88 + sparelen = master->size - spareaddr - master->erasesize; 89 + rootfslen = spareaddr - rootfsaddr; 90 + 91 + /* Determine number of partitions */ 92 + namelen = 8; 93 + if (rootfslen > 0) { 94 + nrparts++; 95 + namelen += 6; 96 + }; 97 + if (kernellen > 0) { 98 + nrparts++; 99 + namelen += 6; 100 + }; 101 + 102 + /* Ask kernel for more memory */ 103 + parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL); 104 + if (!parts) { 105 + vfree(buf); 106 + return -ENOMEM; 107 + }; 108 + 109 + /* Start building partition list */ 110 + parts[curpart].name = "CFE"; 111 + parts[curpart].offset = 0; 112 + parts[curpart].size = master->erasesize; 113 + curpart++; 114 + 115 + if (kernellen > 0) { 116 + parts[curpart].name = "kernel"; 117 + parts[curpart].offset = kerneladdr; 118 + parts[curpart].size = kernellen; 119 + curpart++; 120 + }; 121 + 122 + if (rootfslen > 0) { 123 + parts[curpart].name = "rootfs"; 124 + parts[curpart].offset = rootfsaddr; 125 + parts[curpart].size = rootfslen; 126 + if (sparelen > 0) 127 + parts[curpart].size += sparelen; 128 + curpart++; 129 + }; 130 + 131 + parts[curpart].name = "nvram"; 132 + parts[curpart].offset = master->size - master->erasesize; 133 + parts[curpart].size = master->erasesize; 134 + 135 + /* Global partition "linux" to make easy firmware upgrade */ 136 + curpart++; 137 + parts[curpart].name = "linux"; 138 + parts[curpart].offset = parts[0].size; 139 + parts[curpart].size = master->size - parts[0].size - parts[3].size; 140 + 141 + for (i = 0; i < nrparts; i++) 142 + printk(KERN_INFO PFX "Partition %d is %s offset %lx and " 143 + "length %lx\n", i, parts[i].name, 144 + (long unsigned int)(parts[i].offset), 145 + (long unsigned int)(parts[i].size)); 146 + 147 + printk(KERN_INFO PFX "Spare partition is %x offset and length %x\n", 148 + spareaddr, sparelen); 149 + *pparts = parts; 150 + vfree(buf); 151 + 152 + return nrparts; 153 + }; 154 + 155 + static int bcm963xx_detect_cfe(struct mtd_info *master) 156 + { 157 + int idoffset = 0x4e0; 158 + static char idstring[8] = "CFE1CFE1"; 159 + char buf[9]; 160 + int ret; 161 + size_t retlen; 162 + 163 + ret = master->read(master, idoffset, 8, &retlen, (void *)buf); 164 + buf[retlen] = 0; 165 + printk(KERN_INFO PFX "Read Signature value of %s\n", buf); 166 + 167 + return strncmp(idstring, buf, 8); 168 + } 169 + 170 + static int bcm963xx_probe(struct platform_device *pdev) 171 + { 172 + int err = 0; 173 + int parsed_nr_parts = 0; 174 + char *part_type; 175 + struct resource *r; 176 + 177 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 178 + if (!r) { 179 + dev_err(&pdev->dev, "no resource supplied\n"); 180 + return -ENODEV; 181 + } 182 + 183 + bcm963xx_map.phys = r->start; 184 + bcm963xx_map.size = resource_size(r); 185 + bcm963xx_map.virt = ioremap(r->start, resource_size(r)); 186 + if (!bcm963xx_map.virt) { 187 + dev_err(&pdev->dev, "failed to ioremap\n"); 188 + return -EIO; 189 + } 190 + 191 + dev_info(&pdev->dev, "0x%08lx at 0x%08x\n", 192 + bcm963xx_map.size, bcm963xx_map.phys); 193 + 194 + simple_map_init(&bcm963xx_map); 195 + 196 + bcm963xx_mtd_info = do_map_probe("cfi_probe", &bcm963xx_map); 197 + if (!bcm963xx_mtd_info) { 198 + dev_err(&pdev->dev, "failed to probe using CFI\n"); 199 + err = -EIO; 200 + goto err_probe; 201 + } 202 + 203 + bcm963xx_mtd_info->owner = THIS_MODULE; 204 + 205 + /* This is mutually exclusive */ 206 + if (bcm963xx_detect_cfe(bcm963xx_mtd_info) == 0) { 207 + dev_info(&pdev->dev, "CFE bootloader detected\n"); 208 + if (parsed_nr_parts == 0) { 209 + int ret = parse_cfe_partitions(bcm963xx_mtd_info, 210 + &parsed_parts); 211 + if (ret > 0) { 212 + part_type = "CFE"; 213 + parsed_nr_parts = ret; 214 + } 215 + } 216 + } else { 217 + dev_info(&pdev->dev, "unsupported bootloader\n"); 218 + err = -ENODEV; 219 + goto err_probe; 220 + } 221 + 222 + return add_mtd_partitions(bcm963xx_mtd_info, parsed_parts, 223 + parsed_nr_parts); 224 + 225 + err_probe: 226 + iounmap(bcm963xx_map.virt); 227 + return err; 228 + } 229 + 230 + static int bcm963xx_remove(struct platform_device *pdev) 231 + { 232 + if (bcm963xx_mtd_info) { 233 + del_mtd_partitions(bcm963xx_mtd_info); 234 + map_destroy(bcm963xx_mtd_info); 235 + } 236 + 237 + if (bcm963xx_map.virt) { 238 + iounmap(bcm963xx_map.virt); 239 + bcm963xx_map.virt = 0; 240 + } 241 + 242 + return 0; 243 + } 244 + 245 + static struct platform_driver bcm63xx_mtd_dev = { 246 + .probe = bcm963xx_probe, 247 + .remove = bcm963xx_remove, 248 + .driver = { 249 + .name = "bcm963xx-flash", 250 + .owner = THIS_MODULE, 251 + }, 252 + }; 253 + 254 + static int __init bcm963xx_mtd_init(void) 255 + { 256 + return platform_driver_register(&bcm63xx_mtd_dev); 257 + } 258 + 259 + static void __exit bcm963xx_mtd_exit(void) 260 + { 261 + platform_driver_unregister(&bcm63xx_mtd_dev); 262 + } 263 + 264 + module_init(bcm963xx_mtd_init); 265 + module_exit(bcm963xx_mtd_exit); 266 + 267 + MODULE_LICENSE("GPL"); 268 + MODULE_DESCRIPTION("Broadcom BCM63xx MTD driver for CFE and RedBoot"); 269 + MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>"); 270 + MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); 271 + MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>");