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 25 struct ar7_bin_rec { 26 unsigned int checksum; 27 unsigned int length; 28 unsigned int address; 29 }; 30 31 static 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 120 static struct mtd_part_parser ar7_parser = { 121 .parse_fn = create_mtd_partitions, 122 .name = "ar7part", 123 }; 124 module_mtd_part_parser(ar7_parser); 125 126 MODULE_LICENSE("GPL"); 127 MODULE_AUTHOR( "Felix Fietkau <nbd@openwrt.org>, " 128 "Eugene Konev <ejka@openwrt.org>"); 129 MODULE_DESCRIPTION("MTD partitioning for TI AR7"); 130