From 643cacb6d6d5a9f3adbf294a390537d53208fd79 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 23 Jan 2016 21:04:46 +0100 Subject: usb: ehci: Use map_physmem in ehci-generic Some architectures, like MIPS, require remapping of the registers. Add the map_physmem() call to handle it. Signed-off-by: Marek Vasut Cc: Daniel Schwierzeck Cc: Hans de Goede diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c index 84114c5..4444988 100644 --- a/drivers/usb/host/ehci-generic.c +++ b/drivers/usb/host/ehci-generic.c @@ -6,6 +6,7 @@ #include #include +#include #include #include "ehci.h" @@ -20,7 +21,7 @@ struct generic_ehci { static int ehci_usb_probe(struct udevice *dev) { - struct ehci_hccr *hccr = (struct ehci_hccr *)dev_get_addr(dev); + struct ehci_hccr *hccr; struct ehci_hcor *hcor; int i; @@ -36,6 +37,7 @@ static int ehci_usb_probe(struct udevice *dev) clk_dev->name, clk_id); } + hccr = map_physmem(dev_get_addr(dev), 0x100, MAP_NOCACHE); hcor = (struct ehci_hcor *)((uintptr_t)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); -- cgit v0.10.2 From cf7c93cdd75570fe6f75d04177b94a84146f5e46 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 23 Jan 2016 21:04:46 +0100 Subject: usb: ehci: Implement V2P mapping Certain processor architectures, like MIPS, require that the USB structures and transfer buffers are passed with their PA to the USB controller. If VA is passed, the USB will not work. Add the necessary virt_to_phys() calls into the USB EHCI code to make it work. Signed-off-by: Marek Vasut Cc: Daniel Schwierzeck Cc: Hans de Goede diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index c664b16..b3eb08d 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -245,7 +245,7 @@ static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz) idx = 0; while (idx < QT_BUFFER_CNT) { - td->qt_buffer[idx] = cpu_to_hc32(addr); + td->qt_buffer[idx] = cpu_to_hc32(virt_to_phys((void *)addr)); td->qt_buffer_hi[idx] = 0; next = (addr + EHCI_PAGE_SIZE) & ~(EHCI_PAGE_SIZE - 1); delta = next - addr; @@ -398,7 +398,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, * qh_overlay.qt_next ...... 13-10 H * - qh_overlay.qt_altnext */ - qh->qh_link = cpu_to_hc32((unsigned long)&ctrl->qh_list | QH_LINK_TYPE_QH); + qh->qh_link = cpu_to_hc32(virt_to_phys(&ctrl->qh_list) | QH_LINK_TYPE_QH); c = (dev->speed != USB_SPEED_HIGH) && !usb_pipeendpoint(pipe); maxpacket = usb_maxpacket(dev, pipe); endpt = QH_ENDPT1_RL(8) | QH_ENDPT1_C(c) | @@ -415,7 +415,6 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); tdp = &qh->qh_overlay.qt_next; - if (req != NULL) { /* * Setup request qTD (3.5 in ehci-r10.pdf) @@ -438,7 +437,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, goto fail; } /* Update previous qTD! */ - *tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]); + *tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter])); tdp = &qtd[qtd_counter++].qt_next; toggle = 1; } @@ -497,7 +496,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, goto fail; } /* Update previous qTD! */ - *tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]); + *tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter])); tdp = &qtd[qtd_counter++].qt_next; /* * Data toggle has to be adjusted since the qTD transfer @@ -528,11 +527,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE); qtd[qtd_counter].qt_token = cpu_to_hc32(token); /* Update previous qTD! */ - *tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]); + *tdp = cpu_to_hc32(virt_to_phys(&qtd[qtd_counter])); tdp = &qtd[qtd_counter++].qt_next; } - ctrl->qh_list.qh_link = cpu_to_hc32((unsigned long)qh | QH_LINK_TYPE_QH); + ctrl->qh_list.qh_link = cpu_to_hc32(virt_to_phys(qh) | QH_LINK_TYPE_QH); /* Flush dcache */ flush_dcache_range((unsigned long)&ctrl->qh_list, @@ -542,7 +541,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, ALIGN_END_ADDR(struct qTD, qtd, qtd_count)); /* Set async. queue head pointer. */ - ehci_writel(&ctrl->hcor->or_asynclistaddr, (unsigned long)&ctrl->qh_list); + 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)); @@ -989,7 +988,7 @@ static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks) /* Set head of reclaim list */ memset(qh_list, 0, sizeof(*qh_list)); - qh_list->qh_link = cpu_to_hc32((unsigned long)qh_list | QH_LINK_TYPE_QH); + qh_list->qh_link = cpu_to_hc32(virt_to_phys(qh_list) | QH_LINK_TYPE_QH); qh_list->qh_endpt1 = cpu_to_hc32(QH_ENDPT1_H(1) | QH_ENDPT1_EPS(USB_SPEED_HIGH)); qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); @@ -1001,7 +1000,7 @@ static int ehci_common_init(struct ehci_ctrl *ctrl, uint tweaks) ALIGN_END_ADDR(struct QH, qh_list, 1)); /* Set async. queue head pointer. */ - ehci_writel(&ctrl->hcor->or_asynclistaddr, (unsigned long)qh_list); + ehci_writel(&ctrl->hcor->or_asynclistaddr, virt_to_phys(qh_list)); /* * Set up periodic list -- cgit v0.10.2 From 7ab0d35543004b6f9dca990625fa3fa21b7bc9d6 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 23 Jan 2016 21:04:46 +0100 Subject: usb: ehci: Clear USBMODE_BE on LE MMIO If the USB EHCI is configured for little endian MMIO, make sure to clear the USBMODE_BE flag from the USBMODE register. Signed-off-by: Marek Vasut Cc: Daniel Schwierzeck Cc: Hans de Goede diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index b3eb08d..8f259be 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -134,6 +134,8 @@ static void ehci_set_usbmode(struct ehci_ctrl *ctrl) tmp |= USBMODE_CM_HC; #if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN) tmp |= USBMODE_BE; +#else + tmp &= ~USBMODE_BE; #endif ehci_writel(reg_ptr, tmp); } -- cgit v0.10.2 From e88a1b75d56b03de9db6cbf2acf8ecd20d135a11 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 23 Jan 2016 21:04:46 +0100 Subject: usb: ehci: Be explicit about the BE IO accessors Add explicit cpu_to_be32()/be32_to_cpu() conversion to BE EHCI I/O accessors to align them with their LE counterpart. No functional change. Signed-off-by: Marek Vasut Cc: Daniel Schwierzeck Cc: Hans de Goede diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index b41c04a..826b3fe 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -102,8 +102,9 @@ struct usb_linux_config_descriptor { } __attribute__ ((packed)); #if defined CONFIG_EHCI_DESC_BIG_ENDIAN -#define ehci_readl(x) (*((volatile u32 *)(x))) -#define ehci_writel(a, b) (*((volatile u32 *)(a)) = ((volatile u32)b)) +#define ehci_readl(x) cpu_to_be32((*((volatile u32 *)(x)))) +#define ehci_writel(a, b) (*((volatile u32 *)(a)) = \ + cpu_to_be32(((volatile u32)b))) #else #define ehci_readl(x) cpu_to_le32((*((volatile u32 *)(x)))) #define ehci_writel(a, b) (*((volatile u32 *)(a)) = \ -- cgit v0.10.2 From fc18f8d170ecc7e15269ad5312ec643addb42491 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Thu, 28 Jan 2016 16:14:49 +0100 Subject: dfu: usb: f_dfu: Set deferred call for dfu_flush() function This patch fixes situation when one would like to write large file into medium with the file system (fat, ext4, etc). This change sets file size limitation to the DFU internal buffer size. Since u-boot is not supporting interrupts and seek on file systems, it becomes challenging to store large file appropriately. To reproduce this error - create large file (around 26 MiB) and sent it to the target board. Lets examine the flow of USB transactions: 0. DFU uses EP0 with 64B MPS [Max Packet Size] 1. Send file - OUT (PC->target) - dat_26MiB.img is sent with 4096 B transactions 2. Get status - OUT (PC->target) - wait for DFU_STATE_dfuDNLOAD_IDLE (0x05) sent from target board - IN transaction (target->PC) 3. The whole file content is sent to target - OUT (PC->target) with ZLP [Zero Length Packet] Now the interesting part starts: 4. OUT (PC->target) Setup transaction (request to share DFU state) 5. IN (target->PC) - reply the current DFU state - In the UDC driver the req->completion (with dfu_flush) is called after successful IN transfer. - The dfu_flush() (called from req->completion callback) saves the whole file at once (u-boot doesn't support seek on fs). Such operation takes considerable time. When the file is large - e.g. 26MiB - this time may be more than 5 seconds. 6. OUT (PC->target) - ZLP, is send in the same time when dfu_flush() writes data to eMMC memory. The dfu-util application has hard coded timeout on USB transaction completion set to 5 seconds (it uses libusb calls). When the file to store is large (e.g. 26 MiB) the time needed to write it may excess the dfu-util timeout and following error message will be displayed: "unable to read DFU status" on the HOST PC console. This change is supposed to leverage DFU's part responsible for storing files on file systems. Other DFU operations - i.e. raw/partition write to NAND and eMMC should work as before. The only functional change is the error reporting. When dfu_flush() fails the u-boot prompt will exit with error information and dfu-util application exits afterwards as well. Test HW: - Odroid XU3 (Exynos5433) - test with large file - Trats (Exynos4210) - test for regression - eMMC, raw, Signed-off-by: Lukasz Majewski Reported-by: Alex Gdalevich Tested-by: Stephen Warren Tested-by: Heiko Schocher diff --git a/cmd/dfu.c b/cmd/dfu.c index 6d95ce9..d8aae26 100644 --- a/cmd/dfu.c +++ b/cmd/dfu.c @@ -79,6 +79,26 @@ static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (ctrlc()) goto exit; + if (dfu_get_defer_flush()) { + /* + * Call to usb_gadget_handle_interrupts() is necessary + * to act on ZLP OUT transaction from HOST PC after + * transmitting the whole file. + * + * If this ZLP OUT packet is NAK'ed, the HOST libusb + * function fails after timeout (by default it is set to + * 5 seconds). In such situation the dfu-util program + * exits with error message. + */ + usb_gadget_handle_interrupts(controller_index); + ret = dfu_flush(dfu_get_defer_flush(), NULL, 0, 0); + dfu_set_defer_flush(NULL); + if (ret) { + error("Deferred dfu_flush() failed!"); + goto exit; + } + } + WATCHDOG_RESET(); usb_gadget_handle_interrupts(controller_index); } diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c index 77a1567..7d88008 100644 --- a/drivers/usb/gadget/f_dfu.c +++ b/drivers/usb/gadget/f_dfu.c @@ -44,6 +44,8 @@ struct f_dfu { unsigned int poll_timeout; }; +struct dfu_entity *dfu_defer_flush; + typedef int (*dfu_state_fn) (struct f_dfu *, const struct usb_ctrlrequest *, struct usb_gadget *, @@ -167,14 +169,7 @@ static void dnload_request_complete(struct usb_ep *ep, struct usb_request *req) static void dnload_request_flush(struct usb_ep *ep, struct usb_request *req) { struct f_dfu *f_dfu = req->context; - int ret; - - ret = dfu_flush(dfu_get_entity(f_dfu->altsetting), req->buf, - req->length, f_dfu->blk_seq_num); - if (ret) { - f_dfu->dfu_status = DFU_STATUS_errUNKNOWN; - f_dfu->dfu_state = DFU_STATE_dfuERROR; - } + dfu_set_defer_flush(dfu_get_entity(f_dfu->altsetting)); } static inline int dfu_get_manifest_timeout(struct dfu_entity *dfu) diff --git a/include/dfu.h b/include/dfu.h index 6118dc2..f39d3f1 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -163,6 +163,31 @@ 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_defer_flush - pointer to store dfu_entity for deferred flashing. + * It should be NULL when not used. + */ +extern struct dfu_entity *dfu_defer_flush; +/** + * dfu_get_defer_flush - get current value of dfu_defer_flush pointer + * + * @return - value of the dfu_defer_flush pointer + */ +static inline struct dfu_entity *dfu_get_defer_flush(void) +{ + return dfu_defer_flush; +} + +/** + * dfu_set_defer_flush - set the dfu_defer_flush pointer + * + * @param dfu - pointer to the dfu_entity, which should be written + */ +static inline void dfu_set_defer_flush(struct dfu_entity *dfu) +{ + dfu_defer_flush = dfu; +} + /** * dfu_write_from_mem_addr - write data from memory to DFU managed medium * -- cgit v0.10.2 From 7124a8c4cf014e88b1b569be4150459ca9a6345e Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Thu, 28 Jan 2016 17:14:52 +0100 Subject: dfu: odroid xu3: Define DFU_MANIFEST_POLL_TIMEOUT to handle large files transmission and storage As tested on the Odroid XU3, large files to be stored on the file system require considerable time to be physically written to the medium. The default 300 ms is not enough to store large file (e.g. 26 MiB). To fix this situation the DFU_MANIFEST_POLL_TIMEOUT has been defined. It is used to cease the communication with dfu-util and allow the target board to store the data on file system. Signed-off-by: Lukasz Majewski diff --git a/include/configs/odroid_xu3.h b/include/configs/odroid_xu3.h index 648e48b..500f0f9 100644 --- a/include/configs/odroid_xu3.h +++ b/include/configs/odroid_xu3.h @@ -69,6 +69,7 @@ #define CONFIG_CMD_DFU #define CONFIG_SYS_DFU_DATA_BUF_SIZE SZ_32M #define DFU_DEFAULT_POLL_TIMEOUT 300 +#define DFU_MANIFEST_POLL_TIMEOUT 25000 /* THOR */ #define CONFIG_G_DNL_THOR_VENDOR_NUM CONFIG_G_DNL_VENDOR_NUM -- cgit v0.10.2 From 53419bac4edc4d07225fa80ff1aedf0c301e7cc4 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 12 Feb 2016 13:56:01 -0700 Subject: usb: eth: fix memalign() parameter order The alignment and size were swapped, leading to malloc heap corruption. On my system, this sometimes caused U-Boot to crash during or after certain USB Ethernet operations. Fixes: c8c2797c3810 ("dm: usb: eth: Support driver model with USB Ethernet") Signed-off-by: Stephen Warren diff --git a/drivers/usb/eth/usb_ether.c b/drivers/usb/eth/usb_ether.c index b9c9a84..36734e2 100644 --- a/drivers/usb/eth/usb_ether.c +++ b/drivers/usb/eth/usb_ether.c @@ -73,7 +73,7 @@ int usb_ether_register(struct udevice *dev, struct ueth_data *ueth, int rxsize) } ueth->rxsize = rxsize; - ueth->rxbuf = memalign(rxsize, ARCH_DMA_MINALIGN); + ueth->rxbuf = memalign(ARCH_DMA_MINALIGN, rxsize); if (!ueth->rxbuf) return -ENOMEM; -- cgit v0.10.2 From a18c2706f15ac3460cb902d37705f90ffae84ce6 Mon Sep 17 00:00:00 2001 From: Steve Rae Date: Wed, 27 Jan 2016 15:02:41 -0800 Subject: fastboot: update error and warning messages Fix the formatting in error messages, and demote one error message to a warning, as it is only informational. Signed-off-by: Steve Rae diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 87e54eb..a54b4ee 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -382,7 +382,7 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req) strsep(&cmd, ":"); if (!cmd) { - error("missing variable\n"); + error("missing variable"); fastboot_tx_write_str("FAILmissing var"); return; } @@ -413,7 +413,7 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req) else strcpy(response, "FAILValue not set"); } else { - error("unknown variable: %s\n", cmd); + printf("WARNING: unknown variable: %s\n", cmd); strcpy(response, "FAILVariable not implemented"); } fastboot_tx_write_str(response); @@ -561,7 +561,7 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req) strsep(&cmd, ":"); if (!cmd) { - error("missing partition name\n"); + error("missing partition name"); fastboot_tx_write_str("FAILmissing partition name"); return; } @@ -683,7 +683,7 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) } if (!func_cb) { - error("unknown command: %s\n", cmdbuf); + error("unknown command: %s", cmdbuf); fastboot_tx_write_str("FAILunknown command"); } else { if (req->actual < req->length) { @@ -691,7 +691,7 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) buf[req->actual] = 0; func_cb(ep, req); } else { - error("buffer overflow\n"); + error("buffer overflow"); fastboot_tx_write_str("FAILbuffer overflow"); } } -- cgit v0.10.2 From d7d8c00575c8ae766d387c763395470410427b69 Mon Sep 17 00:00:00 2001 From: Steve Rae Date: Wed, 27 Jan 2016 14:45:45 -0800 Subject: implement Fastboot via USB OTG on bcm28155_ap boards Don't understand how it happened, but this change got applied twice! Therefore, removing the duplicated items. Signed-off-by: Steve Rae diff --git a/include/configs/bcm28155_ap.h b/include/configs/bcm28155_ap.h index a257084..c9515a8 100644 --- a/include/configs/bcm28155_ap.h +++ b/include/configs/bcm28155_ap.h @@ -130,7 +130,6 @@ #define CONFIG_CMD_BOOTZ #define CONFIG_FAT_WRITE - /* Fastboot and USB OTG */ #define CONFIG_USB_FUNCTION_FASTBOOT #define CONFIG_CMD_FASTBOOT @@ -150,23 +149,4 @@ #define CONFIG_G_DNL_PRODUCT_NUM 0x0d02 /* nexus one */ #define CONFIG_G_DNL_MANUFACTURER "Broadcom Corporation" -/* Fastboot and USB OTG */ -#define CONFIG_USB_FUNCTION_FASTBOOT -#define CONFIG_CMD_FASTBOOT -#define CONFIG_FASTBOOT_FLASH -#define CONFIG_FASTBOOT_FLASH_MMC_DEV 0 -#define CONFIG_SYS_CACHELINE_SIZE 64 -#define CONFIG_USB_FASTBOOT_BUF_SIZE (CONFIG_SYS_SDRAM_SIZE - SZ_1M) -#define CONFIG_USB_FASTBOOT_BUF_ADDR CONFIG_SYS_SDRAM_BASE -#define CONFIG_USB_GADGET -#define CONFIG_USB_GADGET_DUALSPEED -#define CONFIG_USB_GADGET_VBUS_DRAW 0 -#define CONFIG_USB_GADGET_S3C_UDC_OTG -#define CONFIG_USB_GADGET_BCM_UDC_OTG_PHY -#define CONFIG_USB_GADGET_DOWNLOAD -#define CONFIG_USBID_ADDR 0x34052c46 -#define CONFIG_G_DNL_VENDOR_NUM 0x18d1 /* google */ -#define CONFIG_G_DNL_PRODUCT_NUM 0x0d02 /* nexus one */ -#define CONFIG_G_DNL_MANUFACTURER "Broadcom Corporation" - #endif /* __BCM28155_AP_H */ -- cgit v0.10.2