Skip to content

Commit da170e8

Browse files
committed
of: Improve compatibility with old Pi 5 firmware
With the jump to the 6.18 kernel we dropped a patch that had been overriding #size-cells in the upstream bcm2712 dts files. The result is cleaner, but only Pi 5 and CM5 EEPROMs since February 2025 are compatible with it. Apply a few hacks to the kernel's early DT parsing and to the 2712 dts so that the EEPROM is able to update the CMA section and the kernel is able to read the result, despite the fact that it is malformed. Signed-off-by: Phil Elwell <phil@raspberrypi.com>
1 parent 95b85be commit da170e8

3 files changed

Lines changed: 78 additions & 7 deletions

File tree

arch/arm64/boot/dts/broadcom/bcm2712-ds.dtsi

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,17 @@
6060
};
6161
};
6262

63+
/*
64+
* With a #size-cells of 2, the 'size' property should be 2 cells long.
65+
* Unfortunately the old firmware will only write the CMA value correctly
66+
* if the property is 1 cell long. Fortunately the new firmware silently
67+
* makes 'size' 2 cells long, so create what is actually an invalid DTS file
68+
* on the understanding that it will be patched up as needed.
69+
*/
70+
&cma {
71+
size = <0x4000000>; /* 64MB */
72+
};
73+
6374
&soc {
6475
system_timer: timer@7c003000 {
6576
compatible = "brcm,bcm2835-system-timer";

drivers/of/fdt.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,7 @@ int __init early_init_dt_scan_memory(void)
10331033

10341034
fdt_for_each_subnode(node, fdt, 0) {
10351035
const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
1036+
int actual_size_cells = dt_root_size_cells;
10361037
const __be32 *reg, *endp;
10371038
int l;
10381039
bool hotpluggable;
@@ -1050,17 +1051,41 @@ int __init early_init_dt_scan_memory(void)
10501051
if (reg == NULL)
10511052
continue;
10521053

1054+
if (dt_root_size_cells == 2 &&
1055+
l % ((dt_root_addr_cells + 1) * sizeof(__be32)) == 0) {
1056+
/* Scan the reg property to see if the content makes sense with size-cells == 1 */
1057+
const int size_cells = 1;
1058+
const __be32 *r = reg;
1059+
bool ok = true;
1060+
1061+
endp = reg + (l / sizeof(__be32));
1062+
while ((endp - r) >= (dt_root_addr_cells + size_cells)) {
1063+
const u64 megabyte = 1024 * 1024ull;
1064+
const u64 max_memory = 64 * 1024 * 1024 * 1024ull;
1065+
u64 base, size;
1066+
1067+
base = dt_mem_next_cell(dt_root_addr_cells, &r);
1068+
size = dt_mem_next_cell(size_cells, &r);
1069+
if (base % megabyte != 0 || base >= max_memory ||
1070+
size % megabyte != 0 || size >= max_memory ||
1071+
size == 0)
1072+
ok = false;
1073+
}
1074+
if (ok)
1075+
actual_size_cells = size_cells;
1076+
}
1077+
10531078
endp = reg + (l / sizeof(__be32));
10541079
hotpluggable = of_get_flat_dt_prop(node, "hotpluggable", NULL);
10551080

10561081
pr_debug("memory scan node %s, reg size %d,\n",
10571082
fdt_get_name(fdt, node, NULL), l);
10581083

1059-
while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
1084+
while ((endp - reg) >= (dt_root_addr_cells + actual_size_cells)) {
10601085
u64 base, size;
10611086

10621087
base = dt_mem_next_cell(dt_root_addr_cells, &reg);
1063-
size = dt_mem_next_cell(dt_root_size_cells, &reg);
1088+
size = dt_mem_next_cell(actual_size_cells, &reg);
10641089

10651090
if (size == 0)
10661091
continue;

drivers/of/of_reserved_mem.c

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,25 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
159159
int len;
160160
const __be32 *prop;
161161
bool nomap, default_cma;
162+
int actual_size_cells = 0;
162163

163164
prop = of_get_flat_dt_prop(node, "reg", &len);
164165
if (!prop)
165166
return -ENOENT;
166167

168+
if (dt_root_addr_cells == 2 &&
169+
dt_root_size_cells == 2 &&
170+
len == (2 + 1) * sizeof(__be32)) {
171+
pr_warn("invalid reg property size in '%s' - firmware out-of-date?\n",
172+
uname);
173+
actual_size_cells = 1;
174+
t_len = (dt_root_addr_cells + actual_size_cells) * sizeof(__be32);
175+
} else {
176+
actual_size_cells = dt_root_size_cells;
177+
}
178+
179+
t_len = (dt_root_addr_cells + actual_size_cells) * sizeof(__be32);
180+
167181
if (len && len % t_len != 0) {
168182
pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n",
169183
uname);
@@ -180,7 +194,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
180194

181195
while (len >= t_len) {
182196
base = dt_mem_next_cell(dt_root_addr_cells, &prop);
183-
size = dt_mem_next_cell(dt_root_size_cells, &prop);
197+
size = dt_mem_next_cell(actual_size_cells, &prop);
184198

185199
if (size && early_init_dt_reserve_memory(base, size, nomap) == 0) {
186200
/* Architecture specific contiguous memory fixup. */
@@ -267,8 +281,21 @@ void __init fdt_scan_reserved_mem_reg_nodes(void)
267281
if (default_cma && cma_skip_dt_default_reserved_mem())
268282
continue;
269283

270-
if (!of_flat_dt_get_addr_size(child, "reg", &b, &s))
271-
continue;
284+
if (!of_flat_dt_get_addr_size(child, "reg", &b, &s)) {
285+
const __be32 *prop;
286+
int size;
287+
288+
prop = of_get_flat_dt_prop(child, "reg", &size);
289+
if (dt_root_addr_cells == 2 &&
290+
dt_root_size_cells == 2 &&
291+
size == 12) {
292+
/* Handle this specific error case from old firmware */
293+
b = of_read_number(prop, dt_root_addr_cells);
294+
s = of_read_number(prop + 2, 1);
295+
} else {
296+
continue;
297+
}
298+
}
272299

273300
base = b;
274301
size = s;
@@ -406,16 +433,24 @@ static int __init __reserved_mem_alloc_size(unsigned long node, const char *unam
406433
const __be32 *prop;
407434
bool nomap, default_cma;
408435
int ret;
436+
int actual_size_cells;
409437

410438
prop = of_get_flat_dt_prop(node, "size", &len);
411439
if (!prop)
412440
return -EINVAL;
441+
if (dt_root_size_cells == 2 && len == sizeof(__be32)) {
442+
pr_warn("invalid reg property size in '%s' - firmware out-of-date?\n",
443+
uname);
444+
actual_size_cells = 1;
445+
} else {
446+
actual_size_cells = dt_root_size_cells;
447+
}
413448

414-
if (len != dt_root_size_cells * sizeof(__be32)) {
449+
if (len != actual_size_cells * sizeof(__be32)) {
415450
pr_err("invalid size property in '%s' node.\n", uname);
416451
return -EINVAL;
417452
}
418-
size = dt_mem_next_cell(dt_root_size_cells, &prop);
453+
size = dt_mem_next_cell(actual_size_cells, &prop);
419454

420455
prop = of_get_flat_dt_prop(node, "alignment", &len);
421456
if (prop) {

0 commit comments

Comments
 (0)