linux/drivers/mtd/ar7part.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright © 2007 Eugene Konev <ejka@openwrt.org>
   4 *
   5 * TI AR7 flash partition table.
   6 * Based on ar7 map by Felix Fietkau <nbd@openwrt.org>
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/slab.h>
  11
  12#include <linux/mtd/mtd.h>
  13#include <linux/mtd/partitions.h>
  14#include <linux/memblock.h>
  15#include <linux/module.h>
  16
  17#include <uapi/linux/magic.h>
  18
  19#define AR7_PARTS       4
  20#define ROOT_OFFSET     0xe0000
  21
  22#define LOADER_MAGIC1   le32_to_cpu(0xfeedfa42)
  23#define LOADER_MAGIC2   le32_to_cpu(0xfeed1281)
  24
  25struct ar7_bin_rec {
  26        unsigned int checksum;
  27        unsigned int length;
  28        unsigned int address;
  29};
  30
  31static int create_mtd_partitions(struct mtd_info *master,
  32                                 const struct mtd_partition **pparts,
  33                                 struct mtd_part_parser_data *data)
  34{
  35        struct ar7_bin_rec header;
  36        unsigned int offset;
  37        size_t len;
  38        unsigned int pre_size = master->erasesize, post_size = 0;
  39        unsigned int root_offset = ROOT_OFFSET;
  40
  41        int retries = 10;
  42        struct mtd_partition *ar7_parts;
  43
  44        ar7_parts = kcalloc(AR7_PARTS, sizeof(*ar7_parts), GFP_KERNEL);
  45        if (!ar7_parts)
  46                return -ENOMEM;
  47        ar7_parts[0].name = "loader";
  48        ar7_parts[0].offset = 0;
  49        ar7_parts[0].size = master->erasesize;
  50        ar7_parts[0].mask_flags = MTD_WRITEABLE;
  51
  52        ar7_parts[1].name = "config";
  53        ar7_parts[1].offset = 0;
  54        ar7_parts[1].size = master->erasesize;
  55        ar7_parts[1].mask_flags = 0;
  56
  57        do { /* Try 10 blocks starting from master->erasesize */
  58                offset = pre_size;
  59                mtd_read(master, offset, sizeof(header), &len,
  60                         (uint8_t *)&header);
  61                if (!strncmp((char *)&header, "TIENV0.8", 8))
  62                        ar7_parts[1].offset = pre_size;
  63                if (header.checksum == LOADER_MAGIC1)
  64                        break;
  65                if (header.checksum == LOADER_MAGIC2)
  66                        break;
  67                pre_size += master->erasesize;
  68        } while (retries--);
  69
  70        pre_size = offset;
  71
  72        if (!ar7_parts[1].offset) {
  73                ar7_parts[1].offset = master->size - master->erasesize;
  74                post_size = master->erasesize;
  75        }
  76
  77        switch (header.checksum) {
  78        case LOADER_MAGIC1:
  79                while (header.length) {
  80                        offset += sizeof(header) + header.length;
  81                        mtd_read(master, offset, sizeof(header), &len,
  82                                 (uint8_t *)&header);
  83                }
  84                root_offset = offset + sizeof(header) + 4;
  85                break;
  86        case LOADER_MAGIC2:
  87                while (header.length) {
  88                        offset += sizeof(header) + header.length;
  89                        mtd_read(master, offset, sizeof(header), &len,
  90                                 (uint8_t *)&header);
  91                }
  92                root_offset = offset + sizeof(header) + 4 + 0xff;
  93                root_offset &= ~(uint32_t)0xff;
  94                break;
  95        default:
  96                printk(KERN_WARNING "Unknown magic: %08x\n", header.checksum);
  97                break;
  98        }
  99
 100        mtd_read(master, root_offset, sizeof(header), &len, (u8 *)&header);
 101        if (header.checksum != SQUASHFS_MAGIC) {
 102                root_offset += master->erasesize - 1;
 103                root_offset &= ~(master->erasesize - 1);
 104        }
 105
 106        ar7_parts[2].name = "linux";
 107        ar7_parts[2].offset = pre_size;
 108        ar7_parts[2].size = master->size - pre_size - post_size;
 109        ar7_parts[2].mask_flags = 0;
 110
 111        ar7_parts[3].name = "rootfs";
 112        ar7_parts[3].offset = root_offset;
 113        ar7_parts[3].size = master->size - root_offset - post_size;
 114        ar7_parts[3].mask_flags = 0;
 115
 116        *pparts = ar7_parts;
 117        return AR7_PARTS;
 118}
 119
 120static struct mtd_part_parser ar7_parser = {
 121        .parse_fn = create_mtd_partitions,
 122        .name = "ar7part",
 123};
 124module_mtd_part_parser(ar7_parser);
 125
 126MODULE_LICENSE("GPL");
 127MODULE_AUTHOR(  "Felix Fietkau <nbd@openwrt.org>, "
 128                "Eugene Konev <ejka@openwrt.org>");
 129MODULE_DESCRIPTION("MTD partitioning for TI AR7");
 130