OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | From d8eeb4de90e968ba32d956728c866f20752cf2c3 Mon Sep 17 00:00:00 2001 |
2 | From: Mathieu Olivari <mathieu@codeaurora.org> |
||
3 | Date: Thu, 9 Mar 2017 08:18:08 +0100 |
||
4 | Subject: [PATCH 31/69] mtd: add SMEM parser for QCOM platforms |
||
5 | |||
6 | On QCOM platforms using MTD devices storage (such as IPQ806x), SMEM is |
||
7 | used to store partition layout. This new parser can now be used to read |
||
8 | SMEM and use it to register an MTD layout according to its content. |
||
9 | |||
10 | Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org> |
||
11 | Signed-off-by: Ram Chandra Jangir <rjangi@codeaurora.org> |
||
12 | --- |
||
13 | drivers/mtd/Kconfig | 7 ++ |
||
14 | drivers/mtd/Makefile | 1 + |
||
15 | drivers/mtd/qcom_smem_part.c | 228 +++++++++++++++++++++++++++++++++++++++++++ |
||
16 | 3 files changed, 236 insertions(+) |
||
17 | create mode 100644 drivers/mtd/qcom_smem_part.c |
||
18 | |||
19 | --- a/drivers/mtd/Kconfig |
||
20 | +++ b/drivers/mtd/Kconfig |
||
21 | @@ -194,6 +194,13 @@ config MTD_MYLOADER_PARTS |
||
22 | You will still need the parsing functions to be called by the driver |
||
23 | for your particular device. It won't happen automatically. |
||
24 | |||
25 | +config MTD_QCOM_SMEM_PARTS |
||
26 | + tristate "QCOM SMEM partitioning support" |
||
27 | + depends on QCOM_SMEM |
||
28 | + help |
||
29 | + This provides partitions parser for QCOM devices using SMEM |
||
30 | + such as IPQ806x. |
||
31 | + |
||
32 | comment "User Modules And Translation Layers" |
||
33 | |||
34 | # |
||
35 | --- /dev/null |
||
36 | +++ b/drivers/mtd/qcom_smem_part.c |
||
37 | @@ -0,0 +1,235 @@ |
||
38 | +/* |
||
39 | + * Copyright (c) 2015, The Linux Foundation. All rights reserved. |
||
40 | + * |
||
41 | + * This program is free software; you can redistribute it and/or modify |
||
42 | + * it under the terms of the GNU General Public License version 2 and |
||
43 | + * only version 2 as published by the Free Software Foundation. |
||
44 | + * |
||
45 | + * This program is distributed in the hope that it will be useful, |
||
46 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
47 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
48 | + * GNU General Public License for more details. |
||
49 | + */ |
||
50 | + |
||
51 | +#include <linux/kernel.h> |
||
52 | +#include <linux/device.h> |
||
53 | +#include <linux/slab.h> |
||
54 | + |
||
55 | +#include <linux/mtd/mtd.h> |
||
56 | +#include <linux/mtd/partitions.h> |
||
57 | +#include <linux/spi/spi.h> |
||
58 | +#include <linux/module.h> |
||
59 | + |
||
60 | +#include <linux/soc/qcom/smem.h> |
||
61 | + |
||
62 | +/* Processor/host identifier for the application processor */ |
||
63 | +#define SMEM_HOST_APPS 0 |
||
64 | + |
||
65 | +/* SMEM items index */ |
||
66 | +#define SMEM_AARM_PARTITION_TABLE 9 |
||
67 | +#define SMEM_BOOT_FLASH_TYPE 421 |
||
68 | +#define SMEM_BOOT_FLASH_BLOCK_SIZE 424 |
||
69 | + |
||
70 | +/* SMEM Flash types */ |
||
71 | +#define SMEM_FLASH_NAND 2 |
||
72 | +#define SMEM_FLASH_SPI 6 |
||
73 | + |
||
74 | +#define SMEM_PART_NAME_SZ 16 |
||
75 | +#define SMEM_PARTS_MAX 32 |
||
76 | + |
||
77 | +struct smem_partition { |
||
78 | + char name[SMEM_PART_NAME_SZ]; |
||
79 | + __le32 start; |
||
80 | + __le32 size; |
||
81 | + __le32 attr; |
||
82 | +}; |
||
83 | + |
||
84 | +struct smem_partition_table { |
||
85 | + u8 magic[8]; |
||
86 | + __le32 version; |
||
87 | + __le32 len; |
||
88 | + struct smem_partition parts[SMEM_PARTS_MAX]; |
||
89 | +}; |
||
90 | + |
||
91 | +/* SMEM Magic values in partition table */ |
||
92 | +static const u8 SMEM_PTABLE_MAGIC[] = { |
||
93 | + 0xaa, 0x73, 0xee, 0x55, |
||
94 | + 0xdb, 0xbd, 0x5e, 0xe3, |
||
95 | +}; |
||
96 | + |
||
97 | +static int qcom_smem_get_flash_blksz(u64 **smem_blksz) |
||
98 | +{ |
||
99 | + size_t size; |
||
100 | + |
||
101 | + *smem_blksz = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_BLOCK_SIZE, |
||
102 | + &size); |
||
103 | + |
||
104 | + if (IS_ERR(*smem_blksz)) { |
||
105 | + pr_err("Unable to read flash blksz from SMEM\n"); |
||
106 | + return -ENOENT; |
||
107 | + } |
||
108 | + |
||
109 | + if (size != sizeof(**smem_blksz)) { |
||
110 | + pr_err("Invalid flash blksz size in SMEM\n"); |
||
111 | + return -EINVAL; |
||
112 | + } |
||
113 | + |
||
114 | + return 0; |
||
115 | +} |
||
116 | + |
||
117 | +static int qcom_smem_get_flash_type(u64 **smem_flash_type) |
||
118 | +{ |
||
119 | + size_t size; |
||
120 | + |
||
121 | + *smem_flash_type = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_TYPE, |
||
122 | + &size); |
||
123 | + |
||
124 | + if (IS_ERR(*smem_flash_type)) { |
||
125 | + pr_err("Unable to read flash type from SMEM\n"); |
||
126 | + return -ENOENT; |
||
127 | + } |
||
128 | + |
||
129 | + if (size != sizeof(**smem_flash_type)) { |
||
130 | + pr_err("Invalid flash type size in SMEM\n"); |
||
131 | + return -EINVAL; |
||
132 | + } |
||
133 | + |
||
134 | + return 0; |
||
135 | +} |
||
136 | + |
||
137 | +static int qcom_smem_get_flash_partitions(struct smem_partition_table **pparts) |
||
138 | +{ |
||
139 | + size_t size; |
||
140 | + |
||
141 | + *pparts = qcom_smem_get(SMEM_HOST_APPS, SMEM_AARM_PARTITION_TABLE, |
||
142 | + &size); |
||
143 | + |
||
144 | + if (IS_ERR(*pparts)) { |
||
145 | + pr_err("Unable to read partition table from SMEM\n"); |
||
146 | + return -ENOENT; |
||
147 | + } |
||
148 | + |
||
149 | + return 0; |
||
150 | +} |
||
151 | + |
||
152 | +static int of_dev_node_match(struct device *dev, void *data) |
||
153 | +{ |
||
154 | + return dev->of_node == data; |
||
155 | +} |
||
156 | + |
||
157 | +static bool is_spi_device(struct device_node *np) |
||
158 | +{ |
||
159 | + struct device *dev; |
||
160 | + |
||
161 | + dev = bus_find_device(&spi_bus_type, NULL, np, of_dev_node_match); |
||
162 | + if (!dev) |
||
163 | + return false; |
||
164 | + |
||
165 | + put_device(dev); |
||
166 | + return true; |
||
167 | +} |
||
168 | + |
||
169 | +static int parse_qcom_smem_partitions(struct mtd_info *master, |
||
170 | + const struct mtd_partition **pparts, |
||
171 | + struct mtd_part_parser_data *data) |
||
172 | +{ |
||
173 | + struct smem_partition_table *smem_parts; |
||
174 | + u64 *smem_flash_type, *smem_blksz; |
||
175 | + struct mtd_partition *mtd_parts; |
||
176 | + struct device_node *of_node = master->dev.of_node; |
||
177 | + int i, ret; |
||
178 | + |
||
179 | + /* |
||
180 | + * SMEM will only store the partition table of the boot device. |
||
181 | + * If this is not the boot device, do not return any partition. |
||
182 | + */ |
||
183 | + ret = qcom_smem_get_flash_type(&smem_flash_type); |
||
184 | + if (ret < 0) |
||
185 | + return ret; |
||
186 | + |
||
187 | + if ((*smem_flash_type == SMEM_FLASH_NAND && !mtd_type_is_nand(master)) |
||
188 | + || (*smem_flash_type == SMEM_FLASH_SPI && !is_spi_device(of_node))) |
||
189 | + return 0; |
||
190 | + |
||
191 | + /* |
||
192 | + * Just for sanity purpose, make sure the block size in SMEM matches the |
||
193 | + * block size of the MTD device |
||
194 | + */ |
||
195 | + ret = qcom_smem_get_flash_blksz(&smem_blksz); |
||
196 | + if (ret < 0) |
||
197 | + return ret; |
||
198 | + |
||
199 | + if (*smem_blksz != master->erasesize) { |
||
200 | + pr_err("SMEM block size differs from MTD block size\n"); |
||
201 | + return -EINVAL; |
||
202 | + } |
||
203 | + |
||
204 | + /* Get partition pointer from SMEM */ |
||
205 | + ret = qcom_smem_get_flash_partitions(&smem_parts); |
||
206 | + if (ret < 0) |
||
207 | + return ret; |
||
208 | + |
||
209 | + if (memcmp(SMEM_PTABLE_MAGIC, smem_parts->magic, |
||
210 | + sizeof(SMEM_PTABLE_MAGIC))) { |
||
211 | + pr_err("SMEM partition magic invalid\n"); |
||
212 | + return -EINVAL; |
||
213 | + } |
||
214 | + |
||
215 | + /* Allocate and populate the mtd structures */ |
||
216 | + mtd_parts = kcalloc(le32_to_cpu(smem_parts->len), sizeof(*mtd_parts), |
||
217 | + GFP_KERNEL); |
||
218 | + if (!mtd_parts) |
||
219 | + return -ENOMEM; |
||
220 | + |
||
221 | + for (i = 0; i < smem_parts->len; i++) { |
||
222 | + struct smem_partition *s_part = &smem_parts->parts[i]; |
||
223 | + struct mtd_partition *m_part = &mtd_parts[i]; |
||
224 | + |
||
225 | + m_part->name = s_part->name; |
||
226 | + m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz); |
||
227 | + m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz); |
||
228 | + |
||
229 | + /* |
||
230 | + * The last SMEM partition may have its size marked as |
||
231 | + * something like 0xffffffff, which means "until the end of the |
||
232 | + * flash device". In this case, truncate it. |
||
233 | + */ |
||
234 | + if (m_part->offset + m_part->size > master->size) |
||
235 | + m_part->size = master->size - m_part->offset; |
||
236 | + } |
||
237 | + |
||
238 | + *pparts = mtd_parts; |
||
239 | + |
||
240 | + return smem_parts->len; |
||
241 | +} |
||
242 | + |
||
243 | +static const struct of_device_id qcom_smem_of_match_table[] = { |
||
244 | + { .compatible = "qcom,smem" }, |
||
245 | + {}, |
||
246 | +}; |
||
247 | +MODULE_DEVICE_TABLE(of, qcom_smem_of_match_table); |
||
248 | + |
||
249 | +static struct mtd_part_parser qcom_smem_parser = { |
||
250 | + .owner = THIS_MODULE, |
||
251 | + .parse_fn = parse_qcom_smem_partitions, |
||
252 | + .name = "qcom-smem", |
||
253 | + .of_match_table = qcom_smem_of_match_table, |
||
254 | +}; |
||
255 | + |
||
256 | +static int __init qcom_smem_parser_init(void) |
||
257 | +{ |
||
258 | + register_mtd_parser(&qcom_smem_parser); |
||
259 | + return 0; |
||
260 | +} |
||
261 | + |
||
262 | +static void __exit qcom_smem_parser_exit(void) |
||
263 | +{ |
||
264 | + deregister_mtd_parser(&qcom_smem_parser); |
||
265 | +} |
||
266 | + |
||
267 | +module_init(qcom_smem_parser_init); |
||
268 | +module_exit(qcom_smem_parser_exit); |
||
269 | + |
||
270 | +MODULE_LICENSE("GPL"); |
||
271 | +MODULE_AUTHOR("Mathieu Olivari <mathieu@codeaurora.org>"); |
||
272 | +MODULE_DESCRIPTION("Parsing code for SMEM based partition tables"); |
||
273 | --- a/drivers/mtd/Makefile |
||
274 | +++ b/drivers/mtd/Makefile |
||
275 | @@ -17,6 +17,7 @@ obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o |
||
276 | obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o |
||
277 | obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o |
||
278 | obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o |
||
279 | +obj-$(CONFIG_MTD_QCOM_SMEM_PARTS) += qcom_smem_part.o |
||
280 | obj-y += parsers/ |
||
281 | |||
282 | # 'Users' - code which presents functionality to userspace. |