X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fdfu%2Fdfu_mmc.c;h=926ccbd2ef5e9eac95d2083f6047c9abcee2ef0a;hb=664ee4c995c82b357a328da94880e37e7abb0a09;hp=b41785dfc7132742903864adf39824a54b871ce1;hpb=711b931f90e44ff1248cd73c15f64485470d86ff;p=u-boot diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index b41785dfc7..926ccbd2ef 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -12,17 +12,26 @@ #include #include #include +#include +#include #include -static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE) - dfu_file_buf[CONFIG_SYS_DFU_MAX_FILE_SIZE]; +static unsigned char *dfu_file_buf; static long dfu_file_buf_len; +static long dfu_file_buf_filled; static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu, u64 offset, void *buf, long *len) { - struct mmc *mmc = find_mmc_device(dfu->dev_num); + struct mmc *mmc; u32 blk_start, blk_count, n = 0; + int ret, part_num_bkp = 0; + + mmc = find_mmc_device(dfu->data.mmc.dev_num); + if (!mmc) { + error("Device MMC %d - not found!", dfu->data.mmc.dev_num); + return -ENODEV; + } /* * We must ensure that we work in lba_blk_size chunks, so ALIGN @@ -39,17 +48,25 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu, return -EINVAL; } + if (dfu->data.mmc.hw_partition >= 0) { + part_num_bkp = mmc_get_blk_desc(mmc)->hwpart; + ret = blk_select_hwpart_devnum(IF_TYPE_MMC, + dfu->data.mmc.dev_num, + dfu->data.mmc.hw_partition); + if (ret) + return ret; + } + debug("%s: %s dev: %d start: %d cnt: %d buf: 0x%p\n", __func__, - op == DFU_OP_READ ? "MMC READ" : "MMC WRITE", dfu->dev_num, - blk_start, blk_count, buf); + op == DFU_OP_READ ? "MMC READ" : "MMC WRITE", + dfu->data.mmc.dev_num, blk_start, blk_count, buf); switch (op) { case DFU_OP_READ: - n = mmc->block_dev.block_read(dfu->dev_num, blk_start, - blk_count, buf); + n = blk_dread(mmc_get_blk_desc(mmc), blk_start, blk_count, buf); break; case DFU_OP_WRITE: - n = mmc->block_dev.block_write(dfu->dev_num, blk_start, - blk_count, buf); + n = blk_dwrite(mmc_get_blk_desc(mmc), blk_start, blk_count, + buf); break; default: error("Operation not supported\n"); @@ -57,9 +74,21 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu, if (n != blk_count) { error("MMC operation failed"); + if (dfu->data.mmc.hw_partition >= 0) + blk_select_hwpart_devnum(IF_TYPE_MMC, + dfu->data.mmc.dev_num, + part_num_bkp); return -EIO; } + if (dfu->data.mmc.hw_partition >= 0) { + ret = blk_select_hwpart_devnum(IF_TYPE_MMC, + dfu->data.mmc.dev_num, + part_num_bkp); + if (ret) + return ret; + } + return 0; } @@ -80,22 +109,17 @@ static int mmc_file_buffer(struct dfu_entity *dfu, void *buf, long *len) static int mmc_file_op(enum dfu_op op, struct dfu_entity *dfu, void *buf, long *len) { + const char *fsname, *opname; char cmd_buf[DFU_CMD_BUF_SIZE]; char *str_env; int ret; switch (dfu->layout) { case DFU_FS_FAT: - sprintf(cmd_buf, "fat%s mmc %d:%d 0x%x %s", - op == DFU_OP_READ ? "load" : "write", - dfu->data.mmc.dev, dfu->data.mmc.part, - (unsigned int) buf, dfu->name); + fsname = "fat"; break; case DFU_FS_EXT4: - sprintf(cmd_buf, "ext4%s mmc %d:%d 0x%x /%s", - op == DFU_OP_READ ? "load" : "write", - dfu->data.mmc.dev, dfu->data.mmc.part, - (unsigned int) buf, dfu->name); + fsname = "ext4"; break; default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, @@ -103,6 +127,28 @@ static int mmc_file_op(enum dfu_op op, struct dfu_entity *dfu, return -1; } + switch (op) { + case DFU_OP_READ: + opname = "load"; + break; + case DFU_OP_WRITE: + opname = "write"; + break; + case DFU_OP_SIZE: + opname = "size"; + break; + default: + return -1; + } + + sprintf(cmd_buf, "%s%s mmc %d:%d", fsname, opname, + dfu->data.mmc.dev, dfu->data.mmc.part); + + if (op != DFU_OP_SIZE) + sprintf(cmd_buf + strlen(cmd_buf), " %p", buf); + + sprintf(cmd_buf + strlen(cmd_buf), " %s", dfu->name); + if (op == DFU_OP_WRITE) sprintf(cmd_buf + strlen(cmd_buf), " %lx", *len); @@ -114,7 +160,7 @@ static int mmc_file_op(enum dfu_op op, struct dfu_entity *dfu, return ret; } - if (dfu->layout != DFU_RAW_ADDR && op == DFU_OP_READ) { + if (op != DFU_OP_WRITE) { str_env = getenv("filesize"); if (str_env == NULL) { puts("dfu: Wrong file size!\n"); @@ -153,7 +199,7 @@ int dfu_flush_medium_mmc(struct dfu_entity *dfu) if (dfu->layout != DFU_RAW_ADDR) { /* Do stuff here. */ - ret = mmc_file_op(DFU_OP_WRITE, dfu, &dfu_file_buf, + ret = mmc_file_op(DFU_OP_WRITE, dfu, dfu_file_buf, &dfu_file_buf_len); /* Now that we're done */ @@ -163,6 +209,51 @@ int dfu_flush_medium_mmc(struct dfu_entity *dfu) return ret; } +long dfu_get_medium_size_mmc(struct dfu_entity *dfu) +{ + int ret; + long len; + + switch (dfu->layout) { + case DFU_RAW_ADDR: + return dfu->data.mmc.lba_size * dfu->data.mmc.lba_blk_size; + case DFU_FS_FAT: + case DFU_FS_EXT4: + dfu_file_buf_filled = -1; + ret = mmc_file_op(DFU_OP_SIZE, dfu, NULL, &len); + if (ret < 0) + return ret; + if (len > CONFIG_SYS_DFU_MAX_FILE_SIZE) + return -1; + return len; + default: + printf("%s: Layout (%s) not (yet) supported!\n", __func__, + dfu_get_layout(dfu->layout)); + return -1; + } +} + +static int mmc_file_unbuffer(struct dfu_entity *dfu, u64 offset, void *buf, + long *len) +{ + int ret; + long file_len; + + if (dfu_file_buf_filled == -1) { + ret = mmc_file_op(DFU_OP_READ, dfu, dfu_file_buf, &file_len); + if (ret < 0) + return ret; + dfu_file_buf_filled = file_len; + } + if (offset + *len > dfu_file_buf_filled) + return -EINVAL; + + /* Add to the current buffer. */ + memcpy(buf, dfu_file_buf + offset, *len); + + return 0; +} + int dfu_read_medium_mmc(struct dfu_entity *dfu, u64 offset, void *buf, long *len) { @@ -174,7 +265,7 @@ int dfu_read_medium_mmc(struct dfu_entity *dfu, u64 offset, void *buf, break; case DFU_FS_FAT: case DFU_FS_EXT4: - ret = mmc_file_op(DFU_OP_READ, dfu, buf, len); + ret = mmc_file_unbuffer(dfu, offset, buf, len); break; default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, @@ -184,6 +275,14 @@ int dfu_read_medium_mmc(struct dfu_entity *dfu, u64 offset, void *buf, return ret; } +void dfu_free_entity_mmc(struct dfu_entity *dfu) +{ + if (dfu_file_buf) { + free(dfu_file_buf); + dfu_file_buf = NULL; + } +} + /* * @param s Parameter string containing space-separated arguments: * 1st: @@ -194,8 +293,10 @@ int dfu_read_medium_mmc(struct dfu_entity *dfu, u64 offset, void *buf, * 2nd and 3rd: * lba_start and lba_size, for raw write * mmc_dev and mmc_part, for filesystems and part + * 4th (optional): + * mmcpart (access to HW eMMC partitions) */ -int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s) +int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s) { const char *entity_type; size_t second_arg; @@ -206,6 +307,8 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s) const char *argv[3]; const char **parg = argv; + dfu->data.mmc.dev_num = simple_strtoul(devstr, NULL, 10); + for (; parg < argv + sizeof(argv) / sizeof(*argv); ++parg) { *parg = strsep(&s, " "); if (*parg == NULL) { @@ -215,12 +318,17 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s) } entity_type = argv[0]; - second_arg = simple_strtoul(argv[1], NULL, 16); - third_arg = simple_strtoul(argv[2], NULL, 16); + /* + * Base 0 means we'll accept (prefixed with 0x or 0) base 16, 8, + * with default 10. + */ + second_arg = simple_strtoul(argv[1], NULL, 0); + third_arg = simple_strtoul(argv[2], NULL, 0); - mmc = find_mmc_device(dfu->dev_num); + mmc = find_mmc_device(dfu->data.mmc.dev_num); if (mmc == NULL) { - error("Couldn't find MMC device no. %d.\n", dfu->dev_num); + error("Couldn't find MMC device no. %d.\n", + dfu->data.mmc.dev_num); return -ENODEV; } @@ -229,18 +337,29 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s) return -ENODEV; } + dfu->data.mmc.hw_partition = -EINVAL; if (!strcmp(entity_type, "raw")) { dfu->layout = DFU_RAW_ADDR; dfu->data.mmc.lba_start = second_arg; dfu->data.mmc.lba_size = third_arg; dfu->data.mmc.lba_blk_size = mmc->read_bl_len; + + /* + * Check for an extra entry at dfu_alt_info env variable + * specifying the mmc HW defined partition number + */ + if (s) + if (!strcmp(strsep(&s, " "), "mmcpart")) + dfu->data.mmc.hw_partition = + simple_strtoul(s, NULL, 0); + } else if (!strcmp(entity_type, "part")) { disk_partition_t partinfo; - block_dev_desc_t *blk_dev = &mmc->block_dev; + struct blk_desc *blk_dev = mmc_get_blk_desc(mmc); int mmcdev = second_arg; int mmcpart = third_arg; - if (get_partition_info(blk_dev, mmcpart, &partinfo) != 0) { + if (part_get_info(blk_dev, mmcpart, &partinfo) != 0) { error("Couldn't find part #%d on mmc device #%d\n", mmcpart, mmcdev); return -ENODEV; @@ -266,10 +385,23 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s) } dfu->dev_type = DFU_DEV_MMC; + dfu->get_medium_size = dfu_get_medium_size_mmc; dfu->read_medium = dfu_read_medium_mmc; dfu->write_medium = dfu_write_medium_mmc; dfu->flush_medium = dfu_flush_medium_mmc; dfu->inited = 0; + dfu->free_entity = dfu_free_entity_mmc; + + /* Check if file buffer is ready */ + if (!dfu_file_buf) { + dfu_file_buf = memalign(CONFIG_SYS_CACHELINE_SIZE, + CONFIG_SYS_DFU_MAX_FILE_SIZE); + if (!dfu_file_buf) { + error("Could not memalign 0x%x bytes", + CONFIG_SYS_DFU_MAX_FILE_SIZE); + return -ENOMEM; + } + } return 0; }