1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 299352afeSRafał Miłecki /* 399352afeSRafał Miłecki * Parser for TRX format partitions 499352afeSRafał Miłecki * 599352afeSRafał Miłecki * Copyright (C) 2012 - 2017 Rafał Miłecki <rafal@milecki.pl> 699352afeSRafał Miłecki */ 799352afeSRafał Miłecki 899352afeSRafał Miłecki #include <linux/module.h> 999352afeSRafał Miłecki #include <linux/slab.h> 1099352afeSRafał Miłecki #include <linux/mtd/mtd.h> 1199352afeSRafał Miłecki #include <linux/mtd/partitions.h> 1299352afeSRafał Miłecki 1399352afeSRafał Miłecki #define TRX_PARSER_MAX_PARTS 4 1499352afeSRafał Miłecki 1599352afeSRafał Miłecki /* Magics */ 1699352afeSRafał Miłecki #define TRX_MAGIC 0x30524448 1799352afeSRafał Miłecki #define UBI_EC_MAGIC 0x23494255 /* UBI# */ 1899352afeSRafał Miłecki 1999352afeSRafał Miłecki struct trx_header { 2099352afeSRafał Miłecki uint32_t magic; 2199352afeSRafał Miłecki uint32_t length; 2299352afeSRafał Miłecki uint32_t crc32; 2399352afeSRafał Miłecki uint16_t flags; 2499352afeSRafał Miłecki uint16_t version; 2599352afeSRafał Miłecki uint32_t offset[3]; 2699352afeSRafał Miłecki } __packed; 2799352afeSRafał Miłecki 2899352afeSRafał Miłecki static const char *parser_trx_data_part_name(struct mtd_info *master, 2999352afeSRafał Miłecki size_t offset) 3099352afeSRafał Miłecki { 3199352afeSRafał Miłecki uint32_t buf; 3299352afeSRafał Miłecki size_t bytes_read; 3399352afeSRafał Miłecki int err; 3499352afeSRafał Miłecki 3599352afeSRafał Miłecki err = mtd_read(master, offset, sizeof(buf), &bytes_read, 3699352afeSRafał Miłecki (uint8_t *)&buf); 3799352afeSRafał Miłecki if (err && !mtd_is_bitflip(err)) { 3858de51caSRafał Miłecki pr_err("mtd_read error while parsing (offset: 0x%zX): %d\n", 3999352afeSRafał Miłecki offset, err); 4099352afeSRafał Miłecki goto out_default; 4199352afeSRafał Miłecki } 4299352afeSRafał Miłecki 4399352afeSRafał Miłecki if (buf == UBI_EC_MAGIC) 4499352afeSRafał Miłecki return "ubi"; 4599352afeSRafał Miłecki 4699352afeSRafał Miłecki out_default: 4799352afeSRafał Miłecki return "rootfs"; 4899352afeSRafał Miłecki } 4999352afeSRafał Miłecki 5099352afeSRafał Miłecki static int parser_trx_parse(struct mtd_info *mtd, 5199352afeSRafał Miłecki const struct mtd_partition **pparts, 5299352afeSRafał Miłecki struct mtd_part_parser_data *data) 5399352afeSRafał Miłecki { 54*d7f7e04fSHauke Mehrtens struct device_node *np = mtd_get_of_node(mtd); 5599352afeSRafał Miłecki struct mtd_partition *parts; 5699352afeSRafał Miłecki struct mtd_partition *part; 5799352afeSRafał Miłecki struct trx_header trx; 5899352afeSRafał Miłecki size_t bytes_read; 5999352afeSRafał Miłecki uint8_t curr_part = 0, i = 0; 60*d7f7e04fSHauke Mehrtens uint32_t trx_magic = TRX_MAGIC; 6199352afeSRafał Miłecki int err; 6299352afeSRafał Miłecki 63*d7f7e04fSHauke Mehrtens /* Get different magic from device tree if specified */ 64*d7f7e04fSHauke Mehrtens err = of_property_read_u32(np, "brcm,trx-magic", &trx_magic); 65*d7f7e04fSHauke Mehrtens if (err != 0 && err != -EINVAL) 66*d7f7e04fSHauke Mehrtens pr_err("failed to parse \"brcm,trx-magic\" DT attribute, using default: %d\n", err); 67*d7f7e04fSHauke Mehrtens 686396bb22SKees Cook parts = kcalloc(TRX_PARSER_MAX_PARTS, sizeof(struct mtd_partition), 6999352afeSRafał Miłecki GFP_KERNEL); 7099352afeSRafał Miłecki if (!parts) 7199352afeSRafał Miłecki return -ENOMEM; 7299352afeSRafał Miłecki 7399352afeSRafał Miłecki err = mtd_read(mtd, 0, sizeof(trx), &bytes_read, (uint8_t *)&trx); 7499352afeSRafał Miłecki if (err) { 7599352afeSRafał Miłecki pr_err("MTD reading error: %d\n", err); 7699352afeSRafał Miłecki kfree(parts); 7799352afeSRafał Miłecki return err; 7899352afeSRafał Miłecki } 7999352afeSRafał Miłecki 80*d7f7e04fSHauke Mehrtens if (trx.magic != trx_magic) { 8199352afeSRafał Miłecki kfree(parts); 8299352afeSRafał Miłecki return -ENOENT; 8399352afeSRafał Miłecki } 8499352afeSRafał Miłecki 8599352afeSRafał Miłecki /* We have LZMA loader if there is address in offset[2] */ 8699352afeSRafał Miłecki if (trx.offset[2]) { 8799352afeSRafał Miłecki part = &parts[curr_part++]; 8899352afeSRafał Miłecki part->name = "loader"; 8999352afeSRafał Miłecki part->offset = trx.offset[i]; 9099352afeSRafał Miłecki i++; 9199352afeSRafał Miłecki } 9299352afeSRafał Miłecki 9399352afeSRafał Miłecki if (trx.offset[i]) { 9499352afeSRafał Miłecki part = &parts[curr_part++]; 9599352afeSRafał Miłecki part->name = "linux"; 9699352afeSRafał Miłecki part->offset = trx.offset[i]; 9799352afeSRafał Miłecki i++; 9899352afeSRafał Miłecki } 9999352afeSRafał Miłecki 10099352afeSRafał Miłecki if (trx.offset[i]) { 10199352afeSRafał Miłecki part = &parts[curr_part++]; 10299352afeSRafał Miłecki part->name = parser_trx_data_part_name(mtd, trx.offset[i]); 10399352afeSRafał Miłecki part->offset = trx.offset[i]; 10499352afeSRafał Miłecki i++; 10599352afeSRafał Miłecki } 10699352afeSRafał Miłecki 10799352afeSRafał Miłecki /* 10899352afeSRafał Miłecki * Assume that every partition ends at the beginning of the one it is 10999352afeSRafał Miłecki * followed by. 11099352afeSRafał Miłecki */ 11199352afeSRafał Miłecki for (i = 0; i < curr_part; i++) { 11299352afeSRafał Miłecki u64 next_part_offset = (i < curr_part - 1) ? 11399352afeSRafał Miłecki parts[i + 1].offset : mtd->size; 11499352afeSRafał Miłecki 11599352afeSRafał Miłecki parts[i].size = next_part_offset - parts[i].offset; 11699352afeSRafał Miłecki } 11799352afeSRafał Miłecki 11899352afeSRafał Miłecki *pparts = parts; 11999352afeSRafał Miłecki return i; 12099352afeSRafał Miłecki }; 12199352afeSRafał Miłecki 12298534a58SRafał Miłecki static const struct of_device_id mtd_parser_trx_of_match_table[] = { 12398534a58SRafał Miłecki { .compatible = "brcm,trx" }, 12498534a58SRafał Miłecki {}, 12598534a58SRafał Miłecki }; 12698534a58SRafał Miłecki MODULE_DEVICE_TABLE(of, mtd_parser_trx_of_match_table); 12798534a58SRafał Miłecki 12899352afeSRafał Miłecki static struct mtd_part_parser mtd_parser_trx = { 12999352afeSRafał Miłecki .parse_fn = parser_trx_parse, 13099352afeSRafał Miłecki .name = "trx", 13198534a58SRafał Miłecki .of_match_table = mtd_parser_trx_of_match_table, 13299352afeSRafał Miłecki }; 13399352afeSRafał Miłecki module_mtd_part_parser(mtd_parser_trx); 13499352afeSRafał Miłecki 13599352afeSRafał Miłecki MODULE_LICENSE("GPL v2"); 13699352afeSRafał Miłecki MODULE_DESCRIPTION("Parser for TRX format partitions"); 137