diff options
| -rw-r--r-- | README | 23 | ||||
| -rw-r--r-- | arch/powerpc/cpu/mpc8xxx/fdt.c | 5 | ||||
| -rw-r--r-- | board/cm_t35/cm_t35.c | 2 | ||||
| -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 | 247 | ||||
| -rw-r--r-- | drivers/dfu/dfu_mmc.c | 108 | ||||
| -rw-r--r-- | drivers/dfu/dfu_nand.c | 187 | ||||
| -rw-r--r-- | drivers/mtd/nand/nand_util.c | 68 | ||||
| -rw-r--r-- | include/configs/am335x_evm.h | 52 | ||||
| -rw-r--r-- | include/dfu.h | 53 | ||||
| -rw-r--r-- | include/nand.h | 4 | 
13 files changed, 680 insertions, 128 deletions
| @@ -1344,6 +1344,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/arch/powerpc/cpu/mpc8xxx/fdt.c b/arch/powerpc/cpu/mpc8xxx/fdt.c index 284709428..2db90455f 100644 --- a/arch/powerpc/cpu/mpc8xxx/fdt.c +++ b/arch/powerpc/cpu/mpc8xxx/fdt.c @@ -167,6 +167,11 @@ void fdt_fixup_dr_usb(void *blob, bd_t *bd)  				}  			} +			if (mode_idx < 0 || phy_idx < 0) { +				puts("ERROR: wrong usb mode/phy defined!!\n"); +				return; +			} +  			dr_mode_type = modes[mode_idx];  			dr_phy_type = phys[phy_idx]; diff --git a/board/cm_t35/cm_t35.c b/board/cm_t35/cm_t35.c index 629ce4a50..84c36bafb 100644 --- a/board/cm_t35/cm_t35.c +++ b/board/cm_t35/cm_t35.c @@ -91,6 +91,7 @@ static int splash_load_from_nand(u32 bmp_load_addr)  	res = nand_read_skip_bad(&nand_info[nand_curr_device],  			splash_screen_nand_offset, &bmp_header_size, +			NULL, nand_info[nand_curr_device].size,  			(u_char *)bmp_load_addr);  	if (res < 0)  		return res; @@ -103,6 +104,7 @@ static int splash_load_from_nand(u32 bmp_load_addr)  	return nand_read_skip_bad(&nand_info[nand_curr_device],  			splash_screen_nand_offset, &bmp_size, +			NULL, nand_info[nand_curr_device].size,  			(u_char *)bmp_load_addr);  splash_address_too_high: diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 32348f377..e9d3d3c1b 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;  		} @@ -426,7 +429,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 @@ -551,7 +554,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]; @@ -619,7 +623,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)) { @@ -635,7 +639,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; @@ -645,9 +649,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")) { @@ -655,8 +661,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 @@ -665,9 +671,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 */ @@ -775,7 +781,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)) { @@ -873,7 +880,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); @@ -905,7 +913,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 5b69889c0..b745822be 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 7b717bce2..153095d71 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 e8477fb7c..6af6890d0 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -44,90 +44,232 @@ 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 i_buf: 0x%p\n", -	       __func__, dfu->name, buf, size, blk_seq_num, i_buf); +	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 (blk_seq_num == 0) { -		i_buf = dfu_buf; -		i_blk_seq_num = 0; +	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;  	} -	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; +	} + +	/* 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; +	} + +	/* 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, buf, &dfu->r_left); +		if (ret != 0) { +			debug("%s: failed to get r_left\n", __func__); +			return ret; +		} -	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); +		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; + +		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; +	} -		i_buf = NULL; -		i_blk_seq_num = 0; -		crc = 0; -		return r_size; +	if (ret < size) { +		debug("%s: %s CRC32: 0x%x\n", __func__, dfu->name, dfu->crc); +		puts("\nUPLOAD ... done\nCtrl+C to exit ...\n"); + +		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 +289,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 afd350652..e2f397840 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -22,6 +22,7 @@  #include <common.h>  #include <malloc.h>  #include <errno.h> +#include <div64.h>  #include <dfu.h>  enum dfu_mmc_op { @@ -29,32 +30,51 @@ 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 (blk_start + blk_count > +			dfu->data.mmc.lba_start + 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 int mmc_file_buffer(struct dfu_entity *dfu, void *buf, long *len)  { -	return mmc_block_op(DFU_OP_WRITE, dfu, buf, len); -} +	if (dfu_file_buf_len + *len > CONFIG_SYS_DFU_MAX_FILE_SIZE) { +		dfu_file_buf_len = 0; +		return -EINVAL; +	} -static inline int mmc_block_read(struct dfu_entity *dfu, void *buf, long *len) -{ -	return mmc_block_op(DFU_OP_READ, dfu, buf, len); +	/* 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, @@ -66,20 +86,23 @@ static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu,  	switch (dfu->layout) {  	case DFU_FS_FAT: -		sprintf(cmd_buf, "fat%s mmc %d:%d 0x%x %s %lx", +		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, *len); +			(unsigned int) buf, dfu->name); +		if (op == DFU_OP_WRITE) +			sprintf(cmd_buf + strlen(cmd_buf), " %lx", *len);  		break;  	case DFU_FS_EXT4: -		sprintf(cmd_buf, "ext4%s mmc %d:%d 0x%x /%s %ld", +		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, *len); +			(unsigned int) buf, dfu->name);  		break;  	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); @@ -102,27 +125,18 @@ 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) -{ -	return mmc_file_op(DFU_OP_WRITE, dfu, 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_op(DFU_OP_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__, @@ -132,17 +146,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, &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_op(DFU_OP_READ, dfu, offset, buf, len);  		break;  	case DFU_FS_FAT:  	case DFU_FS_EXT4: -		ret = mmc_file_read(dfu, buf, len); +		ret = mmc_file_op(DFU_OP_READ, dfu, buf, len);  		break;  	default:  		printf("%s: Layout (%s) not (yet) supported!\n", __func__, @@ -181,14 +212,15 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)  		mmc = find_mmc_device(dev);  		if (mmc == NULL || mmc_init(mmc)) { -			printf("%s: could not find mmc device #%d!\n", __func__, dev); +			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); +			       __func__, part, dev);  			return -ENODEV;  		} @@ -208,6 +240,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 000000000..7dc89b2f2 --- /dev/null +++ b/drivers/dfu/dfu_nand.c @@ -0,0 +1,187 @@ +/* + * 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, lim; +	size_t count, actual; +	int ret; +	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; +	lim = dfu->data.nand.start + dfu->data.nand.size - start; +	count = *len; + +	if (nand_curr_device < 0 || +	    nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE || +	    !nand_info[nand_curr_device].name) { +		printf("%s: invalid nand device\n", __func__); +		return -1; +	} + +	nand = &nand_info[nand_curr_device]; + +	if (op == DFU_OP_READ) +		ret = nand_read_skip_bad(nand, start, &count, &actual, +				lim, buf); +	else +		ret = nand_write_skip_bad(nand, start, &count, &actual, +				lim, 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) +		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 ff2d34830..4727f9c98 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -416,11 +416,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; @@ -442,8 +444,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;  } @@ -476,23 +483,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) @@ -529,13 +549,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) @@ -626,36 +656,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/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index b7c443c57..f7f6d2533 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> @@ -60,6 +62,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" \ @@ -167,8 +174,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 @@ -197,6 +204,7 @@  #define CONFIG_CMD_MMC  #define CONFIG_DOS_PARTITION  #define CONFIG_CMD_FAT +#define CONFIG_FAT_WRITE  #define CONFIG_CMD_EXT2  #define CONFIG_CMD_EXT4  #define CONFIG_CMD_FS_GENERIC @@ -209,6 +217,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 */ @@ -353,6 +393,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 @@ -424,6 +465,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 784d8a442..a107f4b13 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*8) /* 8 MiB */ +#define DFU_NAME_SIZE			32 +#define DFU_CMD_BUF_SIZE		128 +#define DFU_DATA_BUF_SIZE		(1024*1024*8)	/* 8 MiB */ +#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 dded4e27f..f0f3bf94b 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); |