2 * AudioCodes AC49x PSPBoot-based flash partition table
3 * Copyright 2012 Daniel Golle <daniel.golle@gmail.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <linux/kernel.h>
22 #include <linux/slab.h>
24 #include <linux/mtd/mtd.h>
25 #include <linux/mtd/partitions.h>
26 #include <linux/bootmem.h>
27 #include <linux/magic.h>
28 #include <linux/module.h>
30 #include <asm/mach-ar7/prom.h>
32 #define AC49X_MAXENVPARTS 8
34 #define AC49X_PARTTYPE_LOADER 0
35 #define AC49X_PARTTYPE_BOOTENV 1
36 #define AC49X_PARTTYPE_LINUX 2
37 #define AC49X_PARTTYPE_ROOTFS 3
38 #define AC49X_PARTTYPE_UNKNOWN 4
39 #define AC49X_NUM_PARTTYPES 5
41 #define AC49X_FLASH_ADDRMASK 0x00FFFFFF
43 #define AC49X_LOADER_MAGIC 0x40809000
44 #define AC49X_LINUX_MAGIC 0x464c457f /* ELF */
45 #define AC49X_BOOTENV_MAGIC 0x4578614d /* MaxE */
47 #define ROOTFS_MIN_OFFSET 0xC0000
49 int parse_partvar(const unsigned char *partvar
, struct mtd_partition
*part
)
51 unsigned int partstart
, partend
;
54 pnum
= sscanf(partvar
, "0x%x,0x%x", &partstart
, &partend
);
58 part
->offset
= partstart
& AC49X_FLASH_ADDRMASK
;
59 part
->size
= partend
- partstart
;
64 int detect_parttype(struct mtd_info
*master
, struct mtd_partition part
)
72 mtd_read(master
, part
.offset
, sizeof(magic
), &len
,
75 if (len
!= sizeof(magic
))
79 case AC49X_LOADER_MAGIC
:
80 return AC49X_PARTTYPE_LOADER
;
81 case AC49X_LINUX_MAGIC
:
82 return AC49X_PARTTYPE_LINUX
;
85 case CRAMFS_MAGIC_WEND
:
86 return AC49X_PARTTYPE_ROOTFS
;
87 case AC49X_BOOTENV_MAGIC
:
88 return AC49X_PARTTYPE_BOOTENV
;
90 switch (magic
& 0xFF) {
91 case JFFS2_SUPER_MAGIC
:
92 return AC49X_PARTTYPE_ROOTFS
;
95 case JFFS2_SUPER_MAGIC
:
96 return AC49X_PARTTYPE_ROOTFS
;
98 return AC49X_PARTTYPE_UNKNOWN
;
102 const char *partnames
[] = {
110 void gen_partname(unsigned int type
,
111 unsigned int *typenumeration
,
112 struct mtd_partition
*part
)
114 char *s
= kzalloc(sizeof(char) * 8, GFP_KERNEL
);
116 (typenumeration
[type
])++;
117 if (typenumeration
[type
] == 1)
118 sprintf(s
, "%s", partnames
[type
]);
120 sprintf(s
, "%s%d", partnames
[type
], typenumeration
[type
]);
125 static int create_mtd_partitions(struct mtd_info
*master
,
126 const struct mtd_partition
**pparts
,
127 struct mtd_part_parser_data
*data
)
129 unsigned int envpartnum
= 0, linuxpartnum
= 0;
130 unsigned int typenumeration
[5] = { 0, 0, 0, 0, 0 };
131 unsigned char evn
[5];
132 const unsigned char *partvar
= NULL
;
134 struct mtd_partition
*ac49x_parts
;
136 ac49x_parts
= kzalloc(sizeof(*ac49x_parts
) * AC49X_MAXENVPARTS
,
143 for (envpartnum
= 0; envpartnum
< AC49X_MAXENVPARTS
; envpartnum
++) {
144 struct mtd_partition parsepart
;
145 unsigned int offset
, size
, type
;
147 sprintf(evn
, "mtd%d", envpartnum
);
148 partvar
= prom_getenv(evn
);
151 err
= parse_partvar(partvar
, &parsepart
);
154 offset
= parsepart
.offset
;
155 size
= parsepart
.size
;
156 type
= detect_parttype(master
, parsepart
);
157 gen_partname(type
, typenumeration
, &parsepart
);
159 if (type
== AC49X_PARTTYPE_LOADER
)
160 parsepart
.mask_flags
= MTD_WRITEABLE
;
162 parsepart
.mask_flags
= 0;
164 memcpy(&(ac49x_parts
[linuxpartnum
]), &parsepart
,
165 sizeof(struct mtd_partition
));
167 /* scan for contained rootfs */
168 if (type
== AC49X_PARTTYPE_LINUX
) {
169 parsepart
.offset
+= ROOTFS_MIN_OFFSET
&
170 ~(master
->erasesize
- 1);
171 parsepart
.size
-= ROOTFS_MIN_OFFSET
&
172 ~(master
->erasesize
- 1);
174 unsigned int size
, offset
;
175 size
= parsepart
.size
;
176 offset
= parsepart
.offset
;
178 type
= detect_parttype(master
, parsepart
);
179 if (type
== AC49X_PARTTYPE_ROOTFS
) {
180 gen_partname(type
, typenumeration
,
183 "%s %s: 0x%08x@0x%08x\n",
184 "detected sub-partition",
186 (unsigned int)parsepart
.size
,
187 (unsigned int)parsepart
.offset
);
189 memcpy(&(ac49x_parts
[linuxpartnum
]),
191 sizeof(struct mtd_partition
));
194 parsepart
.offset
+= master
->erasesize
;
195 parsepart
.size
-= master
->erasesize
;
196 } while (parsepart
.size
>= master
->erasesize
);
201 *pparts
= ac49x_parts
;
205 static struct mtd_part_parser ac49x_parser
= {
206 .owner
= THIS_MODULE
,
207 .parse_fn
= create_mtd_partitions
,
211 static int __init
ac49x_parser_init(void)
213 register_mtd_parser(&ac49x_parser
);
217 module_init(ac49x_parser_init
);
219 MODULE_LICENSE("GPL");
220 MODULE_AUTHOR("Daniel Golle <daniel.golle@gmail.com>");
221 MODULE_DESCRIPTION("MTD partitioning for AudioCodes AC49x");