diff options
author | Tom Rini <trini@ti.com> | 2013-03-12 14:28:28 -0400 |
---|---|---|
committer | Tom Rini <trini@ti.com> | 2013-03-12 14:28:28 -0400 |
commit | d309a1003804716309f9e74e19959ab3fbdac453 (patch) | |
tree | fe137fe7c8801b627194bb583a1c572ed5bd5cf0 | |
parent | 7d3ef444df299aea39909eaccbed1d915b4a7370 (diff) | |
parent | dd18e4d3f74f5d6f218ae2d68c233b986f9eade9 (diff) |
Merge branch 'am335x-connectivity-2013.01.01' into ti-u-boot-2013.01.01
-rw-r--r-- | README | 23 | ||||
-rw-r--r-- | common/cmd_dfu.c | 5 | ||||
-rw-r--r-- | common/cmd_mmc.c | 10 | ||||
-rw-r--r-- | common/cmd_nand.c | 55 | ||||
-rw-r--r-- | common/env_nand.c | 3 | ||||
-rw-r--r-- | drivers/dfu/Makefile | 1 | ||||
-rw-r--r-- | drivers/dfu/dfu.c | 251 | ||||
-rw-r--r-- | drivers/dfu/dfu_mmc.c | 143 | ||||
-rw-r--r-- | drivers/dfu/dfu_nand.c | 195 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_util.c | 68 | ||||
-rw-r--r-- | drivers/usb/gadget/Makefile | 10 | ||||
-rw-r--r-- | drivers/usb/gadget/composite.c | 27 | ||||
-rw-r--r-- | drivers/usb/gadget/ep0.c | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/f_dfu.c | 9 | ||||
-rw-r--r-- | include/configs/am335x_evm.h | 52 | ||||
-rw-r--r-- | include/dfu.h | 53 | ||||
-rw-r--r-- | include/nand.h | 4 |
17 files changed, 782 insertions, 128 deletions
@@ -1323,6 +1323,29 @@ The following options need to be configured: CONFIG_SH_MMCIF_CLK Define the clock frequency for MMCIF +- USB Device Firmware Update (DFU) class support: + CONFIG_DFU_FUNCTION + This enables the USB portion of the DFU USB class + + CONFIG_CMD_DFU + This enables the command "dfu" which is used to have + U-Boot create a DFU class device via USB. This command + requires that the "dfu_alt_info" environment variable be + set and define the alt settings to expose to the host. + + CONFIG_DFU_MMC + This enables support for exposing (e)MMC devices via DFU. + + CONFIG_DFU_NAND + This enables support for exposing NAND devices via DFU. + + CONFIG_SYS_DFU_MAX_FILE_SIZE + When updating files rather than the raw storage device, + we use a static buffer to copy the file into and then write + the buffer once we've been given the whole file. Define + this to the maximum filesize (in bytes) for the buffer. + Default is 4 MiB if undefined. + - Journaling Flash filesystem support: CONFIG_JFFS2_NAND, CONFIG_JFFS2_NAND_OFF, CONFIG_JFFS2_NAND_SIZE, CONFIG_JFFS2_NAND_DEV diff --git a/common/cmd_dfu.c b/common/cmd_dfu.c index 01d6b3a2d6..83ef32497a 100644 --- a/common/cmd_dfu.c +++ b/common/cmd_dfu.c @@ -50,12 +50,15 @@ static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (ret) return CMD_RET_FAILURE; - if (strcmp(argv[3], "list") == 0) { + if (argc > 3 && strcmp(argv[3], "list") == 0) { dfu_show_entities(); goto done; } +#ifdef CONFIG_TRATS board_usb_init(); +#endif + g_dnl_register(s); while (1) { if (ctrlc()) diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index 7dacd5114c..507ceef8b1 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -277,8 +277,9 @@ static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return 1; } - printf("\nMMC %s: dev # %d, block # %d, count %d ... ", - argv[1], curr_device, blk, cnt); + if (getenv("mmcsilent") == NULL) + printf("\nMMC %s: dev # %d, block # %d, count %d ... ", + argv[1], curr_device, blk, cnt); mmc_init(mmc); @@ -300,8 +301,9 @@ static int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) BUG(); } - printf("%d blocks %s: %s\n", - n, argv[1], (n == cnt) ? "OK" : "ERROR"); + if (getenv("mmcsilent") == NULL) + printf("%d blocks %s: %s\n", + n, argv[1], (n == cnt) ? "OK" : "ERROR"); return (n == cnt) ? 0 : 1; } diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 1568594ca4..da55c3826a 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -137,7 +137,8 @@ static inline int str2long(const char *p, ulong *num) return *p != '\0' && *endptr == '\0'; } -static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size) +static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size, + loff_t *maxsize) { #ifdef CONFIG_CMD_MTDPARTS struct mtd_device *dev; @@ -160,6 +161,7 @@ static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size) *off = part->offset; *size = part->size; + *maxsize = part->size; *idx = dev->id->num; ret = set_dev(*idx); @@ -173,10 +175,11 @@ static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size) #endif } -static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *maxsize) +static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *size, + loff_t *maxsize) { if (!str2off(arg, off)) - return get_part(arg, idx, off, maxsize); + return get_part(arg, idx, off, size, maxsize); if (*off >= nand_info[*idx].size) { puts("Offset exceeds device limit\n"); @@ -184,36 +187,35 @@ static int arg_off(const char *arg, int *idx, loff_t *off, loff_t *maxsize) } *maxsize = nand_info[*idx].size - *off; + *size = *maxsize; return 0; } static int arg_off_size(int argc, char *const argv[], int *idx, - loff_t *off, loff_t *size) + loff_t *off, loff_t *size, loff_t *maxsize) { int ret; - loff_t maxsize = 0; if (argc == 0) { *off = 0; *size = nand_info[*idx].size; + *maxsize = *size; goto print; } - ret = arg_off(argv[0], idx, off, &maxsize); + ret = arg_off(argv[0], idx, off, size, maxsize); if (ret) return ret; - if (argc == 1) { - *size = maxsize; + if (argc == 1) goto print; - } if (!str2off(argv[1], size)) { printf("'%s' is not a number\n", argv[1]); return -1; } - if (*size > maxsize) { + if (*size > *maxsize) { puts("Size exceeds partition or device limit\n"); return -1; } @@ -307,7 +309,8 @@ int do_nand_env_oob(cmd_tbl_t *cmdtp, int argc, char *const argv[]) if (argc < 3) goto usage; - if (arg_off(argv[2], &idx, &addr, &maxsize)) { + /* We don't care about size, or maxsize. */ + if (arg_off(argv[2], &idx, &addr, &maxsize, &maxsize)) { puts("Offset or partition name expected\n"); return 1; } @@ -432,7 +435,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int i, ret = 0; ulong addr; - loff_t off, size; + loff_t off, size, maxsize; char *cmd, *s; nand_info_t *nand; #ifdef CONFIG_SYS_NAND_QUIET @@ -557,7 +560,8 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) printf("\nNAND %s: ", cmd); /* skip first two or three arguments, look for offset and size */ - if (arg_off_size(argc - o, argv + o, &dev, &off, &size) != 0) + if (arg_off_size(argc - o, argv + o, &dev, &off, &size, + &maxsize) != 0) return 1; nand = &nand_info[dev]; @@ -625,7 +629,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (s && !strcmp(s, ".raw")) { raw = 1; - if (arg_off(argv[3], &dev, &off, &size)) + if (arg_off(argv[3], &dev, &off, &size, &maxsize)) return 1; if (argc > 4 && !str2long(argv[4], &pagecount)) { @@ -641,7 +645,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) rwsize = pagecount * (nand->writesize + nand->oobsize); } else { if (arg_off_size(argc - 3, argv + 3, &dev, - &off, &size) != 0) + &off, &size, &maxsize) != 0) return 1; rwsize = size; @@ -651,9 +655,11 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) !strcmp(s, ".e") || !strcmp(s, ".i")) { if (read) ret = nand_read_skip_bad(nand, off, &rwsize, + NULL, maxsize, (u_char *)addr); else ret = nand_write_skip_bad(nand, off, &rwsize, + NULL, maxsize, (u_char *)addr, 0); #ifdef CONFIG_CMD_NAND_TRIMFFS } else if (!strcmp(s, ".trimffs")) { @@ -661,8 +667,8 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) printf("Unknown nand command suffix '%s'\n", s); return 1; } - ret = nand_write_skip_bad(nand, off, &rwsize, - (u_char *)addr, + ret = nand_write_skip_bad(nand, off, &rwsize, NULL, + maxsize, (u_char *)addr, WITH_DROP_FFS); #endif #ifdef CONFIG_CMD_NAND_YAFFS @@ -671,9 +677,9 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) printf("Unknown nand command suffix '%s'.\n", s); return 1; } - ret = nand_write_skip_bad(nand, off, &rwsize, - (u_char *)addr, - WITH_INLINE_OOB); + ret = nand_write_skip_bad(nand, off, &rwsize, NULL, + maxsize, (u_char *)addr, + WITH_YAFFS_OOB); #endif } else if (!strcmp(s, ".oob")) { /* out-of-band data */ @@ -781,7 +787,8 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (s && !strcmp(s, ".allexcept")) allexcept = 1; - if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size) < 0) + if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size, + &maxsize) < 0) return 1; if (!nand_unlock(&nand_info[dev], off, size, allexcept)) { @@ -879,7 +886,8 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand, printf("\nLoading from %s, offset 0x%lx\n", nand->name, offset); cnt = nand->writesize; - r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr); + r = nand_read_skip_bad(nand, offset, &cnt, NULL, nand->size, + (u_char *) addr); if (r) { puts("** Read error\n"); bootstage_error(BOOTSTAGE_ID_NAND_HDR_READ); @@ -911,7 +919,8 @@ static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand, } bootstage_mark(BOOTSTAGE_ID_NAND_TYPE); - r = nand_read_skip_bad(nand, offset, &cnt, (u_char *) addr); + r = nand_read_skip_bad(nand, offset, &cnt, NULL, nand->size, + (u_char *) addr); if (r) { puts("** Read error\n"); bootstage_error(BOOTSTAGE_ID_NAND_READ); diff --git a/common/env_nand.c b/common/env_nand.c index 22e72a20b0..123bcc7273 100644 --- a/common/env_nand.c +++ b/common/env_nand.c @@ -281,7 +281,8 @@ int readenv(size_t offset, u_char *buf) } else { char_ptr = &buf[amount_loaded]; if (nand_read_skip_bad(&nand_info[0], offset, - &len, char_ptr)) + &len, NULL, + nand_info[0].size, char_ptr)) return 1; offset += blocksize; diff --git a/drivers/dfu/Makefile b/drivers/dfu/Makefile index 7b717bce28..153095d71e 100644 --- a/drivers/dfu/Makefile +++ b/drivers/dfu/Makefile @@ -27,6 +27,7 @@ LIB = $(obj)libdfu.o COBJS-$(CONFIG_DFU_FUNCTION) += dfu.o COBJS-$(CONFIG_DFU_MMC) += dfu_mmc.o +COBJS-$(CONFIG_DFU_NAND) += dfu_nand.o SRCS := $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(COBJS-y)) diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index e8477fb7c7..84139bd986 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -44,90 +44,234 @@ static int dfu_find_alt_num(const char *s) static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE) dfu_buf[DFU_DATA_BUF_SIZE]; +static int dfu_write_buffer_drain(struct dfu_entity *dfu) +{ + long w_size; + int ret; + + /* flush size? */ + w_size = dfu->i_buf - dfu->i_buf_start; + if (w_size == 0) + return 0; + + /* update CRC32 */ + dfu->crc = crc32(dfu->crc, dfu->i_buf_start, w_size); + + ret = dfu->write_medium(dfu, dfu->offset, dfu->i_buf_start, &w_size); + if (ret) + debug("%s: Write error!\n", __func__); + + /* point back */ + dfu->i_buf = dfu->i_buf_start; + + /* update offset */ + dfu->offset += w_size; + + puts("#"); + + return ret; +} + int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) { - static unsigned char *i_buf; - static int i_blk_seq_num; - long w_size = 0; int ret = 0; + int tret; + + debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x " + "offset: 0x%llx bufoffset: 0x%x\n", + __func__, dfu->name, buf, size, blk_seq_num, dfu->offset, + dfu->i_buf - dfu->i_buf_start); + + if (!dfu->inited) { + /* initial state */ + dfu->crc = 0; + dfu->offset = 0; + dfu->bad_skip = 0; + dfu->i_blk_seq_num = 0; + dfu->i_buf_start = dfu_buf; + dfu->i_buf_end = dfu_buf + sizeof(dfu_buf); + dfu->i_buf = dfu->i_buf_start; + + dfu->inited = 1; + } - debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x i_buf: 0x%p\n", - __func__, dfu->name, buf, size, blk_seq_num, i_buf); + if (dfu->i_blk_seq_num != blk_seq_num) { + printf("%s: Wrong sequence number! [%d] [%d]\n", + __func__, dfu->i_blk_seq_num, blk_seq_num); + return -1; + } - if (blk_seq_num == 0) { - i_buf = dfu_buf; - i_blk_seq_num = 0; + /* DFU 1.1 standard says: + * The wBlockNum field is a block sequence number. It increments each + * time a block is transferred, wrapping to zero from 65,535. It is used + * to provide useful context to the DFU loader in the device." + * + * This means that it's a 16 bit counter that roll-overs at + * 0xffff -> 0x0000. By having a typical 4K transfer block + * we roll-over at exactly 256MB. Not very fun to debug. + * + * Handling rollover, and having an inited variable, + * makes things work. + */ + + /* handle rollover */ + dfu->i_blk_seq_num = (dfu->i_blk_seq_num + 1) & 0xffff; + + /* flush buffer if overflow */ + if ((dfu->i_buf + size) > dfu->i_buf_end) { + tret = dfu_write_buffer_drain(dfu); + if (ret == 0) + ret = tret; } - if (i_blk_seq_num++ != blk_seq_num) { - printf("%s: Wrong sequence number! [%d] [%d]\n", - __func__, i_blk_seq_num, blk_seq_num); + /* we should be in buffer now (if not then size too large) */ + if ((dfu->i_buf + size) > dfu->i_buf_end) { + printf("%s: Wrong size! [%d] [%d] - %d\n", + __func__, dfu->i_blk_seq_num, blk_seq_num, size); return -1; } - memcpy(i_buf, buf, size); - i_buf += size; + memcpy(dfu->i_buf, buf, size); + dfu->i_buf += size; + /* if end or if buffer full flush */ + if (size == 0 || (dfu->i_buf + size) > dfu->i_buf_end) { + tret = dfu_write_buffer_drain(dfu); + if (ret == 0) + ret = tret; + } + + /* end? */ if (size == 0) { - /* Integrity check (if needed) */ - debug("%s: %s %d [B] CRC32: 0x%x\n", __func__, dfu->name, - i_buf - dfu_buf, crc32(0, dfu_buf, i_buf - dfu_buf)); + /* Now try and flush to the medium if needed. */ + if (dfu->flush_medium) + ret = dfu->flush_medium(dfu); + printf("\nDFU complete CRC32: 0x%08x\n", dfu->crc); - w_size = i_buf - dfu_buf; - ret = dfu->write_medium(dfu, dfu_buf, &w_size); - if (ret) - debug("%s: Write error!\n", __func__); + /* clear everything */ + dfu->crc = 0; + dfu->offset = 0; + dfu->i_blk_seq_num = 0; + dfu->i_buf_start = dfu_buf; + dfu->i_buf_end = dfu_buf + sizeof(dfu_buf); + dfu->i_buf = dfu->i_buf_start; + + dfu->inited = 0; - i_blk_seq_num = 0; - i_buf = NULL; - return ret; } - return ret; + return ret = 0 ? size : ret; +} + +static int dfu_read_buffer_fill(struct dfu_entity *dfu, void *buf, int size) +{ + long chunk; + int ret, readn; + + readn = 0; + while (size > 0) { + + /* get chunk that can be read */ + chunk = min(size, dfu->b_left); + /* consume */ + if (chunk > 0) { + memcpy(buf, dfu->i_buf, chunk); + dfu->crc = crc32(dfu->crc, buf, chunk); + dfu->i_buf += chunk; + dfu->b_left -= chunk; + size -= chunk; + buf += chunk; + readn += chunk; + } + + /* all done */ + if (size > 0) { + /* no more to read */ + if (dfu->r_left == 0) + break; + + dfu->i_buf = dfu->i_buf_start; + dfu->b_left = dfu->i_buf_end - dfu->i_buf_start; + + /* got to read, but buffer is empty */ + if (dfu->b_left > dfu->r_left) + dfu->b_left = dfu->r_left; + ret = dfu->read_medium(dfu, dfu->offset, dfu->i_buf, + &dfu->b_left); + if (ret != 0) { + debug("%s: Read error!\n", __func__); + return ret; + } + dfu->offset += dfu->b_left; + dfu->r_left -= dfu->b_left; + + puts("#"); + } + } + + return readn; } int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) { - static unsigned char *i_buf; - static int i_blk_seq_num; - static long r_size; - static u32 crc; int ret = 0; debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x i_buf: 0x%p\n", - __func__, dfu->name, buf, size, blk_seq_num, i_buf); + __func__, dfu->name, buf, size, blk_seq_num, dfu->i_buf); + + if (!dfu->inited) { + ret = dfu->read_medium(dfu, 0, NULL, &dfu->r_left); + if (ret != 0) { + debug("%s: failed to get r_left\n", __func__); + return ret; + } + + debug("%s: %s %ld [B]\n", __func__, dfu->name, dfu->r_left); + + dfu->i_blk_seq_num = 0; + dfu->crc = 0; + dfu->offset = 0; + dfu->i_buf_start = dfu_buf; + dfu->i_buf_end = dfu_buf + sizeof(dfu_buf); + dfu->i_buf = dfu->i_buf_start; + dfu->b_left = 0; - if (blk_seq_num == 0) { - i_buf = dfu_buf; - ret = dfu->read_medium(dfu, i_buf, &r_size); - debug("%s: %s %ld [B]\n", __func__, dfu->name, r_size); - i_blk_seq_num = 0; - /* Integrity check (if needed) */ - crc = crc32(0, dfu_buf, r_size); + dfu->bad_skip = 0; + + dfu->inited = 1; } - if (i_blk_seq_num++ != blk_seq_num) { + if (dfu->i_blk_seq_num != blk_seq_num) { printf("%s: Wrong sequence number! [%d] [%d]\n", - __func__, i_blk_seq_num, blk_seq_num); + __func__, dfu->i_blk_seq_num, blk_seq_num); return -1; } + /* handle rollover */ + dfu->i_blk_seq_num = (dfu->i_blk_seq_num + 1) & 0xffff; - if (r_size >= size) { - memcpy(buf, i_buf, size); - i_buf += size; - r_size -= size; - return size; - } else { - memcpy(buf, i_buf, r_size); - i_buf += r_size; - debug("%s: %s CRC32: 0x%x\n", __func__, dfu->name, crc); - puts("UPLOAD ... done\nCtrl+C to exit ...\n"); + ret = dfu_read_buffer_fill(dfu, buf, size); + if (ret < 0) { + printf("%s: Failed to fill buffer\n", __func__); + return -1; + } + + if (ret < size) { + debug("%s: %s CRC32: 0x%x\n", __func__, dfu->name, dfu->crc); + puts("\nUPLOAD ... done\nCtrl+C to exit ...\n"); - i_buf = NULL; - i_blk_seq_num = 0; - crc = 0; - return r_size; + dfu->i_blk_seq_num = 0; + dfu->crc = 0; + dfu->offset = 0; + dfu->i_buf_start = dfu_buf; + dfu->i_buf_end = dfu_buf + sizeof(dfu_buf); + dfu->i_buf = dfu->i_buf_start; + dfu->b_left = 0; + + dfu->bad_skip = 0; + + dfu->inited = 0; } + return ret; } @@ -147,6 +291,9 @@ static int dfu_fill_entity(struct dfu_entity *dfu, char *s, int alt, if (strcmp(interface, "mmc") == 0) { if (dfu_fill_entity_mmc(dfu, s)) return -1; + } else if (strcmp(interface, "nand") == 0) { + if (dfu_fill_entity_nand(dfu, s)) + return -1; } else { printf("%s: Device %s not (yet) supported!\n", __func__, interface); diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index 5d504dffd1..2d5ffd88f1 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -21,6 +21,8 @@ #include <common.h> #include <malloc.h> +#include <errno.h> +#include <div64.h> #include <dfu.h> enum dfu_mmc_op { @@ -28,36 +30,67 @@ enum dfu_mmc_op { DFU_OP_WRITE, }; +static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE) + dfu_file_buf[CONFIG_SYS_DFU_MAX_FILE_SIZE]; +static long dfu_file_buf_len; + static int mmc_block_op(enum dfu_mmc_op op, struct dfu_entity *dfu, - void *buf, long *len) + u64 offset, void *buf, long *len) { char cmd_buf[DFU_CMD_BUF_SIZE]; + u32 blk_start, blk_count; - sprintf(cmd_buf, "mmc %s 0x%x %x %x", - op == DFU_OP_READ ? "read" : "write", - (unsigned int) buf, - dfu->data.mmc.lba_start, - dfu->data.mmc.lba_size); + /* + * We must ensure that we work in lba_blk_size chunks, so ALIGN + * this value. + */ + *len = ALIGN(*len, dfu->data.mmc.lba_blk_size); - if (op == DFU_OP_READ) - *len = dfu->data.mmc.lba_blk_size * dfu->data.mmc.lba_size; + blk_start = dfu->data.mmc.lba_start + + (u32)lldiv(offset, dfu->data.mmc.lba_blk_size); + blk_count = *len / dfu->data.mmc.lba_blk_size; + if (*len + blk_start > + dfu->data.mmc.lba_size * dfu->data.mmc.lba_size) { + puts("Request would exceed designated area!\n"); + return -EINVAL; + } + + sprintf(cmd_buf, "mmc %s %p %x %x", + op == DFU_OP_READ ? "read" : "write", + buf, blk_start, blk_count); debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf); return run_command(cmd_buf, 0); } -static inline int mmc_block_write(struct dfu_entity *dfu, void *buf, long *len) +static inline int mmc_block_write(struct dfu_entity *dfu, + u64 offset, void *buf, long *len) { - return mmc_block_op(DFU_OP_WRITE, dfu, buf, len); + return mmc_block_op(DFU_OP_WRITE, dfu, offset, buf, len); } -static inline int mmc_block_read(struct dfu_entity *dfu, void *buf, long *len) +static inline int mmc_block_read(struct dfu_entity *dfu, + u64 offset, void *buf, long *len) { - return mmc_block_op(DFU_OP_READ, dfu, buf, len); + return mmc_block_op(DFU_OP_READ, dfu, offset, buf, len); +} + +static int mmc_file_buffer(struct dfu_entity *dfu, void *buf, long *len) +{ + if (dfu_file_buf_len + *len > CONFIG_SYS_DFU_MAX_FILE_SIZE) { + dfu_file_buf_len = 0; + return -EINVAL; + } + + /* Add to the current buffer. */ + memcpy(dfu_file_buf + dfu_file_buf_len, buf, *len); + dfu_file_buf_len += *len; + + return 0; } static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu, - void *buf, long *len) + u64 offset, void *buf, long *len) { char cmd_buf[DFU_CMD_BUF_SIZE]; char *str_env; @@ -69,8 +102,15 @@ static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu, op == DFU_OP_READ ? "load" : "write", dfu->data.mmc.dev, dfu->data.mmc.part, (unsigned int) buf, dfu->name, *len); + if (op == DFU_OP_READ && offset != 0) + sprintf(cmd_buf + strlen(cmd_buf), " %llx", offset); break; case DFU_FS_EXT4: + if (offset != 0) { + debug("%s: Offset value %llx != 0 not supported!\n", + __func__, offset); + return -1; + } sprintf(cmd_buf, "ext4%s mmc %d:%d /%s 0x%x %ld", op == DFU_OP_READ ? "load" : "write", dfu->data.mmc.dev, dfu->data.mmc.part, @@ -79,6 +119,7 @@ static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu, default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, dfu_get_layout(dfu->layout)); + return -1; } debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf); @@ -101,27 +142,24 @@ static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu, return ret; } -static inline int mmc_file_write(struct dfu_entity *dfu, void *buf, long *len) +static inline int mmc_file_read(struct dfu_entity *dfu, + u64 offset, void *buf, long *len) { - return mmc_file_op(DFU_OP_WRITE, dfu, buf, len); + return mmc_file_op(DFU_OP_READ, dfu, offset, buf, len); } -static inline int mmc_file_read(struct dfu_entity *dfu, void *buf, long *len) -{ - return mmc_file_op(DFU_OP_READ, dfu, buf, len); -} - -int dfu_write_medium_mmc(struct dfu_entity *dfu, void *buf, long *len) +int dfu_write_medium_mmc(struct dfu_entity *dfu, + u64 offset, void *buf, long *len) { int ret = -1; switch (dfu->layout) { case DFU_RAW_ADDR: - ret = mmc_block_write(dfu, buf, len); + ret = mmc_block_write(dfu, offset, buf, len); break; case DFU_FS_FAT: case DFU_FS_EXT4: - ret = mmc_file_write(dfu, buf, len); + ret = mmc_file_buffer(dfu, buf, len); break; default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, @@ -131,17 +169,34 @@ int dfu_write_medium_mmc(struct dfu_entity *dfu, void *buf, long *len) return ret; } -int dfu_read_medium_mmc(struct dfu_entity *dfu, void *buf, long *len) +int dfu_flush_medium_mmc(struct dfu_entity *dfu) +{ + int ret = 0; + + if (dfu->layout != DFU_RAW_ADDR) { + /* Do stuff here. */ + ret = mmc_file_op(DFU_OP_WRITE, dfu, 0, &dfu_file_buf, + &dfu_file_buf_len); + + /* Now that we're done */ + dfu_file_buf_len = 0; + } + + return ret; +} + +int dfu_read_medium_mmc(struct dfu_entity *dfu, u64 offset, void *buf, + long *len) { int ret = -1; switch (dfu->layout) { case DFU_RAW_ADDR: - ret = mmc_block_read(dfu, buf, len); + ret = mmc_block_read(dfu, offset, buf, len); break; case DFU_FS_FAT: case DFU_FS_EXT4: - ret = mmc_file_read(dfu, buf, len); + ret = mmc_file_read(dfu, offset, buf, len); break; default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, @@ -153,6 +208,10 @@ int dfu_read_medium_mmc(struct dfu_entity *dfu, void *buf, long *len) int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s) { + int dev, part; + struct mmc *mmc; + block_dev_desc_t *blk_dev; + disk_partition_t partinfo; char *st; dfu->dev_type = DFU_DEV_MMC; @@ -166,8 +225,36 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s) dfu->layout = DFU_FS_FAT; } else if (!strcmp(st, "ext4")) { dfu->layout = DFU_FS_EXT4; + } else if (!strcmp(st, "part")) { + + dfu->layout = DFU_RAW_ADDR; + + dev = simple_strtoul(s, &s, 10); + s++; + part = simple_strtoul(s, &s, 10); + + mmc = find_mmc_device(dev); + if (mmc == NULL || mmc_init(mmc)) { + printf("%s: could not find mmc device #%d!\n", + __func__, dev); + return -ENODEV; + } + + blk_dev = &mmc->block_dev; + if (get_partition_info(blk_dev, part, &partinfo) != 0) { + printf("%s: could not find partition #%d " + "on mmc device #%d!\n", + __func__, part, dev); + return -ENODEV; + } + + dfu->data.mmc.lba_start = partinfo.start; + dfu->data.mmc.lba_size = partinfo.size; + dfu->data.mmc.lba_blk_size = partinfo.blksz; + } else { printf("%s: Memory layout (%s) not supported!\n", __func__, st); + return -ENODEV; } if (dfu->layout == DFU_FS_EXT4 || dfu->layout == DFU_FS_FAT) { @@ -177,6 +264,10 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s) dfu->read_medium = dfu_read_medium_mmc; dfu->write_medium = dfu_write_medium_mmc; + dfu->flush_medium = dfu_flush_medium_mmc; + + /* initial state */ + dfu->inited = 0; return 0; } diff --git a/drivers/dfu/dfu_nand.c b/drivers/dfu/dfu_nand.c new file mode 100644 index 0000000000..b7f60dd496 --- /dev/null +++ b/drivers/dfu/dfu_nand.c @@ -0,0 +1,195 @@ +/* + * dfu_nand.c -- DFU for NAND routines. + * + * Copyright (C) 2012-2013 Texas Instruments, Inc. + * + * Based on dfu_mmc.c which is: + * Copyright (C) 2012 Samsung Electronics + * author: Lukasz Majewski <l.majewski@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <common.h> +#include <malloc.h> +#include <errno.h> +#include <div64.h> +#include <dfu.h> +#include <linux/mtd/mtd.h> +#include <jffs2/load_kernel.h> +#include <nand.h> + +enum dfu_nand_op { + DFU_OP_READ = 1, + DFU_OP_WRITE, +}; + +static int nand_block_op(enum dfu_nand_op op, struct dfu_entity *dfu, + u64 offset, void *buf, long *len) +{ + loff_t start; + size_t count, actual; + int ret; + int dev; + nand_info_t *nand; + + /* if buf == NULL return total size of the area */ + if (buf == NULL) { + *len = dfu->data.nand.size; + return 0; + } + + start = dfu->data.nand.start + offset + dfu->bad_skip; + count = *len; + if (start + count > + dfu->data.nand.start + dfu->data.nand.size) { + printf("%s: block_op out of bounds\n", __func__); + return -1; + } + + dev = nand_curr_device; + if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || + !nand_info[dev].name) { + printf("%s: invalid nand device\n", __func__); + return -1; + } + + nand = &nand_info[dev]; + + if (op == DFU_OP_READ) + ret = nand_read_skip_bad(nand, start, &count, &actual, + nand->size, buf); + else + ret = nand_write_skip_bad(nand, start, &count, &actual, + nand->size, buf, 0); + + if (ret != 0) { + printf("%s: nand_%s_skip_bad call failed at %llx!\n", + __func__, op == DFU_OP_READ ? "read" : "write", + start); + return ret; + } + + /* + * Find out where we stopped writing data. This can be deeper into + * the NAND than we expected due to having to skip bad blocks. So + * we must take this into account for the next write, if any. + */ + if (actual > count) { + printf("%s: skipped 0x%x bad bytes at 0x%llx\n", __func__, + actual - count, start); + dfu->bad_skip += actual - count; + } + + return ret; +} + +static inline int nand_block_write(struct dfu_entity *dfu, + u64 offset, void *buf, long *len) +{ + return nand_block_op(DFU_OP_WRITE, dfu, offset, buf, len); +} + +static inline int nand_block_read(struct dfu_entity *dfu, + u64 offset, void *buf, long *len) +{ + return nand_block_op(DFU_OP_READ, dfu, offset, buf, len); +} + +static int dfu_write_medium_nand(struct dfu_entity *dfu, + u64 offset, void *buf, long *len) +{ + int ret = -1; + + switch (dfu->layout) { + case DFU_RAW_ADDR: + ret = nand_block_write(dfu, offset, buf, len); + break; + default: + printf("%s: Layout (%s) not (yet) supported!\n", __func__, + dfu_get_layout(dfu->layout)); + } + + return ret; +} + +static int dfu_read_medium_nand(struct dfu_entity *dfu, u64 offset, void *buf, + long *len) +{ + int ret = -1; + + switch (dfu->layout) { + case DFU_RAW_ADDR: + ret = nand_block_read(dfu, offset, buf, len); + break; + default: + printf("%s: Layout (%s) not (yet) supported!\n", __func__, + dfu_get_layout(dfu->layout)); + } + + return ret; +} + +int dfu_fill_entity_nand(struct dfu_entity *dfu, char *s) +{ + char *st; + int ret, dev, part; + + dfu->dev_type = DFU_DEV_NAND; + st = strsep(&s, " "); + if (!strcmp(st, "raw")) { + dfu->layout = DFU_RAW_ADDR; + dfu->data.nand.start = simple_strtoul(s, &s, 16); + s++; + dfu->data.nand.size = simple_strtoul(s, &s, 16); + } else if (!strcmp(st, "part")) { + char mtd_id[32]; + struct mtd_device *mtd_dev; + u8 part_num; + struct part_info *pi; + + dfu->layout = DFU_RAW_ADDR; + + dev = simple_strtoul(s, &s, 10); + s++; + part = simple_strtoul(s, &s, 10); + + sprintf(mtd_id, "%s%d,%d", "nand", dev, part - 1); + printf("using id '%s'\n", mtd_id); + + mtdparts_init(); + + ret = find_dev_and_part(mtd_id, &mtd_dev, &part_num, &pi); + if (ret != 0) { + printf("Could not locate '%s'\n", mtd_id); + return -1; + } + + dfu->data.nand.start = pi->offset; + dfu->data.nand.size = pi->size; + + } else { + printf("%s: Memory layout (%s) not supported!\n", __func__, st); + return -1; + } + + dfu->read_medium = dfu_read_medium_nand; + dfu->write_medium = dfu_write_medium_nand; + + /* initial state */ + dfu->inited = 0; + + return 0; +} diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 2ba0c5ef95..a5c91f833a 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -399,11 +399,13 @@ int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length, * @param nand NAND device * @param offset offset in flash * @param length image length + * @param used length of flash needed for the requested length * @return 0 if the image fits and there are no bad blocks * 1 if the image fits, but there are bad blocks * -1 if the image does not fit */ -static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length) +static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length, + size_t *used) { size_t len_excl_bad = 0; int ret = 0; @@ -425,8 +427,13 @@ static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length) ret = 1; offset += block_len; + *used += block_len; } + /* If the length is not a multiple of block_len, adjust. */ + if (len_excl_bad > length) + *used -= (len_excl_bad - length); + return ret; } @@ -459,23 +466,36 @@ static size_t drop_ffs(const nand_info_t *nand, const u_char *buf, * Write image to NAND flash. * Blocks that are marked bad are skipped and the is written to the next * block instead as long as the image is short enough to fit even after - * skipping the bad blocks. + * skipping the bad blocks. Due to bad blocks we may not be able to + * perform the requested write. In the case where the write would + * extend beyond the end of the NAND device, both length and actual (if + * not NULL) are set to 0. In the case where the write would extend + * beyond the limit we are passed, length is set to 0 and actual is set + * to the required length. * * @param nand NAND device * @param offset offset in flash * @param length buffer length + * @param actual set to size required to write length worth of + * buffer or 0 on error, if not NULL + * @param lim maximum size that actual may be in order to not + * exceed the buffer * @param buffer buffer to read from * @param flags flags modifying the behaviour of the write to NAND * @return 0 in case of success */ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, - u_char *buffer, int flags) + size_t *actual, loff_t lim, u_char *buffer, int flags) { int rval = 0, blocksize; size_t left_to_write = *length; + size_t used_for_write = 0; u_char *p_buffer = buffer; int need_skip; + if (actual) + *actual = 0; + #ifdef CONFIG_CMD_NAND_YAFFS if (flags & WITH_YAFFS_OOB) { if (flags & ~WITH_YAFFS_OOB) @@ -512,13 +532,23 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, return -EINVAL; } - need_skip = check_skip_len(nand, offset, *length); + need_skip = check_skip_len(nand, offset, *length, &used_for_write); + + if (actual) + *actual = used_for_write; + if (need_skip < 0) { printf("Attempt to write outside the flash area\n"); *length = 0; return -EINVAL; } + if (used_for_write > lim) { + puts("Size of write exceeds partition or device limit\n"); + *length = 0; + return -EFBIG; + } + if (!need_skip && !(flags & WITH_DROP_FFS)) { rval = nand_write(nand, offset, length, buffer); if (rval == 0) @@ -609,36 +639,58 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, * * Read image from NAND flash. * Blocks that are marked bad are skipped and the next block is read - * instead as long as the image is short enough to fit even after skipping the - * bad blocks. + * instead as long as the image is short enough to fit even after + * skipping the bad blocks. Due to bad blocks we may not be able to + * perform the requested read. In the case where the read would extend + * beyond the end of the NAND device, both length and actual (if not + * NULL) are set to 0. In the case where the read would extend beyond + * the limit we are passed, length is set to 0 and actual is set to the + * required length. * * @param nand NAND device * @param offset offset in flash * @param length buffer length, on return holds number of read bytes + * @param actual set to size required to read length worth of buffer or 0 + * on error, if not NULL + * @param lim maximum size that actual may be in order to not exceed the + * buffer * @param buffer buffer to write to * @return 0 in case of success */ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, - u_char *buffer) + size_t *actual, loff_t lim, u_char *buffer) { int rval; size_t left_to_read = *length; + size_t used_for_read = 0; u_char *p_buffer = buffer; int need_skip; if ((offset & (nand->writesize - 1)) != 0) { printf("Attempt to read non page-aligned data\n"); *length = 0; + if (actual) + *actual = 0; return -EINVAL; } - need_skip = check_skip_len(nand, offset, *length); + need_skip = check_skip_len(nand, offset, *length, &used_for_read); + + if (actual) + *actual = used_for_read; + if (need_skip < 0) { printf("Attempt to read outside the flash area\n"); *length = 0; return -EINVAL; } + if (used_for_read > lim) { + puts("Size of read exceeds partition or device limit\n"); + *length = 0; + return -EFBIG; + } + if (!need_skip) { rval = nand_read(nand, offset, length, buffer); if (!rval || rval == -EUCLEAN) diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 040eaba3bc..e545b6be6b 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -25,15 +25,21 @@ include $(TOPDIR)/config.mk LIB := $(obj)libusb_gadget.o +# if defined(CONFIG_USB_GADGET) || defined(CONFIG_USB_ETHER) +# Everytime you forget how crufty makefiles can get things like +# this remind you... +ifneq (,$(CONFIG_USB_GADGET)$(CONFIG_USB_ETHER)) +COBJS-y += epautoconf.o config.o usbstring.o +endif + # new USB gadget layer dependencies ifdef CONFIG_USB_GADGET -COBJS-y += epautoconf.o config.o usbstring.o COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o endif ifdef CONFIG_USB_ETHER -COBJS-y += ether.o epautoconf.o config.o usbstring.o +COBJS-y += ether.o COBJS-$(CONFIG_USB_ETH_RNDIS) += rndis.o COBJS-$(CONFIG_MV_UDC) += mv_udc.o COBJS-$(CONFIG_CPU_PXA25X) += pxa25x_udc.o diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index ebb5131a9c..64964360c7 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -773,6 +773,33 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (value >= 0) value = min(w_length, (u16) value); break; + +#ifdef CONFIG_DFU_FUNCTION + /* DFU is mighty weird */ + case DFU_DT_FUNC: + w_value &= 0xff; + list_for_each_entry(c, &cdev->configs, list) { + if (w_value != 0) { + w_value--; + continue; + } + + list_for_each_entry(f, &c->functions, list) { + + /* DFU function only */ + if (strcmp(f->name, "dfu") != 0) + continue; + + value = f->setup(f, ctrl); + goto dfu_func_done; + } + } +dfu_func_done: + if (value >= 0) + value = min(w_length, (u16) value); + break; +#endif + default: goto unknown; } diff --git a/drivers/usb/gadget/ep0.c b/drivers/usb/gadget/ep0.c index aa8f91600d..971d846ff6 100644 --- a/drivers/usb/gadget/ep0.c +++ b/drivers/usb/gadget/ep0.c @@ -221,6 +221,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device, break; case USB_DESCRIPTOR_TYPE_CONFIGURATION: + case USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION: { struct usb_configuration_descriptor *configuration_descriptor; diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c index 10547e3279..c15585c1d7 100644 --- a/drivers/usb/gadget/f_dfu.c +++ b/drivers/usb/gadget/f_dfu.c @@ -164,6 +164,9 @@ static void handle_getstatus(struct usb_request *req) /* send status response */ dstat->bStatus = f_dfu->dfu_status; + dstat->bwPollTimeout[0] = 0; + dstat->bwPollTimeout[1] = 0; + dstat->bwPollTimeout[2] = 0; dstat->bState = f_dfu->dfu_state; dstat->iString = 0; } @@ -534,8 +537,10 @@ dfu_handle(struct usb_function *f, const struct usb_ctrlrequest *ctrl) value = min(len, (u16) sizeof(dfu_func)); memcpy(req->buf, &dfu_func, value); } - } else /* DFU specific request */ - value = dfu_state[f_dfu->dfu_state] (f_dfu, ctrl, gadget, req); + return value; + } + + value = dfu_state[f_dfu->dfu_state] (f_dfu, ctrl, gadget, req); if (value >= 0) { req->length = value; diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index 08d8a9301c..ed7aa26986 100644 --- a/include/configs/am335x_evm.h +++ b/include/configs/am335x_evm.h @@ -39,6 +39,8 @@ #define CONFIG_SETUP_MEMORY_TAGS #define CONFIG_INITRD_TAG +#define CONFIG_SYS_CACHELINE_SIZE 64 + /* commands to include */ #include <config_cmd_default.h> @@ -59,6 +61,11 @@ "fdtfile=\0" \ "console=ttyO0,115200n8\0" \ "optargs=\0" \ + "mtdids=" MTDIDS_DEFAULT "\0" \ + "mtdparts=" MTDPARTS_DEFAULT "\0" \ + "dfu_alt_info_mmc=" DFU_ALT_INFO_MMC "\0" \ + "dfu_alt_info_emmc=rawemmc mmc 0 3751936\0" \ + "dfu_alt_info_nand=" DFU_ALT_INFO_NAND "\0" \ "mmcdev=0\0" \ "mmcroot=/dev/mmcblk0p2 ro\0" \ "mmcrootfstype=ext4 rootwait\0" \ @@ -160,8 +167,8 @@ #define CONFIG_CMD_ECHO -/* max number of command args */ -#define CONFIG_SYS_MAXARGS 16 +/* We set the max number of command args high to avoid HUSH bugs. */ +#define CONFIG_SYS_MAXARGS 64 /* Console I/O Buffer Size */ #define CONFIG_SYS_CBSIZE 512 @@ -190,6 +197,7 @@ #define CONFIG_CMD_MMC #define CONFIG_DOS_PARTITION #define CONFIG_CMD_FAT +#define CONFIG_FAT_WRITE #define CONFIG_CMD_EXT2 #define CONFIG_SPI @@ -200,6 +208,38 @@ #define CONFIG_CMD_SF #define CONFIG_SF_DEFAULT_SPEED (24000000) +/* USB Composite download gadget - g_dnl */ +#define CONFIG_USB_GADGET +#define CONFIG_USBDOWNLOAD_GADGET + +/* USB TI's IDs */ +#define CONFIG_USBD_HS +#define CONFIG_G_DNL_VENDOR_NUM 0x0403 +#define CONFIG_G_DNL_PRODUCT_NUM 0xBD00 +#define CONFIG_G_DNL_MANUFACTURER "Texas Instruments" + +/* USB Device Firmware Update support */ +#define CONFIG_DFU_FUNCTION +#define CONFIG_DFU_MMC +#define CONFIG_DFU_NAND +#define CONFIG_CMD_DFU +#define DFU_ALT_INFO_MMC \ + "boot part 0 1;" \ + "rootfs part 0 2;" \ + "MLO fat 0 1;" \ + "MLO.raw mmc 100 100;" \ + "u-boot.img.raw mmc 300 3C0;" \ + "u-boot.img fat 0 1;" \ + "uEnv.txt fat 0 1" +#define DFU_ALT_INFO_NAND \ + "SPL part 0 1;" \ + "SPL.backup1 part 0 2;" \ + "SPL.backup2 part 0 3;" \ + "SPL.backup3 part 0 4;" \ + "u-boot part 0 5;" \ + "kernel part 0 7;" \ + "rootfs part 0 8" + /* Physical Memory Map */ #define CONFIG_NR_DRAM_BANKS 1 /* 1 bank of DRAM */ #define PHYS_DRAM_1 0x80000000 /* DRAM Bank #1 */ @@ -344,6 +384,7 @@ #define CONFIG_MUSB_GADGET #define CONFIG_MUSB_PIO_ONLY #define CONFIG_USB_GADGET_DUALSPEED +#define CONFIG_USB_GADGET_VBUS_DRAW 2 #define CONFIG_MUSB_HOST #define CONFIG_AM335X_USB0 #define CONFIG_AM335X_USB0_MODE MUSB_PERIPHERAL @@ -415,6 +456,13 @@ /* NAND support */ #ifdef CONFIG_NAND #define CONFIG_CMD_NAND +#define CONFIG_CMD_MTDPARTS +#define MTDIDS_DEFAULT "nand0=omap2-nand.0" +#define MTDPARTS_DEFAULT "mtdparts=omap2-nand.0:128k(SPL)," \ + "128k(SPL.backup1)," \ + "128k(SPL.backup2)," \ + "128k(SPL.backup3),1920k(u-boot)," \ + "128k(u-boot-env),5m(kernel),-(rootfs)" #define CONFIG_NAND_OMAP_GPMC #define GPMC_NAND_ECC_LP_x16_LAYOUT 1 #define CONFIG_SYS_NAND_BASE (0x08000000) /* physical address */ diff --git a/include/dfu.h b/include/dfu.h index 5350d79450..e856a37ccb 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -52,14 +52,26 @@ struct mmc_internal_data { unsigned int part; }; +struct nand_internal_data { + /* RAW programming */ + u64 start; + u64 size; + + unsigned int dev; + unsigned int part; +}; + static inline unsigned int get_mmc_blk_size(int dev) { return find_mmc_device(dev)->read_bl_len; } -#define DFU_NAME_SIZE 32 -#define DFU_CMD_BUF_SIZE 128 -#define DFU_DATA_BUF_SIZE (1024*1024*4) /* 4 MiB */ +#define DFU_NAME_SIZE 32 +#define DFU_CMD_BUF_SIZE 128 +#define DFU_DATA_BUF_SIZE (64 << 10) /* 64 KiB */ +#ifndef CONFIG_SYS_DFU_MAX_FILE_SIZE +#define CONFIG_SYS_DFU_MAX_FILE_SIZE (4 << 20) /* 4 MiB */ +#endif struct dfu_entity { char name[DFU_NAME_SIZE]; @@ -71,12 +83,32 @@ struct dfu_entity { union { struct mmc_internal_data mmc; + struct nand_internal_data nand; } data; - int (*read_medium)(struct dfu_entity *dfu, void *buf, long *len); - int (*write_medium)(struct dfu_entity *dfu, void *buf, long *len); + int (*read_medium)(struct dfu_entity *dfu, + u64 offset, void *buf, long *len); + + int (*write_medium)(struct dfu_entity *dfu, + u64 offset, void *buf, long *len); + + int (*flush_medium)(struct dfu_entity *dfu); struct list_head list; + + /* on the fly state */ + u32 crc; + u64 offset; + int i_blk_seq_num; + u8 *i_buf; + u8 *i_buf_start; + u8 *i_buf_end; + long r_left; + long b_left; + + u32 bad_skip; /* for nand use */ + + unsigned int inited:1; }; int dfu_config_entities(char *s, char *interface, int num); @@ -100,4 +132,15 @@ static inline int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s) return -1; } #endif + +#ifdef CONFIG_DFU_NAND +extern int dfu_fill_entity_nand(struct dfu_entity *dfu, char *s); +#else +static inline int dfu_fill_entity_nand(struct dfu_entity *dfu, char *s) +{ + puts("NAND support not available!\n"); + return -1; +} +#endif + #endif /* __DFU_ENTITY_H_ */ diff --git a/include/nand.h b/include/nand.h index dded4e27f0..f0f3bf94b5 100644 --- a/include/nand.h +++ b/include/nand.h @@ -129,7 +129,7 @@ struct nand_erase_options { typedef struct nand_erase_options nand_erase_options_t; int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, - u_char *buffer); + size_t *actual, loff_t lim, u_char *buffer); #define WITH_YAFFS_OOB (1 << 0) /* whether write with yaffs format. This flag * is a 'mode' meaning it cannot be mixed with @@ -137,7 +137,7 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, #define WITH_DROP_FFS (1 << 1) /* drop trailing all-0xff pages */ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, - u_char *buffer, int flags); + size_t *actual, loff_t lim, u_char *buffer, int flags); int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts); int nand_torture(nand_info_t *nand, loff_t offset); |