1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright © 2022 Rafał Miłecki <rafal@milecki.pl>
6 #include <linux/module.h>
7 #include <linux/kernel.h>
8 #include <linux/slab.h>
9 #include <linux/mtd/mtd.h>
10 #include <linux/mtd/partitions.h>
12 #define BRCM_U_BOOT_MAX_OFFSET 0x200000
13 #define BRCM_U_BOOT_STEP 0x1000
15 #define BRCM_U_BOOT_MAX_PARTS 2
17 #define BRCM_U_BOOT_MAGIC 0x75456e76 /* uEnv */
19 struct brcm_u_boot_header
{
24 static const char *names
[BRCM_U_BOOT_MAX_PARTS
] = {
29 static int brcm_u_boot_parse(struct mtd_info
*mtd
,
30 const struct mtd_partition
**pparts
,
31 struct mtd_part_parser_data
*data
)
33 struct brcm_u_boot_header header
;
34 struct mtd_partition
*parts
;
40 parts
= kcalloc(BRCM_U_BOOT_MAX_PARTS
, sizeof(*parts
), GFP_KERNEL
);
45 offset
< min_t(size_t, mtd
->size
, BRCM_U_BOOT_MAX_OFFSET
);
46 offset
+= BRCM_U_BOOT_STEP
) {
47 err
= mtd_read(mtd
, offset
, sizeof(header
), &bytes_read
, (uint8_t *)&header
);
48 if (err
&& !mtd_is_bitflip(err
)) {
49 pr_err("Failed to read from %s at 0x%zx: %d\n", mtd
->name
, offset
, err
);
53 if (le32_to_cpu(header
.magic
) != BRCM_U_BOOT_MAGIC
)
56 parts
[i
].name
= names
[i
];
57 parts
[i
].offset
= offset
;
58 parts
[i
].size
= sizeof(header
) + le32_to_cpu(header
.length
);
60 pr_info("offset:0x%zx magic:0x%08x BINGO\n", offset
, header
.magic
);
62 if (i
== BRCM_U_BOOT_MAX_PARTS
)
71 static const struct of_device_id brcm_u_boot_of_match_table
[] = {
72 { .compatible
= "brcm,u-boot" },
75 MODULE_DEVICE_TABLE(of
, brcm_u_boot_of_match_table
);
77 static struct mtd_part_parser brcm_u_boot_mtd_parser
= {
78 .parse_fn
= brcm_u_boot_parse
,
79 .name
= "brcm_u-boot",
80 .of_match_table
= brcm_u_boot_of_match_table
,
82 module_mtd_part_parser(brcm_u_boot_mtd_parser
);
84 MODULE_DESCRIPTION("Broadcom's U-Boot partition parser");
85 MODULE_LICENSE("GPL");