diff options
Diffstat (limited to 'common/cmd_mtdparts.c')
-rw-r--r-- | common/cmd_mtdparts.c | 388 |
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 */ /***************************************************/ |