Merge branch 'master' of git://git.denx.de/u-boot-usb

- DFU updates
- USB Storage updates
This commit is contained in:
Tom Rini 2019-11-06 07:11:02 -05:00
commit a8c1846633
18 changed files with 992 additions and 87 deletions

View file

@ -442,6 +442,7 @@ config CMD_FITUPD
config CMD_THOR_DOWNLOAD
bool "thor - TIZEN 'thor' download"
select DFU
help
Implements the 'thor' download protocol. This is a way of
downloading a software update over USB from an attached host.

View file

@ -21,23 +21,28 @@
static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
if (argc < 4)
if (argc < 2)
return CMD_RET_USAGE;
#ifdef CONFIG_DFU_OVER_USB
char *usb_controller = argv[1];
#endif
#if defined(CONFIG_DFU_OVER_USB) || defined(CONFIG_DFU_OVER_TFTP)
char *interface = argv[2];
char *devstring = argv[3];
char *interface = NULL;
char *devstring = NULL;
if (argc >= 4) {
interface = argv[2];
devstring = argv[3];
}
#endif
int ret = 0;
#ifdef CONFIG_DFU_OVER_TFTP
unsigned long addr = 0;
if (!strcmp(argv[1], "tftp")) {
if (argc == 5)
addr = simple_strtoul(argv[4], NULL, 0);
if (argc == 5 || argc == 3)
addr = simple_strtoul(argv[argc - 1], NULL, 0);
return update_tftp(addr, interface, devstring);
}
@ -48,7 +53,7 @@ static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
goto done;
ret = CMD_RET_SUCCESS;
if (argc > 4 && strcmp(argv[4], "list") == 0) {
if (strcmp(argv[argc - 1], "list") == 0) {
dfu_show_entities();
goto done;
}
@ -67,7 +72,7 @@ U_BOOT_CMD(dfu, CONFIG_SYS_MAXARGS, 1, do_dfu,
"Device Firmware Upgrade",
""
#ifdef CONFIG_DFU_OVER_USB
"<USB_controller> <interface> <dev> [list]\n"
"<USB_controller> [<interface> <dev>] [list]\n"
" - device firmware upgrade via <USB_controller>\n"
" on device <dev>, attached to interface\n"
" <interface>\n"
@ -77,7 +82,7 @@ U_BOOT_CMD(dfu, CONFIG_SYS_MAXARGS, 1, do_dfu,
#ifdef CONFIG_DFU_OVER_USB
"dfu "
#endif
"tftp <interface> <dev> [<addr>]\n"
"tftp [<interface> <dev>] [<addr>]\n"
" - device firmware upgrade via TFTP\n"
" on device <dev>, attached to interface\n"
" <interface>\n"

View file

@ -40,7 +40,8 @@ int do_thor_down(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
ret = g_dnl_register("usb_dnl_thor");
if (ret) {
pr_err("g_dnl_register failed %d\n", ret);
return ret;
ret = CMD_RET_FAILURE;
goto exit;
}
ret = thor_init();

View file

@ -938,31 +938,32 @@ do_retry:
static void usb_stor_set_max_xfer_blk(struct usb_device *udev,
struct us_data *us)
{
unsigned short blk;
size_t __maybe_unused size;
int __maybe_unused ret;
#if !CONFIG_IS_ENABLED(DM_USB)
#ifdef CONFIG_USB_EHCI_HCD
/*
* The U-Boot EHCI driver can handle any transfer length as long as
* there is enough free heap space left, but the SCSI READ(10) and
* WRITE(10) commands are limited to 65535 blocks.
* Limit the total size of a transfer to 120 KB.
*
* Some devices are known to choke with anything larger. It seems like
* the problem stems from the fact that original IDE controllers had
* only an 8-bit register to hold the number of sectors in one transfer
* and even those couldn't handle a full 256 sectors.
*
* Because we want to make sure we interoperate with as many devices as
* possible, we will maintain a 240 sector transfer size limit for USB
* Mass Storage devices.
*
* Tests show that other operating have similar limits with Microsoft
* Windows 7 limiting transfers to 128 sectors for both USB2 and USB3
* and Apple Mac OS X 10.11 limiting transfers to 256 sectors for USB2
* and 2048 for USB3 devices.
*/
blk = USHRT_MAX;
#else
blk = 20;
#endif
#else
unsigned short blk = 240;
#if CONFIG_IS_ENABLED(DM_USB)
size_t size;
int ret;
ret = usb_get_max_xfer_size(udev, (size_t *)&size);
if (ret < 0) {
/* unimplemented, let's use default 20 */
blk = 20;
} else {
if (size > USHRT_MAX * 512)
size = USHRT_MAX * 512;
if ((ret >= 0) && (size < blk * 512))
blk = size / 512;
}
#endif
us->max_xfer_blk = blk;
@ -1179,6 +1180,7 @@ retry_it:
srb->pdata = (unsigned char *)buf_addr;
if (usb_read_10(srb, ss, start, smallblks)) {
debug("Read ERROR\n");
ss->flags &= ~USB_READY;
usb_request_sense(srb, ss);
if (retry--)
goto retry_it;
@ -1189,7 +1191,6 @@ retry_it:
blks -= smallblks;
buf_addr += srb->datalen;
} while (blks != 0);
ss->flags &= ~USB_READY;
debug("usb_read: end startblk " LBAF ", blccnt %x buffer %lx\n",
start, smallblks, buf_addr);
@ -1264,6 +1265,7 @@ retry_it:
srb->pdata = (unsigned char *)buf_addr;
if (usb_write_10(srb, ss, start, smallblks)) {
debug("Write ERROR\n");
ss->flags &= ~USB_READY;
usb_request_sense(srb, ss);
if (retry--)
goto retry_it;
@ -1274,7 +1276,6 @@ retry_it:
blks -= smallblks;
buf_addr += srb->datalen;
} while (blks != 0);
ss->flags &= ~USB_READY;
debug("usb_write: end startblk " LBAF ", blccnt %x buffer %lx\n",
start, smallblks, buf_addr);
@ -1469,10 +1470,10 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
memset(pccb->pdata, 0, 8);
if (usb_read_capacity(pccb, ss) != 0) {
printf("READ_CAP ERROR\n");
ss->flags &= ~USB_READY;
cap[0] = 2880;
cap[1] = 0x200;
}
ss->flags &= ~USB_READY;
debug("Read Capacity returns: 0x%08x, 0x%08x\n", cap[0], cap[1]);
#if 0
if (cap[0] > (0x200000 * 10)) /* greater than 10 GByte */

270
doc/README.dfu Normal file
View file

@ -0,0 +1,270 @@
# SPDX-License-Identifier: GPL-2.0+
Device Firmware Upgrade (DFU)
Overview:
The Device Firmware Upgrade (DFU) allows to download and upload firmware
to/from U-Boot connected over USB.
U-boot follows the Universal Serial Bus Device Class Specification for
Device Firmware Upgrade Version 1.1 the USB forum (DFU v1.1 in www.usb.org).
U-Boot implements this DFU capability (CONFIG_DFU) with the command dfu
(cmd/dfu.c / CONFIG_CMD_DFU) based on:
- the DFU stack (common/dfu.c and common/spl/spl_dfu.c), based on the
USB DFU download gadget (drivers/usb/gadget/f_dfu.c)
- The access to mediums is done in DFU backends (driver/dfu)
Today the supported DFU backends are:
- MMC (RAW or FAT / EXT2 / EXT3 / EXT4 file system)
- NAND
- RAM
- SF (serial flash)
- MTD (all MTD device: NAND, SPI-NOR, SPI-NAND,...)
- virtual
These DFU backends are also used by
- the dfutftp (see README.dfutftp)
- the thordown command (cmd/thordown.c and gadget/f_thor.c)
The "virtual" backend is a generic DFU backend to support a board specific
target (for example OTP), only based on the weak functions:
- dfu_write_medium_virt
- dfu_get_medium_size_virt
- dfu_read_medium_virt
Configuration Options:
CONFIG_DFU
CONFIG_DFU_OVER_USB
CONFIG_DFU_MMC
CONFIG_DFU_MTD
CONFIG_DFU_NAND
CONFIG_DFU_RAM
CONFIG_DFU_SF
CONFIG_DFU_SF_PART
CONFIG_DFU_VIRTUAL
CONFIG_CMD_DFU
Environment variables:
the dfu command use 3 environments variables:
"dfu_alt_info" : the DFU setting for the USB download gadget with a comma
separated string of information on each alternate:
dfu_alt_info="<alt1>;<alt2>;....;<altN>"
when only several device are used, the format is:
- <interface> <dev>'='alternate list (';' separated)
- each interface is separated by '&'
dfu_alt_info=\
"<interface1> <dev1>=<alt1>;....;<altN>&"\
"<interface2> <dev2>=<altN+1>;....;<altM>&"\
...\
"<interfaceI> <devI>=<altY+1>;....;<altZ>&"
"dfu_bufsiz" : size of the DFU buffer, when absent, use
CONFIG_SYS_DFU_DATA_BUF_SIZE (8MiB by default)
"dfu_hash_algo" : name of the hash algorithm to use
Commands:
dfu <USB_controller> [<interface> <dev>] list
list the alternate device defined in "dfu_alt_info"
dfu <USB_controller> [<interface> <dev>]
start the dfu stack on the USB instance with the selected medium
backend and use the "dfu_alt_info" variable to configure the
alternate setting and link each one with the medium
The dfu command continue until receive a ^C in console or
a DFU detach transaction from HOST.
The possible values of <interface> are :
(with <USB controller> = 0 in the dfu command example)
"mmc" (for eMMC and SD card)
cmd: dfu 0 mmc <dev>
each element in "dfu_alt_info" =
<name> raw <offset> <size> raw access to mmc device
<name> part <dev> <part_id> raw acces to partition
<name> fat <dev> <part_id> file in FAT partition
<name> ext4 <dev> <part_id> file in EXT4 partition
with <partid> is the GPT or DOS partition index
"nand" (raw slc nand device)
cmd: dfu 0 nand <dev>
each element in "dfu_alt_info" =
<name> raw <offset> <size> raw access to mmc device
<name> part <dev> <part_id> raw acces to partition
<name> partubi <dev> <part_id> raw acces to ubi partition
with <partid> is the MTD partition index
"ram"
cmd: dfu 0 ram <dev>
(<dev> is not used for RAM target)
each element in "dfu_alt_info" =
<name> ram <offset> <size> raw access to ram
"sf" (serial flash : NOR)
cmd: dfu 0 sf <dev>
each element in "dfu_alt_info" =
<name> ram <offset> <size> raw access to sf device
<name> part <dev> <part_id> raw acces to partition
<name> partubi <dev> <part_id> raw acces to ubi partition
with <partid> is the MTD partition index
"mtd" (all MTD device: NAND, SPI-NOR, SPI-NAND,...)
cmd: dfu 0 mtd <dev>
with <dev> the mtd identifier as defined in mtd command
(nand0, nor0, spi-nand0,...)
each element in "dfu_alt_info" =
<name> raw <offset> <size> raw access to mtd device
<name> part <dev> <part_id> raw acces to partition
<name> partubi <dev> <part_id> raw acces to ubi partition
with <partid> is the MTD partition index
"virt"
cmd: dfu 0 virt <dev>
each element in "dfu_alt_info" =
<name>
<interface> and <dev> are absent:
the dfu command to use multiple devices
cmd: dfu 0 list
cmd: dfu 0
"dfu_alt_info" variable provides the list of <interface> <dev> with
alternate list separated by '&' with the same format for each <alt>
mmc <dev>=<alt1>;....;<altN>
nand <dev>=<alt1>;....;<altN>
ram <dev>=<alt1>;....;<altN>
sf <dev>=<alt1>;....;<altN>
mtd <dev>=<alt1>;....;<altN>
virt <dev>=<alt1>;....;<altN>
Callbacks:
The weak callback functions can be implemented to manage specific behavior
- dfu_initiated_callback : called when the DFU transaction is started,
used to initiase the device
- dfu_flush_callback : called at the end of the DFU write after DFU
manifestation, used to manage the device when
DFU transaction is closed
Host tools:
When U-Boot runs the dfu stack, the DFU host tools can be used
to send/receive firmwares on each configurated alternate.
For example dfu-util is a host side implementation of the DFU 1.1
specifications(http://dfu-util.sourceforge.net/) which works with U-Boot.
Usage:
Example 1: firmware located in eMMC or SD card, with:
- alternate 1 (alt=1) for SPL partition (GPT partition 1)
- alternate 2 (alt=2) for U-Boot partition (GPT partition 2)
The U-Boot configuration is:
U-Boot> env set dfu_alt_info "spl part 0 1;u-boot part 0 2"
U-Boot> dfu 0 mmc 0 list
DFU alt settings list:
dev: eMMC alt: 0 name: spl layout: RAW_ADDR
dev: eMMC alt: 1 name: u-boot layout: RAW_ADDR
Boot> dfu 0 mmc 0
On the Host side:
list the available alternate setting:
$> dfu-util -l
dfu-util 0.9
Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/
Found DFU: [0483:5720] ver=0200, devnum=45, cfg=1, intf=0, path="3-1.3.1", \
alt=1, name="u-boot", serial="003A00203438510D36383238"
Found DFU: [0483:5720] ver=0200, devnum=45, cfg=1, intf=0, path="3-1.3.1", \
alt=0, name="spl", serial="003A00203438510D36383238"
To download to U-Boot, use -D option
$> dfu-util -a 0 -D u-boot-spl.bin
$> dfu-util -a 1 -D u-boot.bin
To upload from U-Boot, use -U option
$> dfu-util -a 0 -U u-boot-spl.bin
$> dfu-util -a 1 -U u-boot.bin
To request a DFU detach and reset the USB connection:
$> dfu-util -a 0 -e -R
Example 2: firmware located in NOR (sf) and NAND, with:
- alternate 1 (alt=1) for SPL partition (NOR GPT partition 1)
- alternate 2 (alt=2) for U-Boot partition (NOR GPT partition 2)
- alternate 3 (alt=3) for U-Boot-env partition (NOR GPT partition 3)
- alternate 4 (alt=4) for UBI partition (NAND GPT partition 1)
U-Boot> env set dfu_alt_info \
"sf 0:0:10000000:0=spl part 0 1;u-boot part 0 2; \
u-boot-env part 0 3&nand 0=UBI partubi 0,1"
U-Boot> dfu 0 list
DFU alt settings list:
dev: SF alt: 0 name: spl layout: RAW_ADDR
dev: SF alt: 1 name: ssbl layout: RAW_ADDR
dev: SF alt: 2 name: u-boot-env layout: RAW_ADDR
dev: NAND alt: 3 name: UBI layout: RAW_ADDR
U-Boot> dfu 0
$> dfu-util -l
Found DFU: [0483:5720] ver=9999, devnum=96, cfg=1,\
intf=0, alt=3, name="UBI", serial="002700333338511934383330"
Found DFU: [0483:5720] ver=9999, devnum=96, cfg=1,\
intf=0, alt=2, name="u-boot-env", serial="002700333338511934383330"
Found DFU: [0483:5720] ver=9999, devnum=96, cfg=1,\
intf=0, alt=1, name="u-boot", serial="002700333338511934383330"
Found DFU: [0483:5720] ver=9999, devnum=96, cfg=1,\
intf=0, alt=0, name="spl", serial="002700333338511934383330"
Same example with MTD backend
U-Boot> env set dfu_alt_info \
"mtd nor0=spl part 1;u-boot part 2;u-boot-env part 3&"\
"mtd nand0=UBI partubi 1"
U-Boot> dfu 0 list
using id 'nor0,0'
using id 'nor0,1'
using id 'nor0,2'
using id 'nand0,0'
DFU alt settings list:
dev: MTD alt: 0 name: spl layout: RAW_ADDR
dev: MTD alt: 1 name: u-boot layout: RAW_ADDR
dev: MTD alt: 2 name: u-boot-env layout: RAW_ADDR
dev: MTD alt: 3 name: UBI layout: RAW_ADDR
Example 3: firmware located in SD Card (mmc) and virtual partition on
OTP and PMIC not volatile memory
- alternate 1 (alt=1) for scard
- alternate 2 (alt=2) for OTP (virtual)
- alternate 3 (alt=3) for PMIC NVM (virtual)
U-Boot> env set dfu_alt_info \
"mmc 0=sdcard raw 0 0x100000&"\
"virt 0=otp" \
"virt 1=pmic"
U-Boot> dfu 0 list
DFU alt settings list:
dev: eMMC alt: 0 name: sdcard layout: RAW_ADDR
dev: VIRT alt: 1 name: otp layout: RAW_ADDR
dev: VIRT alt: 2 name: pmic layout: RAW_ADDR

View file

@ -46,5 +46,26 @@ config DFU_SF
This option enables using DFU to read and write to SPI flash based
storage.
config DFU_SF_PART
bool "MTD partition support for SPI flash back end"
depends on DFU_SF && CMD_MTDPARTS
default y
help
This option enables the support of "part" and "partubi" target in
SPI flash DFU back end.
config DFU_MTD
bool "MTD back end for DFU"
depends on MTD
help
This option enables using DFU to read and write to on any MTD device.
config DFU_VIRT
bool "VIRTUAL flash back end for DFU"
help
This option enables using DFU to read and write to VIRTUAL device
used at board level to manage specific behavior
(OTP update for example).
endif
endmenu

View file

@ -5,7 +5,9 @@
obj-$(CONFIG_$(SPL_)DFU) += dfu.o
obj-$(CONFIG_$(SPL_)DFU_MMC) += dfu_mmc.o
obj-$(CONFIG_$(SPL_)DFU_MTD) += dfu_mtd.o
obj-$(CONFIG_$(SPL_)DFU_NAND) += dfu_nand.o
obj-$(CONFIG_$(SPL_)DFU_RAM) += dfu_ram.o
obj-$(CONFIG_$(SPL_)DFU_SF) += dfu_sf.o
obj-$(CONFIG_$(SPL_)DFU_TFTP) += dfu_tftp.o
obj-$(CONFIG_$(SPL_)DFU_VIRT) += dfu_virt.o

View file

@ -22,6 +22,22 @@ static int dfu_alt_num;
static int alt_num_cnt;
static struct hash_algo *dfu_hash_algo;
/*
* The purpose of the dfu_flush_callback() function is to
* provide callback for dfu user
*/
__weak void dfu_flush_callback(struct dfu_entity *dfu)
{
}
/*
* The purpose of the dfu_initiated_callback() function is to
* provide callback for dfu user
*/
__weak void dfu_initiated_callback(struct dfu_entity *dfu)
{
}
/*
* The purpose of the dfu_usb_get_reset() function is to
* provide information if after USB_DETACH request
@ -53,6 +69,54 @@ static int dfu_find_alt_num(const char *s)
return ++i;
}
/*
* treat dfu_alt_info with several interface information
* to allow DFU on several device with one command,
* the string format is
* interface devstring'='alternate list (';' separated)
* and each interface separated by '&'
*/
int dfu_config_interfaces(char *env)
{
struct dfu_entity *dfu;
char *s, *i, *d, *a, *part;
int ret = -EINVAL;
int n = 1;
s = env;
for (; *s; s++) {
if (*s == ';')
n++;
if (*s == '&')
n++;
}
ret = dfu_alt_init(n, &dfu);
if (ret)
return ret;
s = env;
while (s) {
ret = -EINVAL;
i = strsep(&s, " ");
if (!i)
break;
d = strsep(&s, "=");
if (!d)
break;
a = strsep(&s, "&");
if (!a)
a = s;
do {
part = strsep(&a, ";");
ret = dfu_alt_add(dfu, i, d, part);
if (ret)
return ret;
} while (a);
}
return ret;
}
int dfu_init_env_entities(char *interface, char *devstr)
{
const char *str_env;
@ -69,7 +133,11 @@ int dfu_init_env_entities(char *interface, char *devstr)
}
env_bkp = strdup(str_env);
ret = dfu_config_entities(env_bkp, interface, devstr);
if (!interface && !devstr)
ret = dfu_config_interfaces(env_bkp);
else
ret = dfu_config_entities(env_bkp, interface, devstr);
if (ret) {
pr_err("DFU entities configuration failed!\n");
pr_err("(partition table does not match dfu_alt_info?)\n");
@ -83,6 +151,7 @@ done:
static unsigned char *dfu_buf;
static unsigned long dfu_buf_size;
static enum dfu_device_type dfu_buf_device_type;
unsigned char *dfu_free_buf(void)
{
@ -100,6 +169,10 @@ unsigned char *dfu_get_buf(struct dfu_entity *dfu)
{
char *s;
/* manage several entity with several contraint */
if (dfu_buf && dfu->dev_type != dfu_buf_device_type)
dfu_free_buf();
if (dfu_buf != NULL)
return dfu_buf;
@ -118,6 +191,7 @@ unsigned char *dfu_get_buf(struct dfu_entity *dfu)
printf("%s: Could not memalign 0x%lx bytes\n",
__func__, dfu_buf_size);
dfu_buf_device_type = dfu->dev_type;
return dfu_buf;
}
@ -205,6 +279,7 @@ int dfu_transaction_initiate(struct dfu_entity *dfu, bool read)
}
dfu->inited = 1;
dfu_initiated_callback(dfu);
return 0;
}
@ -224,6 +299,8 @@ int dfu_flush(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num)
printf("\nDFU complete %s: 0x%08x\n", dfu_hash_algo->name,
dfu->crc);
dfu_flush_callback(dfu);
dfu_transaction_cleanup(dfu);
return ret;
@ -338,6 +415,8 @@ static int dfu_read_buffer_fill(struct dfu_entity *dfu, void *buf, int size)
debug("%s: Read error!\n", __func__);
return ret;
}
if (dfu->b_left == 0)
break;
dfu->offset += dfu->b_left;
dfu->r_left -= dfu->b_left;
@ -402,6 +481,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, devstr, s))
return -1;
} else if (strcmp(interface, "mtd") == 0) {
if (dfu_fill_entity_mtd(dfu, devstr, s))
return -1;
} else if (strcmp(interface, "nand") == 0) {
if (dfu_fill_entity_nand(dfu, devstr, s))
return -1;
@ -411,6 +493,9 @@ static int dfu_fill_entity(struct dfu_entity *dfu, char *s, int alt,
} else if (strcmp(interface, "sf") == 0) {
if (dfu_fill_entity_sf(dfu, devstr, s))
return -1;
} else if (strcmp(interface, "virt") == 0) {
if (dfu_fill_entity_virt(dfu, devstr, s))
return -1;
} else {
printf("%s: Device %s not (yet) supported!\n",
__func__, interface);
@ -439,13 +524,12 @@ void dfu_free_entities(void)
alt_num_cnt = 0;
}
int dfu_config_entities(char *env, char *interface, char *devstr)
int dfu_alt_init(int num, struct dfu_entity **dfu)
{
struct dfu_entity *dfu;
int i, ret;
char *s;
int ret;
dfu_alt_num = dfu_find_alt_num(env);
dfu_alt_num = num;
debug("%s: dfu_alt_num=%d\n", __func__, dfu_alt_num);
dfu_hash_algo = NULL;
@ -456,21 +540,49 @@ int dfu_config_entities(char *env, char *interface, char *devstr)
pr_err("Hash algorithm %s not supported\n", s);
}
dfu = calloc(sizeof(*dfu), dfu_alt_num);
if (!dfu)
*dfu = calloc(sizeof(struct dfu_entity), dfu_alt_num);
if (!*dfu)
return -1;
for (i = 0; i < dfu_alt_num; i++) {
return 0;
}
int dfu_alt_add(struct dfu_entity *dfu, char *interface, char *devstr, char *s)
{
struct dfu_entity *p_dfu;
int ret;
if (alt_num_cnt >= dfu_alt_num)
return -1;
p_dfu = &dfu[alt_num_cnt];
ret = dfu_fill_entity(p_dfu, s, alt_num_cnt, interface, devstr);
if (ret)
return -1;
list_add_tail(&p_dfu->list, &dfu_list);
alt_num_cnt++;
return 0;
}
int dfu_config_entities(char *env, char *interface, char *devstr)
{
struct dfu_entity *dfu;
int i, ret;
char *s;
ret = dfu_alt_init(dfu_find_alt_num(env), &dfu);
if (ret)
return -1;
for (i = 0; i < dfu_alt_num; i++) {
s = strsep(&env, ";");
ret = dfu_fill_entity(&dfu[i], s, alt_num_cnt, interface,
devstr);
ret = dfu_alt_add(dfu, interface, devstr, s);
if (ret) {
/* We will free "dfu" in dfu_free_entities() */
return -1;
}
list_add_tail(&dfu[i].list, &dfu_list);
alt_num_cnt++;
}
return 0;
@ -478,14 +590,15 @@ int dfu_config_entities(char *env, char *interface, char *devstr)
const char *dfu_get_dev_type(enum dfu_device_type t)
{
const char *dev_t[] = {NULL, "eMMC", "OneNAND", "NAND", "RAM", "SF" };
const char *const dev_t[] = {NULL, "eMMC", "OneNAND", "NAND", "RAM",
"SF", "MTD", "VIRT"};
return dev_t[t];
}
const char *dfu_get_layout(enum dfu_layout l)
{
const char *dfu_layout[] = {NULL, "RAW_ADDR", "FAT", "EXT2",
"EXT3", "EXT4", "RAM_ADDR" };
const char *const dfu_layout[] = {NULL, "RAW_ADDR", "FAT", "EXT2",
"EXT3", "EXT4", "RAM_ADDR" };
return dfu_layout[l];
}

View file

@ -352,6 +352,7 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s)
struct blk_desc *blk_dev = mmc_get_blk_desc(mmc);
int mmcdev = second_arg;
int mmcpart = third_arg;
int offset = 0;
if (part_get_info(blk_dev, mmcpart, &partinfo) != 0) {
pr_err("Couldn't find part #%d on mmc device #%d\n",
@ -359,9 +360,17 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s)
return -ENODEV;
}
/*
* Check for an extra entry at dfu_alt_info env variable
* specifying the mmc HW defined partition number
*/
if (s)
if (!strcmp(strsep(&s, " "), "offset"))
offset = simple_strtoul(s, NULL, 0);
dfu->layout = DFU_RAW_ADDR;
dfu->data.mmc.lba_start = partinfo.start;
dfu->data.mmc.lba_size = partinfo.size;
dfu->data.mmc.lba_start = partinfo.start + offset;
dfu->data.mmc.lba_size = partinfo.size-offset;
dfu->data.mmc.lba_blk_size = partinfo.blksz;
} else if (!strcmp(entity_type, "fat")) {
dfu->layout = DFU_FS_FAT;

311
drivers/dfu/dfu_mtd.c Normal file
View file

@ -0,0 +1,311 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* dfu_mtd.c -- DFU for MTD device.
*
* Copyright (C) 2019,STMicroelectronics - All Rights Reserved
*
* Based on dfu_nand.c
*/
#include <common.h>
#include <dfu.h>
#include <mtd.h>
#include <jffs2/load_kernel.h>
static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
{
return !do_div(size, mtd->erasesize);
}
static int mtd_block_op(enum dfu_op op, struct dfu_entity *dfu,
u64 offset, void *buf, long *len)
{
u64 off, lim, remaining;
struct mtd_info *mtd = dfu->data.mtd.info;
struct mtd_oob_ops io_op = {};
int ret = 0;
bool has_pages = mtd->type == MTD_NANDFLASH ||
mtd->type == MTD_MLCNANDFLASH;
/* if buf == NULL return total size of the area */
if (!buf) {
*len = dfu->data.mtd.size;
return 0;
}
off = dfu->data.mtd.start + offset + dfu->bad_skip;
lim = dfu->data.mtd.start + dfu->data.mtd.size;
if (off >= lim) {
printf("Limit reached 0x%llx\n", lim);
*len = 0;
return op == DFU_OP_READ ? 0 : -EIO;
}
/* limit request with the available size */
if (off + *len >= lim)
*len = lim - off;
if (!mtd_is_aligned_with_block_size(mtd, off)) {
printf("Offset not aligned with a block (0x%x)\n",
mtd->erasesize);
return 0;
}
/* first erase */
if (op == DFU_OP_WRITE) {
struct erase_info erase_op = {};
remaining = round_up(*len, mtd->erasesize);
erase_op.mtd = mtd;
erase_op.addr = off;
erase_op.len = mtd->erasesize;
erase_op.scrub = 0;
while (remaining) {
if (erase_op.addr + remaining > lim) {
printf("Limit reached 0x%llx while erasing at offset 0x%llx\n",
lim, off);
return -EIO;
}
ret = mtd_erase(mtd, &erase_op);
if (ret) {
/* Abort if its not a bad block error */
if (ret != -EIO) {
printf("Failure while erasing at offset 0x%llx\n",
erase_op.fail_addr);
return 0;
}
printf("Skipping bad block at 0x%08llx\n",
erase_op.addr);
} else {
remaining -= mtd->erasesize;
}
/* Continue erase behind bad block */
erase_op.addr += mtd->erasesize;
}
}
io_op.mode = MTD_OPS_AUTO_OOB;
io_op.len = *len;
if (has_pages && io_op.len > mtd->writesize)
io_op.len = mtd->writesize;
io_op.ooblen = 0;
io_op.datbuf = buf;
io_op.oobbuf = NULL;
/* Loop over to do the actual read/write */
remaining = *len;
while (remaining) {
if (off + remaining > lim) {
printf("Limit reached 0x%llx while %s at offset 0x%llx\n",
lim, op == DFU_OP_READ ? "reading" : "writing",
off);
if (op == DFU_OP_READ) {
*len -= remaining;
return 0;
} else {
return -EIO;
}
}
/* Skip the block if it is bad */
if (mtd_is_aligned_with_block_size(mtd, off) &&
mtd_block_isbad(mtd, off)) {
off += mtd->erasesize;
dfu->bad_skip += mtd->erasesize;
continue;
}
if (op == DFU_OP_READ)
ret = mtd_read_oob(mtd, off, &io_op);
else
ret = mtd_write_oob(mtd, off, &io_op);
if (ret) {
printf("Failure while %s at offset 0x%llx\n",
op == DFU_OP_READ ? "reading" : "writing", off);
return -EIO;
}
off += io_op.retlen;
remaining -= io_op.retlen;
io_op.datbuf += io_op.retlen;
io_op.len = remaining;
if (has_pages && io_op.len > mtd->writesize)
io_op.len = mtd->writesize;
}
return ret;
}
static int dfu_get_medium_size_mtd(struct dfu_entity *dfu, u64 *size)
{
*size = dfu->data.mtd.info->size;
return 0;
}
static int dfu_read_medium_mtd(struct dfu_entity *dfu, u64 offset, void *buf,
long *len)
{
int ret = -1;
switch (dfu->layout) {
case DFU_RAW_ADDR:
ret = mtd_block_op(DFU_OP_READ, 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_write_medium_mtd(struct dfu_entity *dfu,
u64 offset, void *buf, long *len)
{
int ret = -1;
switch (dfu->layout) {
case DFU_RAW_ADDR:
ret = mtd_block_op(DFU_OP_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_flush_medium_mtd(struct dfu_entity *dfu)
{
struct mtd_info *mtd = dfu->data.mtd.info;
u64 remaining;
int ret;
/* in case of ubi partition, erase rest of the partition */
if (dfu->data.nand.ubi) {
struct erase_info erase_op = {};
erase_op.mtd = dfu->data.mtd.info;
erase_op.addr = round_up(dfu->data.mtd.start + dfu->offset +
dfu->bad_skip, mtd->erasesize);
erase_op.len = mtd->erasesize;
erase_op.scrub = 0;
remaining = dfu->data.mtd.start + dfu->data.mtd.size -
erase_op.addr;
while (remaining) {
ret = mtd_erase(mtd, &erase_op);
if (ret) {
/* Abort if its not a bad block error */
if (ret != -EIO)
break;
printf("Skipping bad block at 0x%08llx\n",
erase_op.addr);
}
/* Skip bad block and continue behind it */
erase_op.addr += mtd->erasesize;
remaining -= mtd->erasesize;
}
}
return 0;
}
static unsigned int dfu_polltimeout_mtd(struct dfu_entity *dfu)
{
/*
* Currently, Poll Timeout != 0 is only needed on nand
* ubi partition, as sectors which are not used need
* to be erased
*/
if (dfu->data.nand.ubi)
return DFU_MANIFEST_POLL_TIMEOUT;
return DFU_DEFAULT_POLL_TIMEOUT;
}
int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char *s)
{
char *st;
struct mtd_info *mtd;
bool has_pages;
int ret, part;
mtd = get_mtd_device_nm(devstr);
if (IS_ERR_OR_NULL(mtd))
return -ENODEV;
put_mtd_device(mtd);
dfu->dev_type = DFU_DEV_MTD;
dfu->data.mtd.info = mtd;
has_pages = mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH;
dfu->max_buf_size = has_pages ? mtd->erasesize : 0;
st = strsep(&s, " ");
if (!strcmp(st, "raw")) {
dfu->layout = DFU_RAW_ADDR;
dfu->data.mtd.start = simple_strtoul(s, &s, 16);
s++;
dfu->data.mtd.size = simple_strtoul(s, &s, 16);
} else if ((!strcmp(st, "part")) || (!strcmp(st, "partubi"))) {
char mtd_id[32];
struct mtd_device *mtd_dev;
u8 part_num;
struct part_info *pi;
dfu->layout = DFU_RAW_ADDR;
part = simple_strtoul(s, &s, 10);
sprintf(mtd_id, "%s,%d", devstr, 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.mtd.start = pi->offset;
dfu->data.mtd.size = pi->size;
if (!strcmp(st, "partubi"))
dfu->data.mtd.ubi = 1;
} else {
printf("%s: Memory layout (%s) not supported!\n", __func__, st);
return -1;
}
if (!mtd_is_aligned_with_block_size(mtd, dfu->data.mtd.start)) {
printf("Offset not aligned with a block (0x%x)\n",
mtd->erasesize);
return -EINVAL;
}
if (!mtd_is_aligned_with_block_size(mtd, dfu->data.mtd.size)) {
printf("Size not aligned with a block (0x%x)\n",
mtd->erasesize);
return -EINVAL;
}
dfu->get_medium_size = dfu_get_medium_size_mtd;
dfu->read_medium = dfu_read_medium_mtd;
dfu->write_medium = dfu_write_medium_mtd;
dfu->flush_medium = dfu_flush_medium_mtd;
dfu->poll_timeout = dfu_polltimeout_mtd;
/* initial state */
dfu->inited = 0;
return 0;
}

View file

@ -214,7 +214,7 @@ int dfu_fill_entity_nand(struct dfu_entity *dfu, char *devstr, char *s)
part = simple_strtoul(s, &s, 10);
sprintf(mtd_id, "%s%d,%d", "nand", dev, part - 1);
printf("using id '%s'\n", mtd_id);
debug("using id '%s'\n", mtd_id);
mtdparts_init();

View file

@ -10,6 +10,8 @@
#include <dfu.h>
#include <spi.h>
#include <spi_flash.h>
#include <jffs2/load_kernel.h>
#include <linux/mtd/mtd.h>
static int dfu_get_medium_size_sf(struct dfu_entity *dfu, u64 *size)
{
@ -19,7 +21,7 @@ static int dfu_get_medium_size_sf(struct dfu_entity *dfu, u64 *size)
}
static int dfu_read_medium_sf(struct dfu_entity *dfu, u64 offset, void *buf,
long *len)
long *len)
{
return spi_flash_read(dfu->data.sf.dev, dfu->data.sf.start + offset,
*len, buf);
@ -32,7 +34,7 @@ static u64 find_sector(struct dfu_entity *dfu, u64 start, u64 offset)
}
static int dfu_write_medium_sf(struct dfu_entity *dfu,
u64 offset, void *buf, long *len)
u64 offset, void *buf, long *len)
{
int ret;
@ -52,11 +54,33 @@ static int dfu_write_medium_sf(struct dfu_entity *dfu,
static int dfu_flush_medium_sf(struct dfu_entity *dfu)
{
u64 off, length;
if (!CONFIG_IS_ENABLED(DFU_SF_PART) || !dfu->data.sf.ubi)
return 0;
/* in case of ubi partition, erase rest of the partition */
off = find_sector(dfu, dfu->data.sf.start, dfu->offset);
/* last write ended with unaligned length jump to next */
if (off != dfu->data.sf.start + dfu->offset)
off += dfu->data.sf.dev->sector_size;
length = dfu->data.sf.start + dfu->data.sf.size - off;
if (length)
return spi_flash_erase(dfu->data.sf.dev, off, length);
return 0;
}
static unsigned int dfu_polltimeout_sf(struct dfu_entity *dfu)
{
/*
* Currently, Poll Timeout != 0 is only needed on nand
* ubi partition, as sectors which are not used need
* to be erased
*/
if (CONFIG_IS_ENABLED(DFU_SF_PART) && dfu->data.sf.ubi)
return DFU_MANIFEST_POLL_TIMEOUT;
return DFU_DEFAULT_POLL_TIMEOUT;
}
@ -133,6 +157,34 @@ int dfu_fill_entity_sf(struct dfu_entity *dfu, char *devstr, char *s)
dfu->data.sf.start = simple_strtoul(s, &s, 16);
s++;
dfu->data.sf.size = simple_strtoul(s, &s, 16);
} else if (CONFIG_IS_ENABLED(DFU_SF_PART) &&
(!strcmp(st, "part") || !strcmp(st, "partubi"))) {
char mtd_id[32];
struct mtd_device *mtd_dev;
u8 part_num;
struct part_info *pi;
int ret, dev, part;
dfu->layout = DFU_RAW_ADDR;
dev = simple_strtoul(s, &s, 10);
s++;
part = simple_strtoul(s, &s, 10);
sprintf(mtd_id, "%s%d,%d", "nor", 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.sf.start = pi->offset;
dfu->data.sf.size = pi->size;
if (!strcmp(st, "partubi"))
dfu->data.sf.ubi = 1;
} else {
printf("%s: Memory layout (%s) not supported!\n", __func__, st);
spi_flash_free(dfu->data.sf.dev);

49
drivers/dfu/dfu_virt.c Normal file
View file

@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
/*
* Copyright (C) 2019, STMicroelectronics - All Rights Reserved
*/
#include <common.h>
#include <dfu.h>
#include <errno.h>
#include <malloc.h>
int __weak dfu_write_medium_virt(struct dfu_entity *dfu, u64 offset,
void *buf, long *len)
{
debug("%s: off=0x%llx, len=0x%x\n", __func__, offset, (u32)*len);
return 0;
}
int __weak dfu_get_medium_size_virt(struct dfu_entity *dfu, u64 *size)
{
*size = 0;
return 0;
}
int __weak dfu_read_medium_virt(struct dfu_entity *dfu, u64 offset,
void *buf, long *len)
{
debug("%s: off=0x%llx, len=0x%x\n", __func__, offset, (u32)*len);
*len = 0;
return 0;
}
int dfu_fill_entity_virt(struct dfu_entity *dfu, char *devstr, char *s)
{
debug("%s: devstr = %s\n", __func__, devstr);
dfu->dev_type = DFU_DEV_VIRT;
dfu->layout = DFU_RAW_ADDR;
dfu->data.virt.dev_num = simple_strtoul(devstr, NULL, 10);
dfu->write_medium = dfu_write_medium_virt;
dfu->get_medium_size = dfu_get_medium_size_virt;
dfu->read_medium = dfu_read_medium_virt;
dfu->inited = 0;
return 0;
}

View file

@ -338,7 +338,7 @@ static int dwc3_glue_reset_init(struct udevice *dev,
int ret;
ret = reset_get_bulk(dev, &glue->resets);
if (ret == -ENOTSUPP)
if (ret == -ENOTSUPP || ret == -ENOENT)
return 0;
else if (ret)
return ret;
@ -358,7 +358,7 @@ static int dwc3_glue_clk_init(struct udevice *dev,
int ret;
ret = clk_get_bulk(dev, &glue->clks);
if (ret == -ENOSYS)
if (ret == -ENOSYS || ret == -ENOENT)
return 0;
if (ret)
return ret;

View file

@ -242,7 +242,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
list_del(&req->list);
req->trb = NULL;
dwc3_flush_cache((uintptr_t)req->request.dma, req->request.length);
if (req->request.length)
dwc3_flush_cache((uintptr_t)req->request.dma, req->request.length);
if (req->request.status == -EINPROGRESS)
req->request.status = status;

View file

@ -941,6 +941,13 @@ static int thor_eps_setup(struct usb_function *f)
dev->out_req = req;
/* ACM control EP */
ep = dev->int_ep;
d = ep_desc(gadget, &hs_int_desc, &fs_int_desc);
debug("(d)bEndpointAddress: 0x%x\n", d->bEndpointAddress);
result = usb_ep_enable(ep, d);
if (result)
goto err;
ep->driver_data = cdev; /* claim */
return 0;

View file

@ -307,7 +307,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
volatile struct qTD *vtd;
unsigned long ts;
uint32_t *tdp;
uint32_t endpt, maxpacket, token, usbsts;
uint32_t endpt, maxpacket, token, usbsts, qhtoken;
uint32_t c, toggle;
uint32_t cmd;
int timeout;
@ -551,22 +551,21 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
flush_dcache_range((unsigned long)qtd,
ALIGN_END_ADDR(struct qTD, qtd, qtd_count));
/* Set async. queue head pointer. */
ehci_writel(&ctrl->hcor->or_asynclistaddr, virt_to_phys(&ctrl->qh_list));
usbsts = ehci_readl(&ctrl->hcor->or_usbsts);
ehci_writel(&ctrl->hcor->or_usbsts, (usbsts & 0x3f));
/* Enable async. schedule. */
cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
cmd |= CMD_ASE;
ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
if (!(cmd & CMD_ASE)) {
cmd |= CMD_ASE;
ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
ret = handshake((uint32_t *)&ctrl->hcor->or_usbsts, STS_ASS, STS_ASS,
100 * 1000);
if (ret < 0) {
printf("EHCI fail timeout STS_ASS set\n");
goto fail;
ret = handshake((uint32_t *)&ctrl->hcor->or_usbsts, STS_ASS, STS_ASS,
100 * 1000);
if (ret < 0) {
printf("EHCI fail timeout STS_ASS set\n");
goto fail;
}
}
/* Wait for TDs to be processed. */
@ -587,6 +586,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
break;
WATCHDOG_RESET();
} while (get_timer(ts) < timeout);
qhtoken = hc32_to_cpu(qh->qh_overlay.qt_token);
ctrl->qh_list.qh_link = cpu_to_hc32(virt_to_phys(&ctrl->qh_list) | QH_LINK_TYPE_QH);
flush_dcache_range((unsigned long)&ctrl->qh_list,
ALIGN_END_ADDR(struct QH, &ctrl->qh_list, 1));
/*
* Invalidate the memory area occupied by buffer
@ -605,25 +609,12 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)
printf("EHCI timed out on TD - token=%#x\n", token);
/* Disable async schedule. */
cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
cmd &= ~CMD_ASE;
ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
ret = handshake((uint32_t *)&ctrl->hcor->or_usbsts, STS_ASS, 0,
100 * 1000);
if (ret < 0) {
printf("EHCI fail timeout STS_ASS reset\n");
goto fail;
}
token = hc32_to_cpu(qh->qh_overlay.qt_token);
if (!(QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)) {
debug("TOKEN=%#x\n", token);
switch (QT_TOKEN_GET_STATUS(token) &
if (!(QT_TOKEN_GET_STATUS(qhtoken) & QT_TOKEN_STATUS_ACTIVE)) {
debug("TOKEN=%#x\n", qhtoken);
switch (QT_TOKEN_GET_STATUS(qhtoken) &
~(QT_TOKEN_STATUS_SPLITXSTATE | QT_TOKEN_STATUS_PERR)) {
case 0:
toggle = QT_TOKEN_GET_DT(token);
toggle = QT_TOKEN_GET_DT(qhtoken);
usb_settoggle(dev, usb_pipeendpoint(pipe),
usb_pipeout(pipe), toggle);
dev->status = 0;
@ -641,11 +632,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
break;
default:
dev->status = USB_ST_CRC_ERR;
if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_HALTED)
if (QT_TOKEN_GET_STATUS(qhtoken) & QT_TOKEN_STATUS_HALTED)
dev->status |= USB_ST_STALLED;
break;
}
dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token);
dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(qhtoken);
} else {
dev->act_len = 0;
#ifndef CONFIG_USB_EHCI_FARADAY

View file

@ -22,6 +22,8 @@ enum dfu_device_type {
DFU_DEV_NAND,
DFU_DEV_RAM,
DFU_DEV_SF,
DFU_DEV_MTD,
DFU_DEV_VIRT,
};
enum dfu_layout {
@ -55,6 +57,16 @@ struct mmc_internal_data {
unsigned int part;
};
struct mtd_internal_data {
struct mtd_info *info;
/* RAW programming */
u64 start;
u64 size;
/* for ubi partition */
unsigned int ubi;
};
struct nand_internal_data {
/* RAW programming */
u64 start;
@ -77,6 +89,12 @@ struct sf_internal_data {
/* RAW programming */
u64 start;
u64 size;
/* for sf/ubi use */
unsigned int ubi;
};
struct virt_internal_data {
int dev_num;
};
#define DFU_NAME_SIZE 32
@ -103,9 +121,11 @@ struct dfu_entity {
union {
struct mmc_internal_data mmc;
struct mtd_internal_data mtd;
struct nand_internal_data nand;
struct ram_internal_data ram;
struct sf_internal_data sf;
struct virt_internal_data virt;
} data;
int (*get_medium_size)(struct dfu_entity *dfu, u64 *size);
@ -141,6 +161,8 @@ struct dfu_entity {
#ifdef CONFIG_SET_DFU_ALT_INFO
void set_dfu_alt_info(char *interface, char *devstr);
#endif
int dfu_alt_init(int num, struct dfu_entity **dfu);
int dfu_alt_add(struct dfu_entity *dfu, char *interface, char *devstr, char *s);
int dfu_config_entities(char *s, char *interface, char *devstr);
void dfu_free_entities(void);
void dfu_show_entities(void);
@ -161,6 +183,28 @@ int dfu_read(struct dfu_entity *de, void *buf, int size, int blk_seq_num);
int dfu_write(struct dfu_entity *de, void *buf, int size, int blk_seq_num);
int dfu_flush(struct dfu_entity *de, void *buf, int size, int blk_seq_num);
/**
* dfu_initiated_callback - weak callback called on DFU transaction start
*
* It is a callback function called by DFU stack when a DFU transaction is
* initiated. This function allows to manage some board specific behavior on
* DFU targets.
*
* @param dfu - pointer to the dfu_entity, which should be initialized
*
*/
void dfu_initiated_callback(struct dfu_entity *dfu);
/**
* dfu_flush_callback - weak callback called at the end of the DFU write
*
* It is a callback function called by DFU stack after DFU manifestation.
* This function allows to manage some board specific behavior on DFU targets
*
* @param dfu - pointer to the dfu_entity, which should be flushed
*
*/
void dfu_flush_callback(struct dfu_entity *dfu);
/*
* dfu_defer_flush - pointer to store dfu_entity for deferred flashing.
* It should be NULL when not used.
@ -245,6 +289,33 @@ static inline int dfu_fill_entity_sf(struct dfu_entity *dfu, char *devstr,
}
#endif
#if CONFIG_IS_ENABLED(DFU_MTD)
int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char *s);
#else
static inline int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr,
char *s)
{
puts("MTD support not available!\n");
return -1;
}
#endif
#ifdef CONFIG_DFU_VIRT
int dfu_fill_entity_virt(struct dfu_entity *dfu, char *devstr, char *s);
int dfu_write_medium_virt(struct dfu_entity *dfu, u64 offset,
void *buf, long *len);
int dfu_get_medium_size_virt(struct dfu_entity *dfu, u64 *size);
int dfu_read_medium_virt(struct dfu_entity *dfu, u64 offset,
void *buf, long *len);
#else
static inline int dfu_fill_entity_virt(struct dfu_entity *dfu, char *devstr,
char *s)
{
puts("VIRT support not available!\n");
return -1;
}
#endif
/**
* dfu_tftp_write - Write TFTP data to DFU medium
*