340091fab94019b7f1a492d3133730c6654422dc
[openwrt/staging/nbd.git] /
1 From 09cf6ee6d21cd9ef2eb857ccb24305cf51166792 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
3 Date: Thu, 11 Feb 2021 23:04:27 +0100
4 Subject: [PATCH] mtd: parsers: ofpart: support BCM4908 fixed partitions
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 BCM4908 partitioning is based on fixed layout but allows specifying
10 multiple firmware partitions. It requires detecting which firmware
11 partition was used for booting current kernel.
12
13 To support such cases without duplicating a lot of code (without copying
14 most of the ofpart.c code) support for post-parsing callback was added.
15
16 BCM4908 callback simply reads offset of currently used firmware
17 partition from the DT. Bootloader specifies it using the "brcm_blparms"
18 property.
19
20 Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
21 Signed-off-by: Richard Weinberger <richard@nod.at>
22 ---
23 drivers/mtd/parsers/Makefile | 1 +
24 drivers/mtd/parsers/bcm4908-partitions.c | 64 ++++++++++++++++++++++++
25 drivers/mtd/parsers/bcm4908-partitions.h | 7 +++
26 drivers/mtd/parsers/ofpart.c | 28 ++++++++++-
27 4 files changed, 98 insertions(+), 2 deletions(-)
28 create mode 100644 drivers/mtd/parsers/bcm4908-partitions.c
29 create mode 100644 drivers/mtd/parsers/bcm4908-partitions.h
30
31 --- a/drivers/mtd/parsers/Makefile
32 +++ b/drivers/mtd/parsers/Makefile
33 @@ -4,6 +4,7 @@ obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm4
34 obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
35 obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
36 obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
37 +obj-$(CONFIG_MTD_OF_PARTS) += bcm4908-partitions.o
38 obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
39 obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
40 obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
41 --- /dev/null
42 +++ b/drivers/mtd/parsers/bcm4908-partitions.c
43 @@ -0,0 +1,64 @@
44 +// SPDX-License-Identifier: GPL-2.0
45 +/*
46 + * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
47 + */
48 +
49 +#include <linux/module.h>
50 +#include <linux/init.h>
51 +#include <linux/of.h>
52 +#include <linux/mtd/mtd.h>
53 +#include <linux/slab.h>
54 +#include <linux/mtd/partitions.h>
55 +
56 +#include "bcm4908-partitions.h"
57 +
58 +#define BLPARAMS_FW_OFFSET "NAND_RFS_OFS"
59 +
60 +static long long bcm4908_partitions_fw_offset(void)
61 +{
62 + struct device_node *root;
63 + struct property *prop;
64 + const char *s;
65 +
66 + root = of_find_node_by_path("/");
67 + if (!root)
68 + return -ENOENT;
69 +
70 + of_property_for_each_string(root, "brcm_blparms", prop, s) {
71 + size_t len = strlen(BLPARAMS_FW_OFFSET);
72 + unsigned long offset;
73 + int err;
74 +
75 + if (strncmp(s, BLPARAMS_FW_OFFSET, len) || s[len] != '=')
76 + continue;
77 +
78 + err = kstrtoul(s + len + 1, 0, &offset);
79 + if (err) {
80 + pr_err("failed to parse %s\n", s + len + 1);
81 + return err;
82 + }
83 +
84 + return offset << 10;
85 + }
86 +
87 + return -ENOENT;
88 +}
89 +
90 +int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts)
91 +{
92 + long long fw_offset;
93 + int i;
94 +
95 + fw_offset = bcm4908_partitions_fw_offset();
96 +
97 + for (i = 0; i < nr_parts; i++) {
98 + if (of_device_is_compatible(parts[i].of_node, "brcm,bcm4908-firmware")) {
99 + if (fw_offset < 0 || parts[i].offset == fw_offset)
100 + parts[i].name = "firmware";
101 + else
102 + parts[i].name = "backup";
103 + }
104 + }
105 +
106 + return 0;
107 +}
108 --- /dev/null
109 +++ b/drivers/mtd/parsers/bcm4908-partitions.h
110 @@ -0,0 +1,7 @@
111 +/* SPDX-License-Identifier: GPL-2.0 */
112 +#ifndef __BCM4908_PARTITIONS_H
113 +#define __BCM4908_PARTITIONS_H
114 +
115 +int bcm4908_partitions_post_parse(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
116 +
117 +#endif
118 --- a/drivers/mtd/parsers/ofpart.c
119 +++ b/drivers/mtd/parsers/ofpart.c
120 @@ -16,6 +16,18 @@
121 #include <linux/slab.h>
122 #include <linux/mtd/partitions.h>
123
124 +#include "bcm4908-partitions.h"
125 +
126 +struct fixed_partitions_quirks {
127 + int (*post_parse)(struct mtd_info *mtd, struct mtd_partition *parts, int nr_parts);
128 +};
129 +
130 +struct fixed_partitions_quirks bcm4908_partitions_quirks = {
131 + .post_parse = bcm4908_partitions_post_parse,
132 +};
133 +
134 +static const struct of_device_id parse_ofpart_match_table[];
135 +
136 static bool node_has_compatible(struct device_node *pp)
137 {
138 return of_get_property(pp, "compatible", NULL);
139 @@ -25,6 +37,8 @@ static int parse_fixed_partitions(struct
140 const struct mtd_partition **pparts,
141 struct mtd_part_parser_data *data)
142 {
143 + const struct fixed_partitions_quirks *quirks;
144 + const struct of_device_id *of_id;
145 struct mtd_partition *parts;
146 struct device_node *mtd_node;
147 struct device_node *ofpart_node;
148 @@ -33,7 +47,6 @@ static int parse_fixed_partitions(struct
149 int nr_parts, i, ret = 0;
150 bool dedicated = true;
151
152 -
153 /* Pull of_node from the master device node */
154 mtd_node = mtd_get_of_node(master);
155 if (!mtd_node)
156 @@ -50,11 +63,16 @@ static int parse_fixed_partitions(struct
157 master->name, mtd_node);
158 ofpart_node = mtd_node;
159 dedicated = false;
160 - } else if (!of_device_is_compatible(ofpart_node, "fixed-partitions")) {
161 + }
162 +
163 + of_id = of_match_node(parse_ofpart_match_table, ofpart_node);
164 + if (dedicated && !of_id) {
165 /* The 'partitions' subnode might be used by another parser */
166 return 0;
167 }
168
169 + quirks = of_id ? of_id->data : NULL;
170 +
171 /* First count the subnodes */
172 nr_parts = 0;
173 for_each_child_of_node(ofpart_node, pp) {
174 @@ -123,6 +141,9 @@ static int parse_fixed_partitions(struct
175 if (!nr_parts)
176 goto ofpart_none;
177
178 + if (quirks && quirks->post_parse)
179 + quirks->post_parse(master, parts, nr_parts);
180 +
181 *pparts = parts;
182 return nr_parts;
183
184 @@ -137,7 +158,10 @@ ofpart_none:
185 }
186
187 static const struct of_device_id parse_ofpart_match_table[] = {
188 + /* Generic */
189 { .compatible = "fixed-partitions" },
190 + /* Customized */
191 + { .compatible = "brcm,bcm4908-partitions", .data = &bcm4908_partitions_quirks, },
192 {},
193 };
194 MODULE_DEVICE_TABLE(of, parse_ofpart_match_table);