1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright © 2022 Rafał Miłecki <rafal@milecki.pl> |
4 | */ |
5 | |
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> |
11 | |
12 | #define BRCM_U_BOOT_MAX_OFFSET 0x200000 |
13 | #define BRCM_U_BOOT_STEP 0x1000 |
14 | |
15 | #define BRCM_U_BOOT_MAX_PARTS 2 |
16 | |
17 | #define BRCM_U_BOOT_MAGIC 0x75456e76 /* uEnv */ |
18 | |
19 | struct { |
20 | __le32 ; |
21 | __le32 ; |
22 | } __packed; |
23 | |
24 | static const char *names[BRCM_U_BOOT_MAX_PARTS] = { |
25 | "u-boot-env" , |
26 | "u-boot-env-backup" , |
27 | }; |
28 | |
29 | static int brcm_u_boot_parse(struct mtd_info *mtd, |
30 | const struct mtd_partition **pparts, |
31 | struct mtd_part_parser_data *data) |
32 | { |
33 | struct brcm_u_boot_header ; |
34 | struct mtd_partition *parts; |
35 | size_t bytes_read; |
36 | size_t offset; |
37 | int err; |
38 | int i = 0; |
39 | |
40 | parts = kcalloc(BRCM_U_BOOT_MAX_PARTS, size: sizeof(*parts), GFP_KERNEL); |
41 | if (!parts) |
42 | return -ENOMEM; |
43 | |
44 | for (offset = 0; |
45 | offset < min_t(size_t, mtd->size, BRCM_U_BOOT_MAX_OFFSET); |
46 | offset += BRCM_U_BOOT_STEP) { |
47 | err = mtd_read(mtd, from: offset, len: sizeof(header), retlen: &bytes_read, buf: (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); |
50 | continue; |
51 | } |
52 | |
53 | if (le32_to_cpu(header.magic) != BRCM_U_BOOT_MAGIC) |
54 | continue; |
55 | |
56 | parts[i].name = names[i]; |
57 | parts[i].offset = offset; |
58 | parts[i].size = sizeof(header) + le32_to_cpu(header.length); |
59 | i++; |
60 | pr_info("offset:0x%zx magic:0x%08x BINGO\n" , offset, header.magic); |
61 | |
62 | if (i == BRCM_U_BOOT_MAX_PARTS) |
63 | break; |
64 | } |
65 | |
66 | *pparts = parts; |
67 | |
68 | return i; |
69 | }; |
70 | |
71 | static const struct of_device_id brcm_u_boot_of_match_table[] = { |
72 | { .compatible = "brcm,u-boot" }, |
73 | {}, |
74 | }; |
75 | MODULE_DEVICE_TABLE(of, brcm_u_boot_of_match_table); |
76 | |
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, |
81 | }; |
82 | module_mtd_part_parser(brcm_u_boot_mtd_parser); |
83 | |
84 | MODULE_LICENSE("GPL" ); |
85 | |