brcm_u-boot.c 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright © 2022 Rafał Miłecki <[email protected]>
  4. */
  5. #include <linux/module.h>
  6. #include <linux/kernel.h>
  7. #include <linux/slab.h>
  8. #include <linux/mtd/mtd.h>
  9. #include <linux/mtd/partitions.h>
  10. #define BRCM_U_BOOT_MAX_OFFSET 0x200000
  11. #define BRCM_U_BOOT_STEP 0x1000
  12. #define BRCM_U_BOOT_MAX_PARTS 2
  13. #define BRCM_U_BOOT_MAGIC 0x75456e76 /* uEnv */
  14. struct brcm_u_boot_header {
  15. __le32 magic;
  16. __le32 length;
  17. } __packed;
  18. static const char *names[BRCM_U_BOOT_MAX_PARTS] = {
  19. "u-boot-env",
  20. "u-boot-env-backup",
  21. };
  22. static int brcm_u_boot_parse(struct mtd_info *mtd,
  23. const struct mtd_partition **pparts,
  24. struct mtd_part_parser_data *data)
  25. {
  26. struct brcm_u_boot_header header;
  27. struct mtd_partition *parts;
  28. size_t bytes_read;
  29. size_t offset;
  30. int err;
  31. int i = 0;
  32. parts = kcalloc(BRCM_U_BOOT_MAX_PARTS, sizeof(*parts), GFP_KERNEL);
  33. if (!parts)
  34. return -ENOMEM;
  35. for (offset = 0;
  36. offset < min_t(size_t, mtd->size, BRCM_U_BOOT_MAX_OFFSET);
  37. offset += BRCM_U_BOOT_STEP) {
  38. err = mtd_read(mtd, offset, sizeof(header), &bytes_read, (uint8_t *)&header);
  39. if (err && !mtd_is_bitflip(err)) {
  40. pr_err("Failed to read from %s at 0x%zx: %d\n", mtd->name, offset, err);
  41. continue;
  42. }
  43. if (le32_to_cpu(header.magic) != BRCM_U_BOOT_MAGIC)
  44. continue;
  45. parts[i].name = names[i];
  46. parts[i].offset = offset;
  47. parts[i].size = sizeof(header) + le32_to_cpu(header.length);
  48. i++;
  49. pr_info("offset:0x%zx magic:0x%08x BINGO\n", offset, header.magic);
  50. if (i == BRCM_U_BOOT_MAX_PARTS)
  51. break;
  52. }
  53. *pparts = parts;
  54. return i;
  55. };
  56. static const struct of_device_id brcm_u_boot_of_match_table[] = {
  57. { .compatible = "brcm,u-boot" },
  58. {},
  59. };
  60. MODULE_DEVICE_TABLE(of, brcm_u_boot_of_match_table);
  61. static struct mtd_part_parser brcm_u_boot_mtd_parser = {
  62. .parse_fn = brcm_u_boot_parse,
  63. .name = "brcm_u-boot",
  64. .of_match_table = brcm_u_boot_of_match_table,
  65. };
  66. module_mtd_part_parser(brcm_u_boot_mtd_parser);
  67. MODULE_LICENSE("GPL");