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

mtd: maps: bcm963xx-flash: make CFE partition parsing an mtd parser

Recent BCM63XX devices support a variety of flash types (parallel, SPI,
NAND) and share the partition layout. To prevent code duplication make
the CFE partition parsing code a stand alone mtd parser to allow SPI or
NAND flash drivers to use it.

Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
Acked-by: Florian Fainelli <florian@openwrt.org>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>

authored by

Jonas Gorski and committed by
David Woodhouse
70a3c167 ca105f4d

+202 -150
+8
drivers/mtd/Kconfig
··· 140 140 ---help--- 141 141 TI AR7 partitioning support 142 142 143 + config MTD_BCM63XX_PARTS 144 + tristate "BCM63XX CFE partitioning support" 145 + depends on BCM63XX 146 + select CRC32 147 + help 148 + This provides partions parsing for BCM63xx devices with CFE 149 + bootloaders. 150 + 143 151 comment "User Modules And Translation Layers" 144 152 145 153 config MTD_CHAR
+1
drivers/mtd/Makefile
··· 11 11 obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o 12 12 obj-$(CONFIG_MTD_AFS_PARTS) += afs.o 13 13 obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o 14 + obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o 14 15 15 16 # 'Users' - code which presents functionality to userspace. 16 17 obj-$(CONFIG_MTD_CHAR) += mtdchar.o
+189
drivers/mtd/bcm63xxpart.c
··· 1 + /* 2 + * BCM63XX CFE image tag parser 3 + * 4 + * Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org> 5 + * Mike Albon <malbon@openwrt.org> 6 + * Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net> 7 + * Copyright © 2011 Jonas Gorski <jonas.gorski@gmail.com> 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; either version 2 of the License, or 12 + * (at your option) any later version. 13 + * 14 + * This program is distributed in the hope that it will be useful, 15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 + * GNU General Public License for more details. 18 + * 19 + * You should have received a copy of the GNU General Public License 20 + * along with this program; if not, write to the Free Software 21 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 + * 23 + */ 24 + 25 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 26 + 27 + #include <linux/module.h> 28 + #include <linux/kernel.h> 29 + #include <linux/slab.h> 30 + #include <linux/vmalloc.h> 31 + #include <linux/mtd/mtd.h> 32 + #include <linux/mtd/partitions.h> 33 + 34 + #include <asm/mach-bcm63xx/bcm963xx_tag.h> 35 + 36 + #define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */ 37 + 38 + static int bcm63xx_detect_cfe(struct mtd_info *master) 39 + { 40 + int idoffset = 0x4e0; 41 + static char idstring[8] = "CFE1CFE1"; 42 + char buf[9]; 43 + int ret; 44 + size_t retlen; 45 + 46 + ret = master->read(master, idoffset, 8, &retlen, (void *)buf); 47 + buf[retlen] = 0; 48 + pr_info("Read Signature value of %s\n", buf); 49 + 50 + return strncmp(idstring, buf, 8); 51 + } 52 + 53 + static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, 54 + struct mtd_partition **pparts, 55 + struct mtd_part_parser_data *data) 56 + { 57 + /* CFE, NVRAM and global Linux are always present */ 58 + int nrparts = 3, curpart = 0; 59 + struct bcm_tag *buf; 60 + struct mtd_partition *parts; 61 + int ret; 62 + size_t retlen; 63 + unsigned int rootfsaddr, kerneladdr, spareaddr; 64 + unsigned int rootfslen, kernellen, sparelen, totallen; 65 + int namelen = 0; 66 + int i; 67 + char *boardid; 68 + char *tagversion; 69 + 70 + if (bcm63xx_detect_cfe(master)) 71 + return -EINVAL; 72 + 73 + /* Allocate memory for buffer */ 74 + buf = vmalloc(sizeof(struct bcm_tag)); 75 + if (!buf) 76 + return -ENOMEM; 77 + 78 + /* Get the tag */ 79 + ret = master->read(master, master->erasesize, sizeof(struct bcm_tag), 80 + &retlen, (void *)buf); 81 + if (retlen != sizeof(struct bcm_tag)) { 82 + vfree(buf); 83 + return -EIO; 84 + } 85 + 86 + sscanf(buf->kernel_address, "%u", &kerneladdr); 87 + sscanf(buf->kernel_length, "%u", &kernellen); 88 + sscanf(buf->total_length, "%u", &totallen); 89 + tagversion = &(buf->tag_version[0]); 90 + boardid = &(buf->board_id[0]); 91 + 92 + pr_info("CFE boot tag found with version %s and board type %s\n", 93 + tagversion, boardid); 94 + 95 + kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE; 96 + rootfsaddr = kerneladdr + kernellen; 97 + spareaddr = roundup(totallen, master->erasesize) + master->erasesize; 98 + sparelen = master->size - spareaddr - master->erasesize; 99 + rootfslen = spareaddr - rootfsaddr; 100 + 101 + /* Determine number of partitions */ 102 + namelen = 8; 103 + if (rootfslen > 0) { 104 + nrparts++; 105 + namelen += 6; 106 + } 107 + if (kernellen > 0) { 108 + nrparts++; 109 + namelen += 6; 110 + } 111 + 112 + /* Ask kernel for more memory */ 113 + parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL); 114 + if (!parts) { 115 + vfree(buf); 116 + return -ENOMEM; 117 + } 118 + 119 + /* Start building partition list */ 120 + parts[curpart].name = "CFE"; 121 + parts[curpart].offset = 0; 122 + parts[curpart].size = master->erasesize; 123 + curpart++; 124 + 125 + if (kernellen > 0) { 126 + parts[curpart].name = "kernel"; 127 + parts[curpart].offset = kerneladdr; 128 + parts[curpart].size = kernellen; 129 + curpart++; 130 + } 131 + 132 + if (rootfslen > 0) { 133 + parts[curpart].name = "rootfs"; 134 + parts[curpart].offset = rootfsaddr; 135 + parts[curpart].size = rootfslen; 136 + if (sparelen > 0) 137 + parts[curpart].size += sparelen; 138 + curpart++; 139 + } 140 + 141 + parts[curpart].name = "nvram"; 142 + parts[curpart].offset = master->size - master->erasesize; 143 + parts[curpart].size = master->erasesize; 144 + 145 + /* Global partition "linux" to make easy firmware upgrade */ 146 + curpart++; 147 + parts[curpart].name = "linux"; 148 + parts[curpart].offset = parts[0].size; 149 + parts[curpart].size = master->size - parts[0].size - parts[3].size; 150 + 151 + for (i = 0; i < nrparts; i++) 152 + pr_info("Partition %d is %s offset %lx and length %lx\n", i, 153 + parts[i].name, (long unsigned int)(parts[i].offset), 154 + (long unsigned int)(parts[i].size)); 155 + 156 + pr_info("Spare partition is offset %x and length %x\n", spareaddr, 157 + sparelen); 158 + 159 + *pparts = parts; 160 + vfree(buf); 161 + 162 + return nrparts; 163 + }; 164 + 165 + static struct mtd_part_parser bcm63xx_cfe_parser = { 166 + .owner = THIS_MODULE, 167 + .parse_fn = bcm63xx_parse_cfe_partitions, 168 + .name = "bcm63xxpart", 169 + }; 170 + 171 + static int __init bcm63xx_cfe_parser_init(void) 172 + { 173 + return register_mtd_parser(&bcm63xx_cfe_parser); 174 + } 175 + 176 + static void __exit bcm63xx_cfe_parser_exit(void) 177 + { 178 + deregister_mtd_parser(&bcm63xx_cfe_parser); 179 + } 180 + 181 + module_init(bcm63xx_cfe_parser_init); 182 + module_exit(bcm63xx_cfe_parser_exit); 183 + 184 + MODULE_LICENSE("GPL"); 185 + MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>"); 186 + MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); 187 + MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>"); 188 + MODULE_AUTHOR("Jonas Gorski <jonas.gorski@gmail.com"); 189 + MODULE_DESCRIPTION("MTD partitioning for BCM63XX CFE bootloaders");
+1
drivers/mtd/maps/Kconfig
··· 247 247 depends on BCM63XX 248 248 select MTD_MAP_BANK_WIDTH_2 249 249 select MTD_CFI_I1 250 + select MTD_BCM63XX_PARTS 250 251 help 251 252 Support for parsing CFE image tag and creating MTD partitions on 252 253 Broadcom BCM63xx boards.
+3 -150
drivers/mtd/maps/bcm963xx-flash.c
··· 27 27 #include <linux/mtd/map.h> 28 28 #include <linux/mtd/mtd.h> 29 29 #include <linux/mtd/partitions.h> 30 - #include <linux/vmalloc.h> 31 30 #include <linux/platform_device.h> 32 31 #include <linux/io.h> 33 32 34 - #include <asm/mach-bcm63xx/bcm963xx_tag.h> 35 - 36 33 #define BCM63XX_BUSWIDTH 2 /* Buswidth */ 37 - #define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */ 38 - 39 - static struct mtd_partition *parsed_parts; 40 34 41 35 static struct mtd_info *bcm963xx_mtd_info; 42 36 ··· 39 45 .bankwidth = BCM63XX_BUSWIDTH, 40 46 }; 41 47 42 - static int parse_cfe_partitions(struct mtd_info *master, 43 - struct mtd_partition **pparts) 44 - { 45 - /* CFE, NVRAM and global Linux are always present */ 46 - int nrparts = 3, curpart = 0; 47 - struct bcm_tag *buf; 48 - struct mtd_partition *parts; 49 - int ret; 50 - size_t retlen; 51 - unsigned int rootfsaddr, kerneladdr, spareaddr; 52 - unsigned int rootfslen, kernellen, sparelen, totallen; 53 - int namelen = 0; 54 - int i; 55 - char *boardid; 56 - char *tagversion; 57 - 58 - /* Allocate memory for buffer */ 59 - buf = vmalloc(sizeof(struct bcm_tag)); 60 - if (!buf) 61 - return -ENOMEM; 62 - 63 - /* Get the tag */ 64 - ret = master->read(master, master->erasesize, sizeof(struct bcm_tag), 65 - &retlen, (void *)buf); 66 - if (retlen != sizeof(struct bcm_tag)) { 67 - vfree(buf); 68 - return -EIO; 69 - } 70 - 71 - sscanf(buf->kernel_address, "%u", &kerneladdr); 72 - sscanf(buf->kernel_length, "%u", &kernellen); 73 - sscanf(buf->total_length, "%u", &totallen); 74 - tagversion = &(buf->tag_version[0]); 75 - boardid = &(buf->board_id[0]); 76 - 77 - pr_info("CFE boot tag found with version %s and board type %s\n", 78 - tagversion, boardid); 79 - 80 - kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE; 81 - rootfsaddr = kerneladdr + kernellen; 82 - spareaddr = roundup(totallen, master->erasesize) + master->erasesize; 83 - sparelen = master->size - spareaddr - master->erasesize; 84 - rootfslen = spareaddr - rootfsaddr; 85 - 86 - /* Determine number of partitions */ 87 - namelen = 8; 88 - if (rootfslen > 0) { 89 - nrparts++; 90 - namelen += 6; 91 - } 92 - if (kernellen > 0) { 93 - nrparts++; 94 - namelen += 6; 95 - } 96 - 97 - /* Ask kernel for more memory */ 98 - parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL); 99 - if (!parts) { 100 - vfree(buf); 101 - return -ENOMEM; 102 - } 103 - 104 - /* Start building partition list */ 105 - parts[curpart].name = "CFE"; 106 - parts[curpart].offset = 0; 107 - parts[curpart].size = master->erasesize; 108 - curpart++; 109 - 110 - if (kernellen > 0) { 111 - parts[curpart].name = "kernel"; 112 - parts[curpart].offset = kerneladdr; 113 - parts[curpart].size = kernellen; 114 - curpart++; 115 - } 116 - 117 - if (rootfslen > 0) { 118 - parts[curpart].name = "rootfs"; 119 - parts[curpart].offset = rootfsaddr; 120 - parts[curpart].size = rootfslen; 121 - if (sparelen > 0) 122 - parts[curpart].size += sparelen; 123 - curpart++; 124 - } 125 - 126 - parts[curpart].name = "nvram"; 127 - parts[curpart].offset = master->size - master->erasesize; 128 - parts[curpart].size = master->erasesize; 129 - 130 - /* Global partition "linux" to make easy firmware upgrade */ 131 - curpart++; 132 - parts[curpart].name = "linux"; 133 - parts[curpart].offset = parts[0].size; 134 - parts[curpart].size = master->size - parts[0].size - parts[3].size; 135 - 136 - for (i = 0; i < nrparts; i++) 137 - pr_info("Partition %d is %s offset %lx and length %lx\n", i, 138 - parts[i].name, (long unsigned int)(parts[i].offset), 139 - (long unsigned int)(parts[i].size)); 140 - 141 - pr_info("Spare partition is offset %x and length %x\n", spareaddr, 142 - sparelen); 143 - 144 - *pparts = parts; 145 - vfree(buf); 146 - 147 - return nrparts; 148 - }; 149 - 150 - static int bcm963xx_detect_cfe(struct mtd_info *master) 151 - { 152 - int idoffset = 0x4e0; 153 - static char idstring[8] = "CFE1CFE1"; 154 - char buf[9]; 155 - int ret; 156 - size_t retlen; 157 - 158 - ret = master->read(master, idoffset, 8, &retlen, (void *)buf); 159 - buf[retlen] = 0; 160 - printk(KERN_INFO PFX "Read Signature value of %s\n", buf); 161 - 162 - return strncmp(idstring, buf, 8); 163 - } 48 + static const char *part_types[] = { "bcm63xxpart", NULL }; 164 49 165 50 static int bcm963xx_probe(struct platform_device *pdev) 166 51 { 167 52 int err = 0; 168 - int parsed_nr_parts = 0; 169 - char *part_type; 170 53 struct resource *r; 171 54 172 55 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ··· 79 208 probe_ok: 80 209 bcm963xx_mtd_info->owner = THIS_MODULE; 81 210 82 - /* This is mutually exclusive */ 83 - if (bcm963xx_detect_cfe(bcm963xx_mtd_info) == 0) { 84 - dev_info(&pdev->dev, "CFE bootloader detected\n"); 85 - if (parsed_nr_parts == 0) { 86 - int ret = parse_cfe_partitions(bcm963xx_mtd_info, 87 - &parsed_parts); 88 - if (ret > 0) { 89 - part_type = "CFE"; 90 - parsed_nr_parts = ret; 91 - } 92 - } 93 - } else { 94 - dev_info(&pdev->dev, "unsupported bootloader\n"); 95 - err = -ENODEV; 96 - goto err_probe; 97 - } 98 - 99 - return mtd_device_register(bcm963xx_mtd_info, parsed_parts, 100 - parsed_nr_parts); 101 - 211 + return mtd_device_parse_register(bcm963xx_mtd_info, part_types, NULL, 212 + NULL, 0); 102 213 err_probe: 103 214 iounmap(bcm963xx_map.virt); 104 215 return err;