11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*======================================================================
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    drivers/mtd/afs.c: ARM Flash Layout/Partitioning
497894cda5773e59bd13e87b72077751099419a9fThomas Gleixner
5a1452a3771c4eb85bd779790b040efdc36f4274eDavid Woodhouse    Copyright © 2000 ARM Limited
697894cda5773e59bd13e87b72077751099419a9fThomas Gleixner
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This program is free software; you can redistribute it and/or modify
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   it under the terms of the GNU General Public License as published by
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   the Free Software Foundation; either version 2 of the License, or
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   (at your option) any later version.
1197894cda5773e59bd13e87b72077751099419a9fThomas Gleixner
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This program is distributed in the hope that it will be useful,
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   but WITHOUT ANY WARRANTY; without even the implied warranty of
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   GNU General Public License for more details.
1697894cda5773e59bd13e87b72077751099419a9fThomas Gleixner
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   You should have received a copy of the GNU General Public License
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   along with this program; if not, write to the Free Software
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
2097894cda5773e59bd13e87b72077751099419a9fThomas Gleixner
2197894cda5773e59bd13e87b72077751099419a9fThomas Gleixner   This is access code for flashes using ARM's flash partitioning
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   standards.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds======================================================================*/
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/mtd.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/map.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mtd/partitions.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct footer_struct {
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 image_info_base;	/* Address of first word of ImageFooter  */
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 image_start;	/* Start of area reserved by this footer */
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 signature;		/* 'Magic' number proves it's a footer   */
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 type;		/* Area type: ARM Image, SIB, customer   */
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 checksum;		/* Just this structure                   */
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct image_info_struct {
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 bootFlags;		/* Boot flags, compression etc.          */
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 imageNumber;	/* Unique number, selects for boot etc.  */
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 loadAddress;	/* Address program should be loaded to   */
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 length;		/* Actual size of image                  */
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 address;		/* Image is executed from here           */
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char name[16];		/* Null terminated                       */
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 headerBase;		/* Flash Address of any stripped header  */
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 header_length;	/* Length of header in memory            */
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 headerType;		/* AIF, RLF, s-record etc.               */
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 checksum;		/* Image checksum (inc. this struct)     */
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 word_sum(void *words, int num)
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 *p = words;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 sum = 0;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (num--)
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sum += *p++;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sum;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsafs_read_footer(struct mtd_info *mtd, u_int *img_start, u_int *iis_start,
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u_int off, u_int mask)
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct footer_struct fs;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int ptr = off + mtd->erasesize - sizeof(fs);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t sz;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
78329ad399a9b3adf52c90637b21ca029fcf7f8795Artem Bityutskiy	ret = mtd_read(mtd, ptr, sizeof(fs), &sz, (u_char *)&fs);
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret >= 0 && sz != sizeof(fs))
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EINVAL;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0) {
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ptr, ret);
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = 1;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Does it contain the magic number?
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fs.signature != 0xa0ffff9f)
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Check the checksum.
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff)
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Don't touch the SIB.
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (fs.type == 2)
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*iis_start = fs.image_info_base & mask;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*img_start = fs.image_start & mask;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Check the image info base.  This can not
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * be located after the footer structure.
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*iis_start >= ptr)
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Check the start of this image.  The image
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * data can not be located after this block.
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*img_start > off)
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 0;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsafs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr)
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size_t sz;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret, i;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(iis, 0, sizeof(*iis));
135329ad399a9b3adf52c90637b21ca029fcf7f8795Artem Bityutskiy	ret = mtd_read(mtd, ptr, sizeof(*iis), &sz, (u_char *)iis);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sz != sizeof(*iis)) {
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EINVAL;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto failed;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = 0;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Validate the name - it must be NUL terminated.
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < sizeof(iis->name); i++)
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (iis->name[i] == '\0')
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i < sizeof(iis->name))
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = 1;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed:
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ptr, ret);
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16497894cda5773e59bd13e87b72077751099419a9fThomas Gleixnerstatic int parse_afs_partitions(struct mtd_info *mtd,
165c7975330154af17aecc167b33ca866b6b3d98918Dmitry Eremin-Solenikov				struct mtd_partition **pparts,
166c7975330154af17aecc167b33ca866b6b3d98918Dmitry Eremin-Solenikov				struct mtd_part_parser_data *data)
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct mtd_partition *parts;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u_int mask, off, idx, sz;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *str;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This is the address mask; we use this to mask off out of
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * range address bits.
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = mtd->size - 1;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * First, calculate the size of the array we need for the
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * partition information.  We include in this the size of
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * the strings.
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = off = sz = 0; off < mtd->size; off += mtd->erasesize) {
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct image_info_struct iis;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u_int iis_ptr, img_ptr;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret == 0)
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = afs_read_iis(mtd, &iis, iis_ptr);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret == 0)
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sz += sizeof(struct mtd_partition);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sz += strlen(iis.name) + 1;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		idx += 1;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sz)
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20895b93a0cd46682c6d9e8eea803fda510cb6b863aBurman Yan	parts = kzalloc(sz, GFP_KERNEL);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!parts)
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	str = (char *)(parts + idx);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Identify the partitions
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (idx = off = 0; off < mtd->size; off += mtd->erasesize) {
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct image_info_struct iis;
219747aead34de65c25765da79825ce2c08d8257b10Catalin Marinas		u_int iis_ptr, img_ptr;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Read the footer. */
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret == 0)
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Read the image info block */
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = afs_read_iis(mtd, &iis, iis_ptr);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret < 0)
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret == 0)
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strcpy(str, iis.name);
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		parts[idx].name		= str;
238747aead34de65c25765da79825ce2c08d8257b10Catalin Marinas		parts[idx].size		= (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		parts[idx].offset	= img_ptr;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		parts[idx].mask_flags	= 0;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2420ffd24fc7f82a0b594250e5f221340be4c322cdaRussell King		printk("  mtd%d: at 0x%08x, %5lluKiB, %8u, %s\n",
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			idx, img_ptr, parts[idx].size / 1024,
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			iis.imageNumber, str);
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		idx += 1;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		str = str + strlen(iis.name) + 1;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!idx) {
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(parts);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		parts = NULL;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*pparts = parts;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return idx ? idx : ret;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mtd_part_parser afs_parser = {
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner = THIS_MODULE,
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.parse_fn = parse_afs_partitions,
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name = "afs",
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init afs_parser_init(void)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2676e14a61d412eb87ef7bdcec8b08a95bead771a78Axel Lin	register_mtd_parser(&afs_parser);
2686e14a61d412eb87ef7bdcec8b08a95bead771a78Axel Lin	return 0;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit afs_parser_exit(void)
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	deregister_mtd_parser(&afs_parser);
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(afs_parser_init);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(afs_parser_exit);
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("ARM Ltd");
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("ARM Firmware Suite partition parser");
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
283