]> Git Repo - linux.git/blob - drivers/mtd/parsers/parser_imagetag.c
ARM: dts: imx7s: Enable SNVS power key according to board design
[linux.git] / drivers / mtd / parsers / parser_imagetag.c
1 /*
2  * BCM63XX CFE image tag parser
3  *
4  * Copyright © 2006-2008  Florian Fainelli <[email protected]>
5  *                        Mike Albon <[email protected]>
6  * Copyright © 2009-2010  Daniel Dickinson <[email protected]>
7  * Copyright © 2011-2013  Jonas Gorski <[email protected]>
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  */
15
16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17
18 #include <linux/bcm963xx_tag.h>
19 #include <linux/crc32.h>
20 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include <linux/sizes.h>
23 #include <linux/slab.h>
24 #include <linux/vmalloc.h>
25 #include <linux/mtd/mtd.h>
26 #include <linux/mtd/partitions.h>
27 #include <linux/of.h>
28
29 /* Ensure strings read from flash structs are null terminated */
30 #define STR_NULL_TERMINATE(x) \
31         do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0)
32
33 static int bcm963xx_read_imagetag(struct mtd_info *master, const char *name,
34         loff_t tag_offset, struct bcm_tag *buf)
35 {
36         int ret;
37         size_t retlen;
38         u32 computed_crc;
39
40         ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf);
41         if (ret)
42                 return ret;
43
44         if (retlen != sizeof(*buf))
45                 return -EIO;
46
47         computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
48                                 offsetof(struct bcm_tag, header_crc));
49         if (computed_crc == buf->header_crc) {
50                 STR_NULL_TERMINATE(buf->board_id);
51                 STR_NULL_TERMINATE(buf->tag_version);
52
53                 pr_info("%s: CFE image tag found at 0x%llx with version %s, board type %s\n",
54                         name, tag_offset, buf->tag_version, buf->board_id);
55
56                 return 0;
57         }
58
59         pr_warn("%s: CFE image tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n",
60                 name, tag_offset, buf->header_crc, computed_crc);
61         return -EINVAL;
62 }
63
64 static int bcm963xx_parse_imagetag_partitions(struct mtd_info *master,
65                                         const struct mtd_partition **pparts,
66                                         struct mtd_part_parser_data *data)
67 {
68         /* CFE, NVRAM and global Linux are always present */
69         int nrparts = 0, curpart = 0;
70         struct bcm_tag *buf = NULL;
71         struct mtd_partition *parts;
72         int ret;
73         unsigned int rootfsaddr, kerneladdr, spareaddr, offset;
74         unsigned int rootfslen, kernellen, sparelen, totallen;
75         int i;
76         bool rootfs_first = false;
77
78         buf = vmalloc(sizeof(struct bcm_tag));
79         if (!buf)
80                 return -ENOMEM;
81
82         /* Get the tag */
83         ret = bcm963xx_read_imagetag(master, "rootfs", 0, buf);
84         if (!ret) {
85                 STR_NULL_TERMINATE(buf->flash_image_start);
86                 if (kstrtouint(buf->flash_image_start, 10, &rootfsaddr) ||
87                                 rootfsaddr < BCM963XX_EXTENDED_SIZE) {
88                         pr_err("invalid rootfs address: %*ph\n",
89                                 (int)sizeof(buf->flash_image_start),
90                                 buf->flash_image_start);
91                         goto out;
92                 }
93
94                 STR_NULL_TERMINATE(buf->kernel_address);
95                 if (kstrtouint(buf->kernel_address, 10, &kerneladdr) ||
96                                 kerneladdr < BCM963XX_EXTENDED_SIZE) {
97                         pr_err("invalid kernel address: %*ph\n",
98                                 (int)sizeof(buf->kernel_address),
99                                 buf->kernel_address);
100                         goto out;
101                 }
102
103                 STR_NULL_TERMINATE(buf->kernel_length);
104                 if (kstrtouint(buf->kernel_length, 10, &kernellen)) {
105                         pr_err("invalid kernel length: %*ph\n",
106                                 (int)sizeof(buf->kernel_length),
107                                 buf->kernel_length);
108                         goto out;
109                 }
110
111                 STR_NULL_TERMINATE(buf->total_length);
112                 if (kstrtouint(buf->total_length, 10, &totallen)) {
113                         pr_err("invalid total length: %*ph\n",
114                                 (int)sizeof(buf->total_length),
115                                 buf->total_length);
116                         goto out;
117                 }
118
119                 /*
120                  * Addresses are flash absolute, so convert to partition
121                  * relative addresses. Assume either kernel or rootfs will
122                  * directly follow the image tag.
123                  */
124                 if (rootfsaddr < kerneladdr)
125                         offset = rootfsaddr - sizeof(struct bcm_tag);
126                 else
127                         offset = kerneladdr - sizeof(struct bcm_tag);
128
129                 kerneladdr = kerneladdr - offset;
130                 rootfsaddr = rootfsaddr - offset;
131                 spareaddr = roundup(totallen, master->erasesize);
132
133                 if (rootfsaddr < kerneladdr) {
134                         /* default Broadcom layout */
135                         rootfslen = kerneladdr - rootfsaddr;
136                         rootfs_first = true;
137                 } else {
138                         /* OpenWrt layout */
139                         rootfsaddr = kerneladdr + kernellen;
140                         rootfslen = spareaddr - rootfsaddr;
141                 }
142         } else {
143                 goto out;
144         }
145         sparelen = master->size - spareaddr;
146
147         /* Determine number of partitions */
148         if (rootfslen > 0)
149                 nrparts++;
150
151         if (kernellen > 0)
152                 nrparts++;
153
154         parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
155         if (!parts) {
156                 ret = -ENOMEM;
157                 goto out;
158         }
159
160         /* Start building partition list */
161         if (kernellen > 0) {
162                 int kernelpart = curpart;
163
164                 if (rootfslen > 0 && rootfs_first)
165                         kernelpart++;
166                 parts[kernelpart].name = "kernel";
167                 parts[kernelpart].offset = kerneladdr;
168                 parts[kernelpart].size = kernellen;
169                 curpart++;
170         }
171
172         if (rootfslen > 0) {
173                 int rootfspart = curpart;
174
175                 if (kernellen > 0 && rootfs_first)
176                         rootfspart--;
177                 parts[rootfspart].name = "rootfs";
178                 parts[rootfspart].offset = rootfsaddr;
179                 parts[rootfspart].size = rootfslen;
180                 if (sparelen > 0  && !rootfs_first)
181                         parts[rootfspart].size += sparelen;
182                 curpart++;
183         }
184
185         for (i = 0; i < nrparts; i++)
186                 pr_info("Partition %d is %s offset %llx and length %llx\n", i,
187                         parts[i].name, parts[i].offset, parts[i].size);
188
189         pr_info("Spare partition is offset %x and length %x\n", spareaddr,
190                 sparelen);
191
192         *pparts = parts;
193         ret = 0;
194
195 out:
196         vfree(buf);
197
198         if (ret)
199                 return ret;
200
201         return nrparts;
202 }
203
204 static const struct of_device_id parse_bcm963xx_imagetag_match_table[] = {
205         { .compatible = "brcm,bcm963xx-imagetag" },
206         {},
207 };
208 MODULE_DEVICE_TABLE(of, parse_bcm963xx_imagetag_match_table);
209
210 static struct mtd_part_parser bcm963xx_imagetag_parser = {
211         .parse_fn = bcm963xx_parse_imagetag_partitions,
212         .name = "bcm963xx-imagetag",
213         .of_match_table = parse_bcm963xx_imagetag_match_table,
214 };
215 module_mtd_part_parser(bcm963xx_imagetag_parser);
216
217 MODULE_LICENSE("GPL");
218 MODULE_AUTHOR("Daniel Dickinson <[email protected]>");
219 MODULE_AUTHOR("Florian Fainelli <[email protected]>");
220 MODULE_AUTHOR("Mike Albon <[email protected]>");
221 MODULE_AUTHOR("Jonas Gorski <[email protected]>");
222 MODULE_DESCRIPTION("MTD parser for BCM963XX CFE Image Tag partitions");
This page took 0.042801 seconds and 4 git commands to generate.