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
parser_trx_data_part_name(struct mtd_info * master,size_t offset)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
parser_trx_parse(struct mtd_info * mtd,const struct mtd_partition ** pparts,struct mtd_part_parser_data * data)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