aboutsummaryrefslogtreecommitdiff
path: root/common/cmd_mtdparts.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/cmd_mtdparts.c')
-rw-r--r--common/cmd_mtdparts.c388
1 files changed, 367 insertions, 21 deletions
diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 22688293ae..add0585037 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -99,6 +99,7 @@
#if defined(CONFIG_CMD_NAND)
#include <linux/mtd/nand.h>
#include <nand.h>
+#include <mtd/nand/rda_nand.h>
#endif
#if defined(CONFIG_CMD_ONENAND)
@@ -325,7 +326,7 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
{
struct mtd_info *mtd = NULL;
int i, j;
- ulong start;
+ u64 start;
if (get_mtd_info(id->type, id->num, &mtd))
return 1;
@@ -337,7 +338,7 @@ static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
* Only one eraseregion (NAND, OneNAND or uniform NOR),
* checking for alignment is easy here
*/
- if ((unsigned long)part->offset % mtd->erasesize) {
+ if (part->offset % (u64)mtd->erasesize) {
printf("%s%d: partition (%s) start offset"
"alignment incorrect\n",
MTD_DEV_TYPE(id->type), id->num, part->name);
@@ -412,19 +413,20 @@ static int part_validate(struct mtdids *id, struct part_info *part)
part->size = id->size - part->offset;
if (part->offset > id->size) {
- printf("%s: offset %08x beyond flash size %08x\n",
+ printf("%s: offset %llx beyond flash size 0x%llx\n",
id->mtd_id, part->offset, id->size);
return 1;
}
- if ((part->offset + part->size) <= part->offset) {
+ if (((u64)part->offset + (u64)part->size) <= (u64)part->offset) {
printf("%s%d: partition (%s) size too big\n",
MTD_DEV_TYPE(id->type), id->num, part->name);
return 1;
}
if (part->offset + part->size > id->size) {
- printf("%s: partitioning exceeds flash size\n", id->mtd_id);
+ printf("%s: partitioning exceeds flash size %llx, part %llx+%llx\n",
+ id->mtd_id, id->size, part->offset, part->size);
return 1;
}
@@ -462,7 +464,7 @@ static int part_del(struct mtd_device *dev, struct part_info *part)
if (curr_pi == part) {
printf("current partition deleted, resetting current to 0\n");
current_mtd_partnum = 0;
- } else if (part->offset <= curr_pi->offset) {
+ } else if (part->offset <= (u64)curr_pi->offset) {
current_mtd_partnum--;
}
current_save_needed = 1;
@@ -595,8 +597,7 @@ static int part_add(struct mtd_device *dev, struct part_info *part)
static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart)
{
struct part_info *part;
- unsigned long size;
- unsigned long offset;
+ u64 size, offset;
const char *name;
int name_len;
unsigned int mask_flags;
@@ -615,7 +616,7 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
} else {
size = memsize_parse(p, &p);
if (size < MIN_PART_SIZE) {
- printf("partition size too small (%lx)\n", size);
+ printf("partition size too small (%llx)\n", size);
return 1;
}
}
@@ -680,6 +681,8 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
part->offset = offset;
part->mask_flags = mask_flags;
part->name = (char *)(part + 1);
+ /*we set the mtdpart is dirty and force erase before program if needed*/
+ part->dirty = 1;
if (name) {
/* copy user provided name */
@@ -687,14 +690,14 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
part->auto_name = 0;
} else {
/* auto generated name in form of size@offset */
- sprintf(part->name, "0x%08lx@0x%08lx", size, offset);
+ sprintf(part->name, "0x%llx@0x%llx", size, offset);
part->auto_name = 1;
}
part->name[name_len - 1] = '\0';
INIT_LIST_HEAD(&part->link);
- debug("+ partition: name %-22s size 0x%08x offset 0x%08x mask flags %d\n",
+ debug("+ partition: name %-22s size 0x%llx offset 0x%llx mask flags %d\n",
part->name, part->size,
part->offset, part->mask_flags);
@@ -710,7 +713,7 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
* @param size a pointer to the size of the mtd device (output)
* @return 0 if device is valid, 1 otherwise
*/
-int mtd_device_validate(u8 type, u8 num, u32 *size)
+int mtd_device_validate(u8 type, u8 num, u64 *size)
{
struct mtd_info *mtd = NULL;
@@ -843,7 +846,7 @@ static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_
LIST_HEAD(tmp_list);
struct list_head *entry, *n;
u16 num_parts;
- u32 offset;
+ u64 offset;
int err = 1;
debug("===device_parse===\n");
@@ -1087,7 +1090,8 @@ static int generate_mtdparts(char *buf, u32 buflen)
struct part_info *part, *prev_part;
char *p = buf;
char tmpbuf[32];
- u32 size, offset, len, part_cnt;
+ u64 size, offset;
+ u32 len, part_cnt;
u32 maxlen = buflen - 1;
debug("--- generate_mtdparts ---\n");
@@ -1274,7 +1278,7 @@ static void print_partition_table(void)
part = list_entry(pentry, struct part_info, link);
net_size = net_part_size(mtd, part);
size_note = part->size == net_size ? " " : " (!)";
- printf("%2d: %-20s0x%08x\t0x%08x%s\t0x%08x\t%d\n",
+ printf("%2d: %-20s0x%llx\t0x%08x%s\t0x%llx\t%d\n",
part_num, part->name, part->size,
net_size, size_note, part->offset,
part->mask_flags);
@@ -1286,7 +1290,7 @@ static void print_partition_table(void)
list_for_each(pentry, &dev->parts) {
part = list_entry(pentry, struct part_info, link);
- printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
+ printf("%2d: %-20s0x%llx\t0x%llx\t%d\n",
part_num, part->name, part->size,
part->offset, part->mask_flags);
#endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
@@ -1299,6 +1303,41 @@ static void print_partition_table(void)
}
/**
+ * Given nand partition number find the partition info and
+ * corresponding nand device
+ *
+ * @param part_num nand partition number
+ * @param part pointer to requested partition (output)
+ * @param nand pointer to the nand device (output)
+ * @return 0 on success, -1 otherwise
+ */
+int find_nand_part_info(int part_num, struct part_info **part,
+ struct mtd_info **nand)
+{
+ struct list_head *dentry;
+ struct mtd_device *dev;
+
+ if (list_empty(&devices)) {
+ printf("no partitions defined\n");
+ return -1;
+ }
+
+ list_for_each(dentry, &devices) {
+ dev = list_entry(dentry, struct mtd_device, link);
+ /* list partitions for given device */
+
+ if (dev->id->type == MTD_DEV_TYPE_NAND) {
+ *part = mtd_part_info(dev, part_num);
+ if (!part)
+ return -1;
+ *nand = &nand_info[dev->id->num];
+ return 0;
+ }
+ }
+
+ return -1;
+}
+/**
* Format and print out a partition list for each device from global device
* list.
*/
@@ -1313,7 +1352,7 @@ static void list_partitions(void)
if (current_mtd_dev) {
part = mtd_part_info(current_mtd_dev, current_mtd_partnum);
if (part) {
- printf("\nactive partition: %s%d,%d - (%s) 0x%08x @ 0x%08x\n",
+ printf("\nactive partition: %s%d,%d - (%s) 0x%llx @ 0x%llx\n",
MTD_DEV_TYPE(current_mtd_dev->id->type),
current_mtd_dev->id->num, current_mtd_partnum,
part->name, part->size, part->offset);
@@ -1413,7 +1452,7 @@ static int delete_partition(const char *id)
if (find_dev_and_part(id, &dev, &pnum, &part) == 0) {
- debug("delete_partition: device = %s%d, partition %d = (%s) 0x%08x@0x%08x\n",
+ debug("delete_partition: device = %s%d, partition %d = (%s) 0x%llx@0x%llx\n",
MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum,
part->name, part->size, part->offset);
@@ -1502,7 +1541,7 @@ static int spread_partitions(void)
part = list_entry(pentry, struct part_info, link);
debug("spread_partitions: device = %s%d, partition %d ="
- " (%s) 0x%08x@0x%08x\n",
+ " (%s) 0x%08x@0x%llx\n",
MTD_DEV_TYPE(dev->id->type), dev->id->num,
part_num, part->name, part->size,
part->offset);
@@ -1599,7 +1638,7 @@ static int parse_mtdids(const char *const ids)
struct list_head *entry, *n;
struct mtdids *id_tmp;
u8 type, num;
- u32 size;
+ u64 size;
int ret = 1;
debug("\n---parse_mtdids---\nmtdids = %s\n\n", ids);
@@ -1673,7 +1712,7 @@ static int parse_mtdids(const char *const ids)
id->mtd_id[mtd_id_len - 1] = '\0';
INIT_LIST_HEAD(&id->link);
- debug("+ id %s%d\t%16d bytes\t%s\n",
+ debug("+ id %s%d\t%lld bytes\t%s\n",
MTD_DEV_TYPE(id->type), id->num,
id->size, id->mtd_id);
@@ -1829,6 +1868,296 @@ int mtdparts_init(void)
return 0;
}
+/* Load mtd partition table from flash */
+static int mtdparts_ptbl_read(char *data)
+{
+ nand_info_t *nand;
+ int dev = nand_curr_device;
+ int ret = 0;
+ char *buff;
+ size_t rsize;
+ u32 offs = CONFIG_MTD_PTBL_OFFS;
+ u32 data_size, data_crc;
+
+ if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE ||
+ !nand_info[dev].name) {
+ printf("%s: nand not init.\n", __func__);
+ return -1;
+ }
+ nand = &nand_info[dev];
+
+ {
+ struct nand_chip *this = nand->priv;
+ struct rda_nand_info *info = this->priv;
+ offs = (offs * info->spl_adjust_ratio) / 2;
+ }
+
+ buff = malloc(CONFIG_MTD_PTBL_SIZE);
+ if(!buff) {
+ printf("%s: can't malloc memory.\n", __func__);
+ return -1;
+ }
+
+ /* calculate read size */
+ rsize = nand->erasesize - (offs % nand->erasesize);
+ if(rsize > CONFIG_MTD_PTBL_SIZE) {
+ rsize = CONFIG_MTD_PTBL_SIZE;
+ }
+
+ /* read data from flash */
+ ret = nand_read_skip_bad(nand, offs, &rsize, (u_char *)buff);
+ if(ret) {
+ printf("%s: flash read error %d\n", __func__, ret);
+ ret = -1;
+ goto exit;
+ }
+
+ memcpy((void*)&data_size, (void*)&buff[0], 4);
+ memcpy((void*)&data_crc, (void*)&buff[4], 4);
+ if(!data_size || data_size > (CONFIG_MTD_PTBL_SIZE - 8)) {
+ printf("%s: partition table is invalid.\n", __func__);
+ ret = -1;
+ goto exit;
+ }
+
+ /* crc checking */
+ if(data_crc != crc32(0, (const unsigned char *)(&buff[8]), data_size)) {
+ printf("%s: crc checking failed.\n", __func__);
+ ret = -1;
+ goto exit;
+ }
+
+ memcpy(data, (void*)&buff[8], data_size);
+ printf("%s: load partition table from %#x\n", __func__, offs);
+ printf("partition table: %s\n", data);
+
+exit:
+ free(buff);
+ return ret;
+}
+
+/* save mtd partition table to flash */
+static int mtdparts_ptbl_write(char *data, int need_erase)
+{
+ nand_info_t *nand;
+ int dev = nand_curr_device;
+ int ret = 0;
+ size_t wsize, rsize;
+ char *buff;
+ u32 offs = CONFIG_MTD_PTBL_OFFS;
+ nand_erase_options_t opts;
+ u32 data_size = strlen(data) + 1;
+ u32 data_crc;
+
+ buff = malloc(CONFIG_MTD_PTBL_SIZE);
+ if(!buff) {
+ printf("%s: can't malloc memory.\n", __func__);
+ return -1;
+ }
+
+ /* check if the new table is same as old */
+ if(mtdparts_ptbl_read(buff) == 0) {
+ if(strcmp(buff, data) == 0) {
+ printf("%s: same as old, do nothing.\n", __func__);
+ free(buff);
+ return 0;
+ }
+ }
+ free(buff);
+
+ if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE ||
+ !nand_info[dev].name) {
+ printf("%s: nand not init.\n", __func__);
+ return -1;
+ }
+ nand = &nand_info[dev];
+
+ {
+ printf("mtdparts_ptbl_write0: offs = 0x%x \n", offs);
+ struct nand_chip *this = nand->priv;
+ struct rda_nand_info *info = this->priv;
+ offs = (offs * info->spl_adjust_ratio) / 2;
+ printf("mtdparts_ptbl_write1: offs = 0x%x \n", offs);
+ }
+
+ printf("%s: save partition table to %#x\n", __func__, offs);
+ printf("%s: %s\n", __func__, data);
+
+ /* Limit data in one block */
+ if(data_size > (CONFIG_MTD_PTBL_SIZE - 8) ||
+ data_size > (nand->erasesize - (offs % nand->erasesize) - 8)) {
+ printf("%s: data size is too large.\n", __func__);
+ return -1;
+ }
+
+ buff = malloc(nand->erasesize);
+ if(!buff) {
+ printf("%s: can't malloc memory.\n", __func__);
+ return -1;
+ }
+
+ /* not need to do erase */
+ if(!need_erase) {
+ /* fill buffer */
+ data_crc = crc32(0, (const unsigned char *)data, data_size);
+ memcpy((void *)(buff), &data_size, 4);
+ memcpy((void *)(buff+4), &data_crc, 4);
+ memcpy((void *)(buff+8), data, data_size);
+
+ /* write data to flash */
+ wsize = data_size + 8;
+ ret = nand_write_skip_bad(nand, offs, &wsize, (u_char *)buff, 0);
+ if(ret) {
+ printf("%s: flash write error %d\n", __func__, ret);
+ }
+ goto exit;
+ }
+
+ /* need to do erase */
+
+ memset(&opts, 0, sizeof(opts));
+ opts.offset = (loff_t) (offs - (offs % nand->erasesize));
+ opts.length = (loff_t) nand->erasesize;
+ opts.jffs2 = 0;
+ opts.quiet = 0;
+
+ /* Read this block data to buffer */
+ rsize = nand->erasesize;
+ ret = nand_read_skip_bad(nand, opts.offset, &rsize, (u_char *)buff);
+ if(ret) {
+ printf("%s: flash read error %d\n", __func__, ret);
+ goto exit;
+ }
+
+ /* erase block */
+ ret = nand_erase_opts(nand, &opts);
+ if(ret) {
+ printf("%s: flash erase error %d\n", __func__, ret);
+ goto exit;
+ }
+
+ /* fill buffer */
+ data_crc = crc32(0, (const unsigned char *)data, data_size);
+ memcpy((void *)(buff+(offs % nand->erasesize)), &data_size, 4);
+ memcpy((void *)(buff+(offs % nand->erasesize)+4), &data_crc, 4);
+ memcpy((void *)(buff+(offs % nand->erasesize)+8), data, data_size);
+
+ /* write data to flash */
+ wsize = nand->erasesize;
+ ret = nand_write_skip_bad(nand, opts.offset, &wsize, (u_char *)buff, 0);
+ if(ret) {
+ printf("%s: flash write error %d\n", __func__, ret);
+ }
+
+exit:
+ free(buff);
+ return ret;
+}
+
+int mtdparts_init_from_ptbl(void)
+{
+ char *mtdparts_str = malloc(CONFIG_MTD_PTBL_SIZE);
+
+ setenv("mtdparts", (char *)mtdparts_default);
+
+ /* load partition table from flash */
+ if(mtdparts_str){
+ if(mtdparts_ptbl_read(mtdparts_str) == 0) {
+ setenv("mtdparts", mtdparts_str);
+ }
+ free(mtdparts_str);
+ }
+
+ setenv("mtdids", (char *)mtdids_default);
+ setenv("partition", NULL);
+
+ return mtdparts_init();
+}
+
+int mtdparts_save_ptbl(int need_erase)
+{
+ if(mtdparts_ptbl_write((char *)mtdparts_default, need_erase)){
+ printf("%s: save partition table failed.\n", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+int mtdparts_init_default(void)
+{
+ setenv("mtdids", (char *)mtdids_default);
+ setenv("mtdparts", (char *)mtdparts_default);
+ setenv("partition", NULL);
+
+ return mtdparts_init();
+}
+
+/* Check if the partition table is same with the table stored in flash */
+int mtdparts_ptbl_check(int *same)
+{
+ int ret;
+ char *buff;
+
+ if(!same) return -1;
+ *same = 0;
+
+ if(!mtdparts_default) {
+ return -1;
+ }
+
+ buff = malloc(CONFIG_MTD_PTBL_SIZE);
+ if(!buff) {
+ printf("%s: can't malloc memory.\n", __func__);
+ return -1;
+ }
+
+ ret = mtdparts_ptbl_read(buff);
+ if(!ret) {
+ printf("mtdparts_default: %s\n", mtdparts_default);
+ printf("mtdparts_in_flash: %s\n", buff);
+ if(strcmp(buff, mtdparts_default) == 0) {
+ *same = 1;
+ }
+ }
+
+ free(buff);
+ return ret;
+}
+
+/* Check if the part(bootloader & factorydata) of partition
+ table is same with the table stored in flash */
+int mtdparts_ptbl_check_factorydata(int *same)
+{
+ int ret;
+ char *buff;
+
+ if(!same) return -1;
+ *same = 0;
+
+ if(!mtdparts_default) {
+ return -1;
+ }
+
+ buff = malloc(CONFIG_MTD_PTBL_SIZE);
+ if(!buff) {
+ printf("%s: can't malloc memory.\n", __func__);
+ return -1;
+ }
+
+ ret = mtdparts_ptbl_read(buff);
+ if(!ret) {
+ int len = strstr(buff, "factorydata") - buff;
+ //printf("mtdparts_default: %s\n", mtdparts_default);
+ //printf("mtdparts_in_flash: %s\n", buff);
+ if(strncmp(buff, mtdparts_default, len) == 0) {
+ *same = 1;
+ }
+ }
+
+ free(buff);
+ return ret;
+}
+
/**
* Return pointer to the partition of a requested number from a requested
* device.
@@ -1870,6 +2199,23 @@ static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part
return NULL;
}
+int mtdparts_clear_all_dirty(struct mtd_device *dev)
+{
+ struct list_head *entry;
+ struct part_info *part;
+
+ if(!dev)
+ return -1;
+
+ printf("clear all %d mtdparts's dirty\n", dev->num_parts);
+ list_for_each(entry, &dev->parts) {
+ part = list_entry(entry, struct part_info, link);
+ if (part)
+ part->dirty = 0;
+ }
+ return 0;
+
+}
/***************************************************/
/* U-boot commands */
/***************************************************/