^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * BCM47XX MTD partitioning
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright © 2012 Rafał Miłecki <zajec5@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/bcm47xx_nvram.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/mtd/mtd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/mtd/partitions.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <uapi/linux/magic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * NAND flash on Netgear R6250 was verified to contain 15 partitions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * This will result in allocating too big array for some old devices, but the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * memory will be freed soon anyway (see mtd_device_parse_register).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define BCM47XXPART_MAX_PARTS 20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * Amount of bytes we read when analyzing each block of flash memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * Set it big enough to allow detecting partition and reading important data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define BCM47XXPART_BYTES_TO_READ 0x4e8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) /* Magics */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define BOARD_DATA_MAGIC 0x5246504D /* MPFR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define BOARD_DATA_MAGIC2 0xBD0D0BBD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define CFE_MAGIC 0x43464531 /* 1EFC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define FACTORY_MAGIC 0x59544346 /* FCTY */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define NVRAM_HEADER 0x48534C46 /* FLSH */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define POT_MAGIC1 0x54544f50 /* POTT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define POT_MAGIC2 0x504f /* OP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define ML_MAGIC1 0x39685a42
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define ML_MAGIC2 0x26594131
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define TRX_MAGIC 0x30524448
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define SHSQ_MAGIC 0x71736873 /* shsq (weird ZTE H218N endianness) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static const char * const trx_types[] = { "trx", NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct trx_header {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) uint32_t magic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) uint32_t length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) uint32_t crc32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) uint16_t flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) uint16_t version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) uint32_t offset[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static void bcm47xxpart_add_part(struct mtd_partition *part, const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) u64 offset, uint32_t mask_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) part->name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) part->offset = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) part->mask_flags = mask_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * bcm47xxpart_bootpartition - gets index of TRX partition used by bootloader
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * Some devices may have more than one TRX partition. In such case one of them
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * is the main one and another a failsafe one. Bootloader may fallback to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * failsafe firmware if it detects corruption of the main image.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * This function provides info about currently used TRX partition. It's the one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * containing kernel started by the bootloader.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static int bcm47xxpart_bootpartition(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) char buf[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) int bootpartition;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /* Check CFE environment variable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (bcm47xx_nvram_getenv("bootpartition", buf, sizeof(buf)) > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (!kstrtoint(buf, 0, &bootpartition))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return bootpartition;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static int bcm47xxpart_parse(struct mtd_info *master,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) const struct mtd_partition **pparts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct mtd_part_parser_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct mtd_partition *parts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) uint8_t i, curr_part = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) uint32_t *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) size_t bytes_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) uint32_t offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) uint32_t blocksize = master->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) int trx_parts[2]; /* Array with indexes of TRX partitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) int trx_num = 0; /* Number of found TRX partitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * partitions were aligned to at least 0x1000 anyway.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (blocksize < 0x1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) blocksize = 0x1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /* Alloc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) parts = kcalloc(BCM47XXPART_MAX_PARTS, sizeof(struct mtd_partition),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (!parts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) buf = kzalloc(BCM47XXPART_BYTES_TO_READ, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (!buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) kfree(parts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /* Parse block by block looking for magics */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) for (offset = 0; offset <= master->size - blocksize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) offset += blocksize) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /* Nothing more in higher memory on BCM47XX (MIPS) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (IS_ENABLED(CONFIG_BCM47XX) && offset >= 0x2000000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (curr_part >= BCM47XXPART_MAX_PARTS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) pr_warn("Reached maximum number of partitions, scanning stopped!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) /* Read beginning of the block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) &bytes_read, (uint8_t *)buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (err && !mtd_is_bitflip(err)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) offset, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /* Magic or small NVRAM at 0x400 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if ((buf[0x4e0 / 4] == CFE_MAGIC && buf[0x4e4 / 4] == CFE_MAGIC) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) (buf[0x400 / 4] == NVRAM_HEADER)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) bcm47xxpart_add_part(&parts[curr_part++], "boot",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) offset, MTD_WRITEABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * board_data starts with board_id which differs across boards,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * but we can use 'MPFR' (hopefully) magic at 0x100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (buf[0x100 / 4] == BOARD_DATA_MAGIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) bcm47xxpart_add_part(&parts[curr_part++], "board_data",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) offset, MTD_WRITEABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /* Found on Huawei E970 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (buf[0x000 / 4] == FACTORY_MAGIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) bcm47xxpart_add_part(&parts[curr_part++], "factory",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) offset, MTD_WRITEABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) /* POT(TOP) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) if (buf[0x000 / 4] == POT_MAGIC1 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) (buf[0x004 / 4] & 0xFFFF) == POT_MAGIC2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) bcm47xxpart_add_part(&parts[curr_part++], "POT", offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) MTD_WRITEABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) /* ML */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (buf[0x010 / 4] == ML_MAGIC1 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) buf[0x014 / 4] == ML_MAGIC2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) bcm47xxpart_add_part(&parts[curr_part++], "ML", offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) MTD_WRITEABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /* TRX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) if (buf[0x000 / 4] == TRX_MAGIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct trx_header *trx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) uint32_t last_subpart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) uint32_t trx_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (trx_num >= ARRAY_SIZE(trx_parts))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) pr_warn("No enough space to store another TRX found at 0x%X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) trx_parts[trx_num++] = curr_part;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) bcm47xxpart_add_part(&parts[curr_part++], "firmware",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) offset, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * Try to find TRX size. The "length" field isn't fully
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * reliable as it could be decreased to make CRC32 cover
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * only part of TRX data. It's commonly used as checksum
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * can't cover e.g. ever-changing rootfs partition.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) * Use offsets as helpers for assuming min TRX size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) trx = (struct trx_header *)buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) last_subpart = max3(trx->offset[0], trx->offset[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) trx->offset[2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) trx_size = max(trx->length, last_subpart + blocksize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * Skip the TRX data. Decrease offset by block size as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) * the next loop iteration will increase it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) offset += roundup(trx_size, blocksize) - blocksize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /* Squashfs on devices not using TRX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (le32_to_cpu(buf[0x000 / 4]) == SQUASHFS_MAGIC ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) buf[0x000 / 4] == SHSQ_MAGIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) offset, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * New (ARM?) devices may have NVRAM in some middle block. Last
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * block will be checked later, so skip it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (offset != master->size - blocksize &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) buf[0x000 / 4] == NVRAM_HEADER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) bcm47xxpart_add_part(&parts[curr_part++], "nvram",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) offset, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) /* Read middle of the block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) (uint8_t *)buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (err && !mtd_is_bitflip(err)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) offset, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) /* Some devices (ex. WNDR3700v3) don't have a standard 'MPFR' */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (buf[0x000 / 4] == BOARD_DATA_MAGIC2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) bcm47xxpart_add_part(&parts[curr_part++], "board_data",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) offset, MTD_WRITEABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) /* Look for NVRAM at the end of the last block. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) for (i = 0; i < ARRAY_SIZE(possible_nvram_sizes); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (curr_part >= BCM47XXPART_MAX_PARTS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) pr_warn("Reached maximum number of partitions, scanning stopped!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) offset = master->size - possible_nvram_sizes[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) err = mtd_read(master, offset, 0x4, &bytes_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) (uint8_t *)buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (err && !mtd_is_bitflip(err)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) pr_err("mtd_read error while reading (offset 0x%X): %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) offset, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) /* Standard NVRAM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) if (buf[0] == NVRAM_HEADER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) bcm47xxpart_add_part(&parts[curr_part++], "nvram",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) master->size - blocksize, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) * Assume that partitions end at the beginning of the one they are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * followed by.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) for (i = 0; i < curr_part; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) u64 next_part_offset = (i < curr_part - 1) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) parts[i + 1].offset : master->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) parts[i].size = next_part_offset - parts[i].offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /* If there was TRX parse it now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) for (i = 0; i < trx_num; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) struct mtd_partition *trx = &parts[trx_parts[i]];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (i == bcm47xxpart_bootpartition())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) trx->types = trx_types;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) trx->name = "failsafe";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) *pparts = parts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) return curr_part;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) static const struct of_device_id bcm47xxpart_of_match_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) { .compatible = "brcm,bcm947xx-cfe-partitions" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) MODULE_DEVICE_TABLE(of, bcm47xxpart_of_match_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) static struct mtd_part_parser bcm47xxpart_mtd_parser = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) .parse_fn = bcm47xxpart_parse,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) .name = "bcm47xxpart",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) .of_match_table = bcm47xxpart_of_match_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) module_mtd_part_parser(bcm47xxpart_mtd_parser);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) MODULE_DESCRIPTION("MTD partitioning for BCM47XX flash memories");