mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
usb changes for v4.6 merge window
This is almost all under drivers/usb/dwc2/. Many changes to the host side implementation of dwc2 have been done by Douglas Anderson. We also have USB 3.1 support added to the Gadget Framework and, because of that work, dwc3 got support to Synopsys new DWC_usb31 IP core. Other than these 2 important series, we also have the usual collection of non-critical fixes, Documentation updates, and minor changes all over the place. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJW2YqWAAoJEIaOsuA1yqREJEgP/11ETLS7iE+HgYMEWbJxo4Ri 6H7XryMuqyiqNSUrmYlSeax2CQCLac3fXNN7iDGkT2Ot6E3CcnOzdq5/fTSoAEvN vgv0nr1MHQaYlYMlsFNZJjZ98h2ZsmtYFuY+RJAKivgjCKoIR6XHeU0ExjAjyWZJ 5exPyfA8tGnHOJFGdZUe4bBQGCG5TO/cxVkc7xkX6bLnpJibuiRJfToxbwHjY0cK mQPba+Tw+3E72mhZw1qw8jwqjLCdgRZXlEvMl0ogaiQydEntDC4bIbY4xDJ8c4L2 EsACyyx63XYTiaELScxJ2e0Oh0d2yOxLZnUvspsZDlTL0OF/9E2wrVO+1s+FzdQ+ MmvU9lPcTm+SToIJMWPkmCxpwxtQ2+4HR6IwaU2CIC1YwIjMBzhEvhHV9uZDRx2Q 7haTEQ5Hny3YvOElEYSAof3WiUCdjMoT4UKCpPFVTZ62mVpOrlcahZoS4UbyOobd YGJBx2GwNLpC/Hoa5anasGLeGlR2rtPciHyvYlVm+X9OvQXnHx5d6KqlaBlM+U/6 vjFtwS7nbbX+ttM7EtdmrC/8i0bFJQqmqg48a7El+E4Os9VJ79+/h9xmoDWoSEWX uTUhro+gLs23P6DAd/A08UL/Get0pqM+QdB42Y+ac3CIyl0dviRQ/2JCKgijo52Z wK+nnmuJIgzt8ljSzu9G =vivP -----END PGP SIGNATURE----- Merge tag 'usb-for-v4.6' of http://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next Felipe writes: usb changes for v4.6 merge window This is almost all under drivers/usb/dwc2/. Many changes to the host side implementation of dwc2 have been done by Douglas Anderson. We also have USB 3.1 support added to the Gadget Framework and, because of that work, dwc3 got support to Synopsys new DWC_usb31 IP core. Other than these 2 important series, we also have the usual collection of non-critical fixes, Documentation updates, and minor changes all over the place.
This commit is contained in:
commit
3d0712deb0
@ -8,6 +8,8 @@ Required properties:
|
||||
- rockchip,rk3066-usb: The DWC2 USB controller instance in the rk3066 Soc;
|
||||
- "rockchip,rk3188-usb", "rockchip,rk3066-usb", "snps,dwc2": for rk3188 Soc;
|
||||
- "rockchip,rk3288-usb", "rockchip,rk3066-usb", "snps,dwc2": for rk3288 Soc;
|
||||
- "lantiq,arx100-usb": The DWC2 USB controller instance in Lantiq ARX SoCs;
|
||||
- "lantiq,xrx200-usb": The DWC2 USB controller instance in Lantiq XRX SoCs;
|
||||
- snps,dwc2: A generic DWC2 USB controller with default parameters.
|
||||
- reg : Should contain 1 register range (address and length)
|
||||
- interrupts : Should contain 1 interrupt
|
||||
|
@ -26,16 +26,17 @@ cat /sys/kernel/debug/ci_hdrc.0/registers
|
||||
On B-device:
|
||||
echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req
|
||||
|
||||
if HNP polling is not supported, also need:
|
||||
On A-device:
|
||||
echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req
|
||||
|
||||
B-device should take host role and enumrate A-device.
|
||||
|
||||
4) A-device switch back to host.
|
||||
On B-device:
|
||||
echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req
|
||||
|
||||
or, by introducing HNP polling, B-Host can know when A-peripheral wish
|
||||
to be host role, so this role switch also can be trigged in A-peripheral
|
||||
side by answering the polling from B-Host, this can be done on A-device:
|
||||
echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req
|
||||
|
||||
A-device should switch back to host and enumrate B-device.
|
||||
|
||||
5) Remove B-device(unplug micro B plug) and insert again in 10 seconds,
|
||||
|
@ -395,204 +395,6 @@
|
||||
#define CRP_AD_CBE_BESL 20
|
||||
#define CRP_AD_CBE_WRITE 0x00010000
|
||||
|
||||
|
||||
/*
|
||||
* USB Device Controller
|
||||
*
|
||||
* These are used by the USB gadget driver, so they don't follow the
|
||||
* IXP4XX_ naming convetions.
|
||||
*
|
||||
*/
|
||||
# define IXP4XX_USB_REG(x) (*((volatile u32 *)(x)))
|
||||
|
||||
/* UDC Undocumented - Reserved1 */
|
||||
#define UDC_RES1 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0004)
|
||||
/* UDC Undocumented - Reserved2 */
|
||||
#define UDC_RES2 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0008)
|
||||
/* UDC Undocumented - Reserved3 */
|
||||
#define UDC_RES3 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x000C)
|
||||
/* UDC Control Register */
|
||||
#define UDCCR IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0000)
|
||||
/* UDC Endpoint 0 Control/Status Register */
|
||||
#define UDCCS0 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0010)
|
||||
/* UDC Endpoint 1 (IN) Control/Status Register */
|
||||
#define UDCCS1 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0014)
|
||||
/* UDC Endpoint 2 (OUT) Control/Status Register */
|
||||
#define UDCCS2 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0018)
|
||||
/* UDC Endpoint 3 (IN) Control/Status Register */
|
||||
#define UDCCS3 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x001C)
|
||||
/* UDC Endpoint 4 (OUT) Control/Status Register */
|
||||
#define UDCCS4 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0020)
|
||||
/* UDC Endpoint 5 (Interrupt) Control/Status Register */
|
||||
#define UDCCS5 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0024)
|
||||
/* UDC Endpoint 6 (IN) Control/Status Register */
|
||||
#define UDCCS6 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0028)
|
||||
/* UDC Endpoint 7 (OUT) Control/Status Register */
|
||||
#define UDCCS7 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x002C)
|
||||
/* UDC Endpoint 8 (IN) Control/Status Register */
|
||||
#define UDCCS8 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0030)
|
||||
/* UDC Endpoint 9 (OUT) Control/Status Register */
|
||||
#define UDCCS9 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0034)
|
||||
/* UDC Endpoint 10 (Interrupt) Control/Status Register */
|
||||
#define UDCCS10 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0038)
|
||||
/* UDC Endpoint 11 (IN) Control/Status Register */
|
||||
#define UDCCS11 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x003C)
|
||||
/* UDC Endpoint 12 (OUT) Control/Status Register */
|
||||
#define UDCCS12 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0040)
|
||||
/* UDC Endpoint 13 (IN) Control/Status Register */
|
||||
#define UDCCS13 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0044)
|
||||
/* UDC Endpoint 14 (OUT) Control/Status Register */
|
||||
#define UDCCS14 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0048)
|
||||
/* UDC Endpoint 15 (Interrupt) Control/Status Register */
|
||||
#define UDCCS15 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x004C)
|
||||
/* UDC Frame Number Register High */
|
||||
#define UFNRH IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0060)
|
||||
/* UDC Frame Number Register Low */
|
||||
#define UFNRL IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0064)
|
||||
/* UDC Byte Count Reg 2 */
|
||||
#define UBCR2 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0068)
|
||||
/* UDC Byte Count Reg 4 */
|
||||
#define UBCR4 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x006c)
|
||||
/* UDC Byte Count Reg 7 */
|
||||
#define UBCR7 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0070)
|
||||
/* UDC Byte Count Reg 9 */
|
||||
#define UBCR9 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0074)
|
||||
/* UDC Byte Count Reg 12 */
|
||||
#define UBCR12 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0078)
|
||||
/* UDC Byte Count Reg 14 */
|
||||
#define UBCR14 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x007c)
|
||||
/* UDC Endpoint 0 Data Register */
|
||||
#define UDDR0 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0080)
|
||||
/* UDC Endpoint 1 Data Register */
|
||||
#define UDDR1 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0100)
|
||||
/* UDC Endpoint 2 Data Register */
|
||||
#define UDDR2 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0180)
|
||||
/* UDC Endpoint 3 Data Register */
|
||||
#define UDDR3 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0200)
|
||||
/* UDC Endpoint 4 Data Register */
|
||||
#define UDDR4 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0400)
|
||||
/* UDC Endpoint 5 Data Register */
|
||||
#define UDDR5 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x00A0)
|
||||
/* UDC Endpoint 6 Data Register */
|
||||
#define UDDR6 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0600)
|
||||
/* UDC Endpoint 7 Data Register */
|
||||
#define UDDR7 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0680)
|
||||
/* UDC Endpoint 8 Data Register */
|
||||
#define UDDR8 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0700)
|
||||
/* UDC Endpoint 9 Data Register */
|
||||
#define UDDR9 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0900)
|
||||
/* UDC Endpoint 10 Data Register */
|
||||
#define UDDR10 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x00C0)
|
||||
/* UDC Endpoint 11 Data Register */
|
||||
#define UDDR11 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0B00)
|
||||
/* UDC Endpoint 12 Data Register */
|
||||
#define UDDR12 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0B80)
|
||||
/* UDC Endpoint 13 Data Register */
|
||||
#define UDDR13 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0C00)
|
||||
/* UDC Endpoint 14 Data Register */
|
||||
#define UDDR14 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0E00)
|
||||
/* UDC Endpoint 15 Data Register */
|
||||
#define UDDR15 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x00E0)
|
||||
/* UDC Interrupt Control Register 0 */
|
||||
#define UICR0 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0050)
|
||||
/* UDC Interrupt Control Register 1 */
|
||||
#define UICR1 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0054)
|
||||
/* UDC Status Interrupt Register 0 */
|
||||
#define USIR0 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x0058)
|
||||
/* UDC Status Interrupt Register 1 */
|
||||
#define USIR1 IXP4XX_USB_REG(IXP4XX_USB_BASE_VIRT+0x005C)
|
||||
|
||||
#define UDCCR_UDE (1 << 0) /* UDC enable */
|
||||
#define UDCCR_UDA (1 << 1) /* UDC active */
|
||||
#define UDCCR_RSM (1 << 2) /* Device resume */
|
||||
#define UDCCR_RESIR (1 << 3) /* Resume interrupt request */
|
||||
#define UDCCR_SUSIR (1 << 4) /* Suspend interrupt request */
|
||||
#define UDCCR_SRM (1 << 5) /* Suspend/resume interrupt mask */
|
||||
#define UDCCR_RSTIR (1 << 6) /* Reset interrupt request */
|
||||
#define UDCCR_REM (1 << 7) /* Reset interrupt mask */
|
||||
|
||||
#define UDCCS0_OPR (1 << 0) /* OUT packet ready */
|
||||
#define UDCCS0_IPR (1 << 1) /* IN packet ready */
|
||||
#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */
|
||||
#define UDCCS0_DRWF (1 << 3) /* Device remote wakeup feature */
|
||||
#define UDCCS0_SST (1 << 4) /* Sent stall */
|
||||
#define UDCCS0_FST (1 << 5) /* Force stall */
|
||||
#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */
|
||||
#define UDCCS0_SA (1 << 7) /* Setup active */
|
||||
|
||||
#define UDCCS_BI_TFS (1 << 0) /* Transmit FIFO service */
|
||||
#define UDCCS_BI_TPC (1 << 1) /* Transmit packet complete */
|
||||
#define UDCCS_BI_FTF (1 << 2) /* Flush Tx FIFO */
|
||||
#define UDCCS_BI_TUR (1 << 3) /* Transmit FIFO underrun */
|
||||
#define UDCCS_BI_SST (1 << 4) /* Sent stall */
|
||||
#define UDCCS_BI_FST (1 << 5) /* Force stall */
|
||||
#define UDCCS_BI_TSP (1 << 7) /* Transmit short packet */
|
||||
|
||||
#define UDCCS_BO_RFS (1 << 0) /* Receive FIFO service */
|
||||
#define UDCCS_BO_RPC (1 << 1) /* Receive packet complete */
|
||||
#define UDCCS_BO_DME (1 << 3) /* DMA enable */
|
||||
#define UDCCS_BO_SST (1 << 4) /* Sent stall */
|
||||
#define UDCCS_BO_FST (1 << 5) /* Force stall */
|
||||
#define UDCCS_BO_RNE (1 << 6) /* Receive FIFO not empty */
|
||||
#define UDCCS_BO_RSP (1 << 7) /* Receive short packet */
|
||||
|
||||
#define UDCCS_II_TFS (1 << 0) /* Transmit FIFO service */
|
||||
#define UDCCS_II_TPC (1 << 1) /* Transmit packet complete */
|
||||
#define UDCCS_II_FTF (1 << 2) /* Flush Tx FIFO */
|
||||
#define UDCCS_II_TUR (1 << 3) /* Transmit FIFO underrun */
|
||||
#define UDCCS_II_TSP (1 << 7) /* Transmit short packet */
|
||||
|
||||
#define UDCCS_IO_RFS (1 << 0) /* Receive FIFO service */
|
||||
#define UDCCS_IO_RPC (1 << 1) /* Receive packet complete */
|
||||
#define UDCCS_IO_ROF (1 << 3) /* Receive overflow */
|
||||
#define UDCCS_IO_DME (1 << 3) /* DMA enable */
|
||||
#define UDCCS_IO_RNE (1 << 6) /* Receive FIFO not empty */
|
||||
#define UDCCS_IO_RSP (1 << 7) /* Receive short packet */
|
||||
|
||||
#define UDCCS_INT_TFS (1 << 0) /* Transmit FIFO service */
|
||||
#define UDCCS_INT_TPC (1 << 1) /* Transmit packet complete */
|
||||
#define UDCCS_INT_FTF (1 << 2) /* Flush Tx FIFO */
|
||||
#define UDCCS_INT_TUR (1 << 3) /* Transmit FIFO underrun */
|
||||
#define UDCCS_INT_SST (1 << 4) /* Sent stall */
|
||||
#define UDCCS_INT_FST (1 << 5) /* Force stall */
|
||||
#define UDCCS_INT_TSP (1 << 7) /* Transmit short packet */
|
||||
|
||||
#define UICR0_IM0 (1 << 0) /* Interrupt mask ep 0 */
|
||||
#define UICR0_IM1 (1 << 1) /* Interrupt mask ep 1 */
|
||||
#define UICR0_IM2 (1 << 2) /* Interrupt mask ep 2 */
|
||||
#define UICR0_IM3 (1 << 3) /* Interrupt mask ep 3 */
|
||||
#define UICR0_IM4 (1 << 4) /* Interrupt mask ep 4 */
|
||||
#define UICR0_IM5 (1 << 5) /* Interrupt mask ep 5 */
|
||||
#define UICR0_IM6 (1 << 6) /* Interrupt mask ep 6 */
|
||||
#define UICR0_IM7 (1 << 7) /* Interrupt mask ep 7 */
|
||||
|
||||
#define UICR1_IM8 (1 << 0) /* Interrupt mask ep 8 */
|
||||
#define UICR1_IM9 (1 << 1) /* Interrupt mask ep 9 */
|
||||
#define UICR1_IM10 (1 << 2) /* Interrupt mask ep 10 */
|
||||
#define UICR1_IM11 (1 << 3) /* Interrupt mask ep 11 */
|
||||
#define UICR1_IM12 (1 << 4) /* Interrupt mask ep 12 */
|
||||
#define UICR1_IM13 (1 << 5) /* Interrupt mask ep 13 */
|
||||
#define UICR1_IM14 (1 << 6) /* Interrupt mask ep 14 */
|
||||
#define UICR1_IM15 (1 << 7) /* Interrupt mask ep 15 */
|
||||
|
||||
#define USIR0_IR0 (1 << 0) /* Interrupt request ep 0 */
|
||||
#define USIR0_IR1 (1 << 1) /* Interrupt request ep 1 */
|
||||
#define USIR0_IR2 (1 << 2) /* Interrupt request ep 2 */
|
||||
#define USIR0_IR3 (1 << 3) /* Interrupt request ep 3 */
|
||||
#define USIR0_IR4 (1 << 4) /* Interrupt request ep 4 */
|
||||
#define USIR0_IR5 (1 << 5) /* Interrupt request ep 5 */
|
||||
#define USIR0_IR6 (1 << 6) /* Interrupt request ep 6 */
|
||||
#define USIR0_IR7 (1 << 7) /* Interrupt request ep 7 */
|
||||
|
||||
#define USIR1_IR8 (1 << 0) /* Interrupt request ep 8 */
|
||||
#define USIR1_IR9 (1 << 1) /* Interrupt request ep 9 */
|
||||
#define USIR1_IR10 (1 << 2) /* Interrupt request ep 10 */
|
||||
#define USIR1_IR11 (1 << 3) /* Interrupt request ep 11 */
|
||||
#define USIR1_IR12 (1 << 4) /* Interrupt request ep 12 */
|
||||
#define USIR1_IR13 (1 << 5) /* Interrupt request ep 13 */
|
||||
#define USIR1_IR14 (1 << 6) /* Interrupt request ep 14 */
|
||||
#define USIR1_IR15 (1 << 7) /* Interrupt request ep 15 */
|
||||
|
||||
#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */
|
||||
|
||||
/* "fuse" bits of IXP_EXP_CFG2 */
|
||||
|
@ -1,163 +0,0 @@
|
||||
#ifndef _ASM_ARCH_PXA25X_UDC_H
|
||||
#define _ASM_ARCH_PXA25X_UDC_H
|
||||
|
||||
#ifdef _ASM_ARCH_PXA27X_UDC_H
|
||||
#error "You can't include both PXA25x and PXA27x UDC support"
|
||||
#endif
|
||||
|
||||
#define UDC_RES1 __REG(0x40600004) /* UDC Undocumented - Reserved1 */
|
||||
#define UDC_RES2 __REG(0x40600008) /* UDC Undocumented - Reserved2 */
|
||||
#define UDC_RES3 __REG(0x4060000C) /* UDC Undocumented - Reserved3 */
|
||||
|
||||
#define UDCCR __REG(0x40600000) /* UDC Control Register */
|
||||
#define UDCCR_UDE (1 << 0) /* UDC enable */
|
||||
#define UDCCR_UDA (1 << 1) /* UDC active */
|
||||
#define UDCCR_RSM (1 << 2) /* Device resume */
|
||||
#define UDCCR_RESIR (1 << 3) /* Resume interrupt request */
|
||||
#define UDCCR_SUSIR (1 << 4) /* Suspend interrupt request */
|
||||
#define UDCCR_SRM (1 << 5) /* Suspend/resume interrupt mask */
|
||||
#define UDCCR_RSTIR (1 << 6) /* Reset interrupt request */
|
||||
#define UDCCR_REM (1 << 7) /* Reset interrupt mask */
|
||||
|
||||
#define UDCCS0 __REG(0x40600010) /* UDC Endpoint 0 Control/Status Register */
|
||||
#define UDCCS0_OPR (1 << 0) /* OUT packet ready */
|
||||
#define UDCCS0_IPR (1 << 1) /* IN packet ready */
|
||||
#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */
|
||||
#define UDCCS0_DRWF (1 << 3) /* Device remote wakeup feature */
|
||||
#define UDCCS0_SST (1 << 4) /* Sent stall */
|
||||
#define UDCCS0_FST (1 << 5) /* Force stall */
|
||||
#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */
|
||||
#define UDCCS0_SA (1 << 7) /* Setup active */
|
||||
|
||||
/* Bulk IN - Endpoint 1,6,11 */
|
||||
#define UDCCS1 __REG(0x40600014) /* UDC Endpoint 1 (IN) Control/Status Register */
|
||||
#define UDCCS6 __REG(0x40600028) /* UDC Endpoint 6 (IN) Control/Status Register */
|
||||
#define UDCCS11 __REG(0x4060003C) /* UDC Endpoint 11 (IN) Control/Status Register */
|
||||
|
||||
#define UDCCS_BI_TFS (1 << 0) /* Transmit FIFO service */
|
||||
#define UDCCS_BI_TPC (1 << 1) /* Transmit packet complete */
|
||||
#define UDCCS_BI_FTF (1 << 2) /* Flush Tx FIFO */
|
||||
#define UDCCS_BI_TUR (1 << 3) /* Transmit FIFO underrun */
|
||||
#define UDCCS_BI_SST (1 << 4) /* Sent stall */
|
||||
#define UDCCS_BI_FST (1 << 5) /* Force stall */
|
||||
#define UDCCS_BI_TSP (1 << 7) /* Transmit short packet */
|
||||
|
||||
/* Bulk OUT - Endpoint 2,7,12 */
|
||||
#define UDCCS2 __REG(0x40600018) /* UDC Endpoint 2 (OUT) Control/Status Register */
|
||||
#define UDCCS7 __REG(0x4060002C) /* UDC Endpoint 7 (OUT) Control/Status Register */
|
||||
#define UDCCS12 __REG(0x40600040) /* UDC Endpoint 12 (OUT) Control/Status Register */
|
||||
|
||||
#define UDCCS_BO_RFS (1 << 0) /* Receive FIFO service */
|
||||
#define UDCCS_BO_RPC (1 << 1) /* Receive packet complete */
|
||||
#define UDCCS_BO_DME (1 << 3) /* DMA enable */
|
||||
#define UDCCS_BO_SST (1 << 4) /* Sent stall */
|
||||
#define UDCCS_BO_FST (1 << 5) /* Force stall */
|
||||
#define UDCCS_BO_RNE (1 << 6) /* Receive FIFO not empty */
|
||||
#define UDCCS_BO_RSP (1 << 7) /* Receive short packet */
|
||||
|
||||
/* Isochronous IN - Endpoint 3,8,13 */
|
||||
#define UDCCS3 __REG(0x4060001C) /* UDC Endpoint 3 (IN) Control/Status Register */
|
||||
#define UDCCS8 __REG(0x40600030) /* UDC Endpoint 8 (IN) Control/Status Register */
|
||||
#define UDCCS13 __REG(0x40600044) /* UDC Endpoint 13 (IN) Control/Status Register */
|
||||
|
||||
#define UDCCS_II_TFS (1 << 0) /* Transmit FIFO service */
|
||||
#define UDCCS_II_TPC (1 << 1) /* Transmit packet complete */
|
||||
#define UDCCS_II_FTF (1 << 2) /* Flush Tx FIFO */
|
||||
#define UDCCS_II_TUR (1 << 3) /* Transmit FIFO underrun */
|
||||
#define UDCCS_II_TSP (1 << 7) /* Transmit short packet */
|
||||
|
||||
/* Isochronous OUT - Endpoint 4,9,14 */
|
||||
#define UDCCS4 __REG(0x40600020) /* UDC Endpoint 4 (OUT) Control/Status Register */
|
||||
#define UDCCS9 __REG(0x40600034) /* UDC Endpoint 9 (OUT) Control/Status Register */
|
||||
#define UDCCS14 __REG(0x40600048) /* UDC Endpoint 14 (OUT) Control/Status Register */
|
||||
|
||||
#define UDCCS_IO_RFS (1 << 0) /* Receive FIFO service */
|
||||
#define UDCCS_IO_RPC (1 << 1) /* Receive packet complete */
|
||||
#define UDCCS_IO_ROF (1 << 2) /* Receive overflow */
|
||||
#define UDCCS_IO_DME (1 << 3) /* DMA enable */
|
||||
#define UDCCS_IO_RNE (1 << 6) /* Receive FIFO not empty */
|
||||
#define UDCCS_IO_RSP (1 << 7) /* Receive short packet */
|
||||
|
||||
/* Interrupt IN - Endpoint 5,10,15 */
|
||||
#define UDCCS5 __REG(0x40600024) /* UDC Endpoint 5 (Interrupt) Control/Status Register */
|
||||
#define UDCCS10 __REG(0x40600038) /* UDC Endpoint 10 (Interrupt) Control/Status Register */
|
||||
#define UDCCS15 __REG(0x4060004C) /* UDC Endpoint 15 (Interrupt) Control/Status Register */
|
||||
|
||||
#define UDCCS_INT_TFS (1 << 0) /* Transmit FIFO service */
|
||||
#define UDCCS_INT_TPC (1 << 1) /* Transmit packet complete */
|
||||
#define UDCCS_INT_FTF (1 << 2) /* Flush Tx FIFO */
|
||||
#define UDCCS_INT_TUR (1 << 3) /* Transmit FIFO underrun */
|
||||
#define UDCCS_INT_SST (1 << 4) /* Sent stall */
|
||||
#define UDCCS_INT_FST (1 << 5) /* Force stall */
|
||||
#define UDCCS_INT_TSP (1 << 7) /* Transmit short packet */
|
||||
|
||||
#define UFNRH __REG(0x40600060) /* UDC Frame Number Register High */
|
||||
#define UFNRL __REG(0x40600064) /* UDC Frame Number Register Low */
|
||||
#define UBCR2 __REG(0x40600068) /* UDC Byte Count Reg 2 */
|
||||
#define UBCR4 __REG(0x4060006c) /* UDC Byte Count Reg 4 */
|
||||
#define UBCR7 __REG(0x40600070) /* UDC Byte Count Reg 7 */
|
||||
#define UBCR9 __REG(0x40600074) /* UDC Byte Count Reg 9 */
|
||||
#define UBCR12 __REG(0x40600078) /* UDC Byte Count Reg 12 */
|
||||
#define UBCR14 __REG(0x4060007c) /* UDC Byte Count Reg 14 */
|
||||
#define UDDR0 __REG(0x40600080) /* UDC Endpoint 0 Data Register */
|
||||
#define UDDR1 __REG(0x40600100) /* UDC Endpoint 1 Data Register */
|
||||
#define UDDR2 __REG(0x40600180) /* UDC Endpoint 2 Data Register */
|
||||
#define UDDR3 __REG(0x40600200) /* UDC Endpoint 3 Data Register */
|
||||
#define UDDR4 __REG(0x40600400) /* UDC Endpoint 4 Data Register */
|
||||
#define UDDR5 __REG(0x406000A0) /* UDC Endpoint 5 Data Register */
|
||||
#define UDDR6 __REG(0x40600600) /* UDC Endpoint 6 Data Register */
|
||||
#define UDDR7 __REG(0x40600680) /* UDC Endpoint 7 Data Register */
|
||||
#define UDDR8 __REG(0x40600700) /* UDC Endpoint 8 Data Register */
|
||||
#define UDDR9 __REG(0x40600900) /* UDC Endpoint 9 Data Register */
|
||||
#define UDDR10 __REG(0x406000C0) /* UDC Endpoint 10 Data Register */
|
||||
#define UDDR11 __REG(0x40600B00) /* UDC Endpoint 11 Data Register */
|
||||
#define UDDR12 __REG(0x40600B80) /* UDC Endpoint 12 Data Register */
|
||||
#define UDDR13 __REG(0x40600C00) /* UDC Endpoint 13 Data Register */
|
||||
#define UDDR14 __REG(0x40600E00) /* UDC Endpoint 14 Data Register */
|
||||
#define UDDR15 __REG(0x406000E0) /* UDC Endpoint 15 Data Register */
|
||||
|
||||
#define UICR0 __REG(0x40600050) /* UDC Interrupt Control Register 0 */
|
||||
|
||||
#define UICR0_IM0 (1 << 0) /* Interrupt mask ep 0 */
|
||||
#define UICR0_IM1 (1 << 1) /* Interrupt mask ep 1 */
|
||||
#define UICR0_IM2 (1 << 2) /* Interrupt mask ep 2 */
|
||||
#define UICR0_IM3 (1 << 3) /* Interrupt mask ep 3 */
|
||||
#define UICR0_IM4 (1 << 4) /* Interrupt mask ep 4 */
|
||||
#define UICR0_IM5 (1 << 5) /* Interrupt mask ep 5 */
|
||||
#define UICR0_IM6 (1 << 6) /* Interrupt mask ep 6 */
|
||||
#define UICR0_IM7 (1 << 7) /* Interrupt mask ep 7 */
|
||||
|
||||
#define UICR1 __REG(0x40600054) /* UDC Interrupt Control Register 1 */
|
||||
|
||||
#define UICR1_IM8 (1 << 0) /* Interrupt mask ep 8 */
|
||||
#define UICR1_IM9 (1 << 1) /* Interrupt mask ep 9 */
|
||||
#define UICR1_IM10 (1 << 2) /* Interrupt mask ep 10 */
|
||||
#define UICR1_IM11 (1 << 3) /* Interrupt mask ep 11 */
|
||||
#define UICR1_IM12 (1 << 4) /* Interrupt mask ep 12 */
|
||||
#define UICR1_IM13 (1 << 5) /* Interrupt mask ep 13 */
|
||||
#define UICR1_IM14 (1 << 6) /* Interrupt mask ep 14 */
|
||||
#define UICR1_IM15 (1 << 7) /* Interrupt mask ep 15 */
|
||||
|
||||
#define USIR0 __REG(0x40600058) /* UDC Status Interrupt Register 0 */
|
||||
|
||||
#define USIR0_IR0 (1 << 0) /* Interrupt request ep 0 */
|
||||
#define USIR0_IR1 (1 << 1) /* Interrupt request ep 1 */
|
||||
#define USIR0_IR2 (1 << 2) /* Interrupt request ep 2 */
|
||||
#define USIR0_IR3 (1 << 3) /* Interrupt request ep 3 */
|
||||
#define USIR0_IR4 (1 << 4) /* Interrupt request ep 4 */
|
||||
#define USIR0_IR5 (1 << 5) /* Interrupt request ep 5 */
|
||||
#define USIR0_IR6 (1 << 6) /* Interrupt request ep 6 */
|
||||
#define USIR0_IR7 (1 << 7) /* Interrupt request ep 7 */
|
||||
|
||||
#define USIR1 __REG(0x4060005C) /* UDC Status Interrupt Register 1 */
|
||||
|
||||
#define USIR1_IR8 (1 << 0) /* Interrupt request ep 8 */
|
||||
#define USIR1_IR9 (1 << 1) /* Interrupt request ep 9 */
|
||||
#define USIR1_IR10 (1 << 2) /* Interrupt request ep 10 */
|
||||
#define USIR1_IR11 (1 << 3) /* Interrupt request ep 11 */
|
||||
#define USIR1_IR12 (1 << 4) /* Interrupt request ep 12 */
|
||||
#define USIR1_IR13 (1 << 5) /* Interrupt request ep 13 */
|
||||
#define USIR1_IR14 (1 << 6) /* Interrupt request ep 14 */
|
||||
#define USIR1_IR15 (1 << 7) /* Interrupt request ep 15 */
|
||||
|
||||
#endif
|
@ -26,7 +26,7 @@ obj-$(CONFIG_USB_U132_HCD) += host/
|
||||
obj-$(CONFIG_USB_R8A66597_HCD) += host/
|
||||
obj-$(CONFIG_USB_HWA_HCD) += host/
|
||||
obj-$(CONFIG_USB_IMX21_HCD) += host/
|
||||
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
|
||||
obj-$(CONFIG_USB_FSL_USB2) += host/
|
||||
obj-$(CONFIG_USB_FOTG210_HCD) += host/
|
||||
obj-$(CONFIG_USB_MAX3421_HCD) += host/
|
||||
|
||||
|
@ -66,6 +66,11 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr,
|
||||
return count;
|
||||
}
|
||||
ci->fsm.a_bus_req = 1;
|
||||
if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) {
|
||||
ci->gadget.host_request_flag = 1;
|
||||
mutex_unlock(&ci->fsm.lock);
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
ci_otg_queue_work(ci);
|
||||
@ -144,8 +149,14 @@ set_b_bus_req(struct device *dev, struct device_attribute *attr,
|
||||
mutex_lock(&ci->fsm.lock);
|
||||
if (buf[0] == '0')
|
||||
ci->fsm.b_bus_req = 0;
|
||||
else if (buf[0] == '1')
|
||||
else if (buf[0] == '1') {
|
||||
ci->fsm.b_bus_req = 1;
|
||||
if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) {
|
||||
ci->gadget.host_request_flag = 1;
|
||||
mutex_unlock(&ci->fsm.lock);
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
ci_otg_queue_work(ci);
|
||||
mutex_unlock(&ci->fsm.lock);
|
||||
@ -198,6 +209,7 @@ static unsigned otg_timer_ms[] = {
|
||||
TA_AIDL_BDIS,
|
||||
TB_ASE0_BRST,
|
||||
TA_BIDL_ADIS,
|
||||
TB_AIDL_BDIS,
|
||||
TB_SE0_SRP,
|
||||
TB_SRP_FAIL,
|
||||
0,
|
||||
@ -309,6 +321,12 @@ static int a_bidl_adis_tmout(struct ci_hdrc *ci)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b_aidl_bdis_tmout(struct ci_hdrc *ci)
|
||||
{
|
||||
ci->fsm.a_bus_suspend = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b_se0_srp_tmout(struct ci_hdrc *ci)
|
||||
{
|
||||
ci->fsm.b_se0_srp = 1;
|
||||
@ -353,6 +371,7 @@ static int (*otg_timer_handlers[])(struct ci_hdrc *) = {
|
||||
a_aidl_bdis_tmout, /* A_AIDL_BDIS */
|
||||
b_ase0_brst_tmout, /* B_ASE0_BRST */
|
||||
a_bidl_adis_tmout, /* A_BIDL_ADIS */
|
||||
b_aidl_bdis_tmout, /* B_AIDL_BDIS */
|
||||
b_se0_srp_tmout, /* B_SE0_SRP */
|
||||
b_srp_fail_tmout, /* B_SRP_FAIL */
|
||||
NULL, /* A_WAIT_ENUM */
|
||||
@ -644,9 +663,9 @@ static void ci_otg_fsm_event(struct ci_hdrc *ci)
|
||||
break;
|
||||
case OTG_STATE_B_PERIPHERAL:
|
||||
if ((intr_sts & USBi_SLI) && port_conn && otg_bsess_vld) {
|
||||
fsm->a_bus_suspend = 1;
|
||||
ci_otg_queue_work(ci);
|
||||
ci_otg_add_timer(ci, B_AIDL_BDIS);
|
||||
} else if (intr_sts & USBi_PCI) {
|
||||
ci_otg_del_timer(ci, B_AIDL_BDIS);
|
||||
if (fsm->a_bus_suspend == 1)
|
||||
fsm->a_bus_suspend = 0;
|
||||
}
|
||||
@ -786,6 +805,10 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
|
||||
ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
|
||||
ci->fsm.otg->state = OTG_STATE_UNDEFINED;
|
||||
ci->fsm.ops = &ci_otg_ops;
|
||||
ci->gadget.hnp_polling_support = 1;
|
||||
ci->fsm.host_req_flag = devm_kzalloc(ci->dev, 1, GFP_KERNEL);
|
||||
if (!ci->fsm.host_req_flag)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&ci->fsm.lock);
|
||||
|
||||
|
@ -62,6 +62,8 @@
|
||||
/* SSEND time before SRP */
|
||||
#define TB_SSEND_SRP (1500) /* minimum 1.5 sec, section:5.1.2 */
|
||||
|
||||
#define TB_AIDL_BDIS (20) /* 4ms ~ 150ms, section 5.2.1 */
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_OTG_FSM)
|
||||
|
||||
int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci);
|
||||
|
@ -1067,7 +1067,8 @@ __acquires(ci->lock)
|
||||
}
|
||||
break;
|
||||
case USB_REQ_GET_STATUS:
|
||||
if (type != (USB_DIR_IN|USB_RECIP_DEVICE) &&
|
||||
if ((type != (USB_DIR_IN|USB_RECIP_DEVICE) ||
|
||||
le16_to_cpu(req.wIndex) == OTG_STS_SELECTOR) &&
|
||||
type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
|
||||
type != (USB_DIR_IN|USB_RECIP_INTERFACE))
|
||||
goto delegate;
|
||||
|
@ -78,6 +78,8 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
|
||||
fsm->b_srp_done = 0;
|
||||
break;
|
||||
case OTG_STATE_B_PERIPHERAL:
|
||||
if (fsm->otg->gadget)
|
||||
fsm->otg->gadget->host_request_flag = 0;
|
||||
break;
|
||||
case OTG_STATE_B_WAIT_ACON:
|
||||
otg_del_timer(fsm, B_ASE0_BRST);
|
||||
@ -107,6 +109,8 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
|
||||
case OTG_STATE_A_PERIPHERAL:
|
||||
otg_del_timer(fsm, A_BIDL_ADIS);
|
||||
fsm->a_bidl_adis_tmout = 0;
|
||||
if (fsm->otg->gadget)
|
||||
fsm->otg->gadget->host_request_flag = 0;
|
||||
break;
|
||||
case OTG_STATE_A_WAIT_VFALL:
|
||||
otg_del_timer(fsm, A_WAIT_VFALL);
|
||||
@ -120,6 +124,87 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
|
||||
}
|
||||
}
|
||||
|
||||
static void otg_hnp_polling_work(struct work_struct *work)
|
||||
{
|
||||
struct otg_fsm *fsm = container_of(to_delayed_work(work),
|
||||
struct otg_fsm, hnp_polling_work);
|
||||
struct usb_device *udev;
|
||||
enum usb_otg_state state = fsm->otg->state;
|
||||
u8 flag;
|
||||
int retval;
|
||||
|
||||
if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST)
|
||||
return;
|
||||
|
||||
udev = usb_hub_find_child(fsm->otg->host->root_hub, 1);
|
||||
if (!udev) {
|
||||
dev_err(fsm->otg->host->controller,
|
||||
"no usb dev connected, can't start HNP polling\n");
|
||||
return;
|
||||
}
|
||||
|
||||
*fsm->host_req_flag = 0;
|
||||
/* Get host request flag from connected USB device */
|
||||
retval = usb_control_msg(udev,
|
||||
usb_rcvctrlpipe(udev, 0),
|
||||
USB_REQ_GET_STATUS,
|
||||
USB_DIR_IN | USB_RECIP_DEVICE,
|
||||
0,
|
||||
OTG_STS_SELECTOR,
|
||||
fsm->host_req_flag,
|
||||
1,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
if (retval != 1) {
|
||||
dev_err(&udev->dev, "Get one byte OTG status failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
flag = *fsm->host_req_flag;
|
||||
if (flag == 0) {
|
||||
/* Continue HNP polling */
|
||||
schedule_delayed_work(&fsm->hnp_polling_work,
|
||||
msecs_to_jiffies(T_HOST_REQ_POLL));
|
||||
return;
|
||||
} else if (flag != HOST_REQUEST_FLAG) {
|
||||
dev_err(&udev->dev, "host request flag %d is invalid\n", flag);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Host request flag is set */
|
||||
if (state == OTG_STATE_A_HOST) {
|
||||
/* Set b_hnp_enable */
|
||||
if (!fsm->otg->host->b_hnp_enable) {
|
||||
retval = usb_control_msg(udev,
|
||||
usb_sndctrlpipe(udev, 0),
|
||||
USB_REQ_SET_FEATURE, 0,
|
||||
USB_DEVICE_B_HNP_ENABLE,
|
||||
0, NULL, 0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
if (retval >= 0)
|
||||
fsm->otg->host->b_hnp_enable = 1;
|
||||
}
|
||||
fsm->a_bus_req = 0;
|
||||
} else if (state == OTG_STATE_B_HOST) {
|
||||
fsm->b_bus_req = 0;
|
||||
}
|
||||
|
||||
otg_statemachine(fsm);
|
||||
}
|
||||
|
||||
static void otg_start_hnp_polling(struct otg_fsm *fsm)
|
||||
{
|
||||
/*
|
||||
* The memory of host_req_flag should be allocated by
|
||||
* controller driver, otherwise, hnp polling is not started.
|
||||
*/
|
||||
if (!fsm->host_req_flag)
|
||||
return;
|
||||
|
||||
INIT_DELAYED_WORK(&fsm->hnp_polling_work, otg_hnp_polling_work);
|
||||
schedule_delayed_work(&fsm->hnp_polling_work,
|
||||
msecs_to_jiffies(T_HOST_REQ_POLL));
|
||||
}
|
||||
|
||||
/* Called when entering a state */
|
||||
static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
|
||||
{
|
||||
@ -169,6 +254,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
|
||||
otg_set_protocol(fsm, PROTO_HOST);
|
||||
usb_bus_start_enum(fsm->otg->host,
|
||||
fsm->otg->host->otg_port);
|
||||
otg_start_hnp_polling(fsm);
|
||||
break;
|
||||
case OTG_STATE_A_IDLE:
|
||||
otg_drv_vbus(fsm, 0);
|
||||
@ -203,6 +289,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
|
||||
*/
|
||||
if (!fsm->a_bus_req || fsm->a_suspend_req_inf)
|
||||
otg_add_timer(fsm, A_WAIT_ENUM);
|
||||
otg_start_hnp_polling(fsm);
|
||||
break;
|
||||
case OTG_STATE_A_SUSPEND:
|
||||
otg_drv_vbus(fsm, 1);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -44,6 +44,26 @@
|
||||
#include <linux/usb/phy.h>
|
||||
#include "hw.h"
|
||||
|
||||
/*
|
||||
* Suggested defines for tracers:
|
||||
* - no_printk: Disable tracing
|
||||
* - pr_info: Print this info to the console
|
||||
* - trace_printk: Print this info to trace buffer (good for verbose logging)
|
||||
*/
|
||||
|
||||
#define DWC2_TRACE_SCHEDULER no_printk
|
||||
#define DWC2_TRACE_SCHEDULER_VB no_printk
|
||||
|
||||
/* Detailed scheduler tracing, but won't overwhelm console */
|
||||
#define dwc2_sch_dbg(hsotg, fmt, ...) \
|
||||
DWC2_TRACE_SCHEDULER(pr_fmt("%s: SCH: " fmt), \
|
||||
dev_name(hsotg->dev), ##__VA_ARGS__)
|
||||
|
||||
/* Verbose scheduler tracing */
|
||||
#define dwc2_sch_vdbg(hsotg, fmt, ...) \
|
||||
DWC2_TRACE_SCHEDULER_VB(pr_fmt("%s: SCH: " fmt), \
|
||||
dev_name(hsotg->dev), ##__VA_ARGS__)
|
||||
|
||||
static inline u32 dwc2_readl(const void __iomem *addr)
|
||||
{
|
||||
u32 value = __raw_readl(addr);
|
||||
@ -572,6 +592,84 @@ struct dwc2_hregs_backup {
|
||||
bool valid;
|
||||
};
|
||||
|
||||
/*
|
||||
* Constants related to high speed periodic scheduling
|
||||
*
|
||||
* We have a periodic schedule that is DWC2_HS_SCHEDULE_UFRAMES long. From a
|
||||
* reservation point of view it's assumed that the schedule goes right back to
|
||||
* the beginning after the end of the schedule.
|
||||
*
|
||||
* What does that mean for scheduling things with a long interval? It means
|
||||
* we'll reserve time for them in every possible microframe that they could
|
||||
* ever be scheduled in. ...but we'll still only actually schedule them as
|
||||
* often as they were requested.
|
||||
*
|
||||
* We keep our schedule in a "bitmap" structure. This simplifies having
|
||||
* to keep track of and merge intervals: we just let the bitmap code do most
|
||||
* of the heavy lifting. In a way scheduling is much like memory allocation.
|
||||
*
|
||||
* We schedule 100us per uframe or 80% of 125us (the maximum amount you're
|
||||
* supposed to schedule for periodic transfers). That's according to spec.
|
||||
*
|
||||
* Note that though we only schedule 80% of each microframe, the bitmap that we
|
||||
* keep the schedule in is tightly packed (AKA it doesn't have 100us worth of
|
||||
* space for each uFrame).
|
||||
*
|
||||
* Requirements:
|
||||
* - DWC2_HS_SCHEDULE_UFRAMES must even divide 0x4000 (HFNUM_MAX_FRNUM + 1)
|
||||
* - DWC2_HS_SCHEDULE_UFRAMES must be 8 times DWC2_LS_SCHEDULE_FRAMES (probably
|
||||
* could be any multiple of 8 times DWC2_LS_SCHEDULE_FRAMES, but there might
|
||||
* be bugs). The 8 comes from the USB spec: number of microframes per frame.
|
||||
*/
|
||||
#define DWC2_US_PER_UFRAME 125
|
||||
#define DWC2_HS_PERIODIC_US_PER_UFRAME 100
|
||||
|
||||
#define DWC2_HS_SCHEDULE_UFRAMES 8
|
||||
#define DWC2_HS_SCHEDULE_US (DWC2_HS_SCHEDULE_UFRAMES * \
|
||||
DWC2_HS_PERIODIC_US_PER_UFRAME)
|
||||
|
||||
/*
|
||||
* Constants related to low speed scheduling
|
||||
*
|
||||
* For high speed we schedule every 1us. For low speed that's a bit overkill,
|
||||
* so we make up a unit called a "slice" that's worth 25us. There are 40
|
||||
* slices in a full frame and we can schedule 36 of those (90%) for periodic
|
||||
* transfers.
|
||||
*
|
||||
* Our low speed schedule can be as short as 1 frame or could be longer. When
|
||||
* we only schedule 1 frame it means that we'll need to reserve a time every
|
||||
* frame even for things that only transfer very rarely, so something that runs
|
||||
* every 2048 frames will get time reserved in every frame. Our low speed
|
||||
* schedule can be longer and we'll be able to handle more overlap, but that
|
||||
* will come at increased memory cost and increased time to schedule.
|
||||
*
|
||||
* Note: one other advantage of a short low speed schedule is that if we mess
|
||||
* up and miss scheduling we can jump in and use any of the slots that we
|
||||
* happened to reserve.
|
||||
*
|
||||
* With 25 us per slice and 1 frame in the schedule, we only need 4 bytes for
|
||||
* the schedule. There will be one schedule per TT.
|
||||
*
|
||||
* Requirements:
|
||||
* - DWC2_US_PER_SLICE must evenly divide DWC2_LS_PERIODIC_US_PER_FRAME.
|
||||
*/
|
||||
#define DWC2_US_PER_SLICE 25
|
||||
#define DWC2_SLICES_PER_UFRAME (DWC2_US_PER_UFRAME / DWC2_US_PER_SLICE)
|
||||
|
||||
#define DWC2_ROUND_US_TO_SLICE(us) \
|
||||
(DIV_ROUND_UP((us), DWC2_US_PER_SLICE) * \
|
||||
DWC2_US_PER_SLICE)
|
||||
|
||||
#define DWC2_LS_PERIODIC_US_PER_FRAME \
|
||||
900
|
||||
#define DWC2_LS_PERIODIC_SLICES_PER_FRAME \
|
||||
(DWC2_LS_PERIODIC_US_PER_FRAME / \
|
||||
DWC2_US_PER_SLICE)
|
||||
|
||||
#define DWC2_LS_SCHEDULE_FRAMES 1
|
||||
#define DWC2_LS_SCHEDULE_SLICES (DWC2_LS_SCHEDULE_FRAMES * \
|
||||
DWC2_LS_PERIODIC_SLICES_PER_FRAME)
|
||||
|
||||
/**
|
||||
* struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
|
||||
* and periodic schedules
|
||||
@ -657,11 +755,14 @@ struct dwc2_hregs_backup {
|
||||
* periodic_sched_ready because it must be rescheduled for
|
||||
* the next frame. Otherwise, the item moves to
|
||||
* periodic_sched_inactive.
|
||||
* @split_order: List keeping track of channels doing splits, in order.
|
||||
* @periodic_usecs: Total bandwidth claimed so far for periodic transfers.
|
||||
* This value is in microseconds per (micro)frame. The
|
||||
* assumption is that all periodic transfers may occur in
|
||||
* the same (micro)frame.
|
||||
* @frame_usecs: Internal variable used by the microframe scheduler
|
||||
* @hs_periodic_bitmap: Bitmap used by the microframe scheduler any time the
|
||||
* host is in high speed mode; low speed schedules are
|
||||
* stored elsewhere since we need one per TT.
|
||||
* @frame_number: Frame number read from the core at SOF. The value ranges
|
||||
* from 0 to HFNUM_MAX_FRNUM.
|
||||
* @periodic_qh_count: Count of periodic QHs, if using several eps. Used for
|
||||
@ -780,16 +881,19 @@ struct dwc2_hsotg {
|
||||
struct list_head periodic_sched_ready;
|
||||
struct list_head periodic_sched_assigned;
|
||||
struct list_head periodic_sched_queued;
|
||||
struct list_head split_order;
|
||||
u16 periodic_usecs;
|
||||
u16 frame_usecs[8];
|
||||
unsigned long hs_periodic_bitmap[
|
||||
DIV_ROUND_UP(DWC2_HS_SCHEDULE_US, BITS_PER_LONG)];
|
||||
u16 frame_number;
|
||||
u16 periodic_qh_count;
|
||||
bool bus_suspended;
|
||||
bool new_connection;
|
||||
|
||||
u16 last_frame_num;
|
||||
|
||||
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
|
||||
#define FRAME_NUM_ARRAY_SIZE 1000
|
||||
u16 last_frame_num;
|
||||
u16 *frame_num_array;
|
||||
u16 *last_frame_num_array;
|
||||
int frame_num_idx;
|
||||
@ -885,34 +989,11 @@ enum dwc2_halt_status {
|
||||
*/
|
||||
extern int dwc2_core_reset(struct dwc2_hsotg *hsotg);
|
||||
extern int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg);
|
||||
extern void dwc2_core_host_init(struct dwc2_hsotg *hsotg);
|
||||
extern int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg);
|
||||
extern int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore);
|
||||
|
||||
void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg);
|
||||
|
||||
/*
|
||||
* Host core Functions.
|
||||
* The following functions support managing the DWC_otg controller in host
|
||||
* mode.
|
||||
*/
|
||||
extern void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan);
|
||||
extern void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
|
||||
enum dwc2_halt_status halt_status);
|
||||
extern void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_host_chan *chan);
|
||||
extern void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_host_chan *chan);
|
||||
extern void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_host_chan *chan);
|
||||
extern int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_host_chan *chan);
|
||||
extern void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_host_chan *chan);
|
||||
extern void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg);
|
||||
extern void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg);
|
||||
|
||||
extern u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg);
|
||||
extern bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg);
|
||||
|
||||
/*
|
||||
@ -924,7 +1005,6 @@ extern void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes);
|
||||
extern void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num);
|
||||
extern void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg);
|
||||
|
||||
extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup);
|
||||
extern void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd);
|
||||
extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd);
|
||||
|
||||
@ -1191,6 +1271,8 @@ extern void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg);
|
||||
extern void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2);
|
||||
extern int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
|
||||
#define dwc2_is_device_connected(hsotg) (hsotg->connected)
|
||||
int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg);
|
||||
int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg);
|
||||
#else
|
||||
static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2)
|
||||
{ return 0; }
|
||||
@ -1208,22 +1290,37 @@ static inline int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
|
||||
int testmode)
|
||||
{ return 0; }
|
||||
#define dwc2_is_device_connected(hsotg) (0)
|
||||
static inline int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
|
||||
{ return 0; }
|
||||
static inline int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
|
||||
{ return 0; }
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
|
||||
extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg);
|
||||
extern int dwc2_hcd_get_future_frame_number(struct dwc2_hsotg *hsotg, int us);
|
||||
extern void dwc2_hcd_connect(struct dwc2_hsotg *hsotg);
|
||||
extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force);
|
||||
extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
|
||||
int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg);
|
||||
int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
|
||||
#else
|
||||
static inline int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
|
||||
{ return 0; }
|
||||
static inline int dwc2_hcd_get_future_frame_number(struct dwc2_hsotg *hsotg,
|
||||
int us)
|
||||
{ return 0; }
|
||||
static inline void dwc2_hcd_connect(struct dwc2_hsotg *hsotg) {}
|
||||
static inline void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force) {}
|
||||
static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {}
|
||||
static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {}
|
||||
static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
|
||||
{ return 0; }
|
||||
static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
|
||||
{ return 0; }
|
||||
static inline int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
|
||||
{ return 0; }
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __DWC2_CORE_H__ */
|
||||
|
@ -3668,3 +3668,105 @@ int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc2_backup_device_registers() - Backup controller device registers.
|
||||
* When suspending usb bus, registers needs to be backuped
|
||||
* if controller power is disabled once suspended.
|
||||
*
|
||||
* @hsotg: Programming view of the DWC_otg controller
|
||||
*/
|
||||
int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_dregs_backup *dr;
|
||||
int i;
|
||||
|
||||
dev_dbg(hsotg->dev, "%s\n", __func__);
|
||||
|
||||
/* Backup dev regs */
|
||||
dr = &hsotg->dr_backup;
|
||||
|
||||
dr->dcfg = dwc2_readl(hsotg->regs + DCFG);
|
||||
dr->dctl = dwc2_readl(hsotg->regs + DCTL);
|
||||
dr->daintmsk = dwc2_readl(hsotg->regs + DAINTMSK);
|
||||
dr->diepmsk = dwc2_readl(hsotg->regs + DIEPMSK);
|
||||
dr->doepmsk = dwc2_readl(hsotg->regs + DOEPMSK);
|
||||
|
||||
for (i = 0; i < hsotg->num_of_eps; i++) {
|
||||
/* Backup IN EPs */
|
||||
dr->diepctl[i] = dwc2_readl(hsotg->regs + DIEPCTL(i));
|
||||
|
||||
/* Ensure DATA PID is correctly configured */
|
||||
if (dr->diepctl[i] & DXEPCTL_DPID)
|
||||
dr->diepctl[i] |= DXEPCTL_SETD1PID;
|
||||
else
|
||||
dr->diepctl[i] |= DXEPCTL_SETD0PID;
|
||||
|
||||
dr->dieptsiz[i] = dwc2_readl(hsotg->regs + DIEPTSIZ(i));
|
||||
dr->diepdma[i] = dwc2_readl(hsotg->regs + DIEPDMA(i));
|
||||
|
||||
/* Backup OUT EPs */
|
||||
dr->doepctl[i] = dwc2_readl(hsotg->regs + DOEPCTL(i));
|
||||
|
||||
/* Ensure DATA PID is correctly configured */
|
||||
if (dr->doepctl[i] & DXEPCTL_DPID)
|
||||
dr->doepctl[i] |= DXEPCTL_SETD1PID;
|
||||
else
|
||||
dr->doepctl[i] |= DXEPCTL_SETD0PID;
|
||||
|
||||
dr->doeptsiz[i] = dwc2_readl(hsotg->regs + DOEPTSIZ(i));
|
||||
dr->doepdma[i] = dwc2_readl(hsotg->regs + DOEPDMA(i));
|
||||
}
|
||||
dr->valid = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc2_restore_device_registers() - Restore controller device registers.
|
||||
* When resuming usb bus, device registers needs to be restored
|
||||
* if controller power were disabled.
|
||||
*
|
||||
* @hsotg: Programming view of the DWC_otg controller
|
||||
*/
|
||||
int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_dregs_backup *dr;
|
||||
u32 dctl;
|
||||
int i;
|
||||
|
||||
dev_dbg(hsotg->dev, "%s\n", __func__);
|
||||
|
||||
/* Restore dev regs */
|
||||
dr = &hsotg->dr_backup;
|
||||
if (!dr->valid) {
|
||||
dev_err(hsotg->dev, "%s: no device registers to restore\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
dr->valid = false;
|
||||
|
||||
dwc2_writel(dr->dcfg, hsotg->regs + DCFG);
|
||||
dwc2_writel(dr->dctl, hsotg->regs + DCTL);
|
||||
dwc2_writel(dr->daintmsk, hsotg->regs + DAINTMSK);
|
||||
dwc2_writel(dr->diepmsk, hsotg->regs + DIEPMSK);
|
||||
dwc2_writel(dr->doepmsk, hsotg->regs + DOEPMSK);
|
||||
|
||||
for (i = 0; i < hsotg->num_of_eps; i++) {
|
||||
/* Restore IN EPs */
|
||||
dwc2_writel(dr->diepctl[i], hsotg->regs + DIEPCTL(i));
|
||||
dwc2_writel(dr->dieptsiz[i], hsotg->regs + DIEPTSIZ(i));
|
||||
dwc2_writel(dr->diepdma[i], hsotg->regs + DIEPDMA(i));
|
||||
|
||||
/* Restore OUT EPs */
|
||||
dwc2_writel(dr->doepctl[i], hsotg->regs + DOEPCTL(i));
|
||||
dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i));
|
||||
dwc2_writel(dr->doepdma[i], hsotg->regs + DOEPDMA(i));
|
||||
}
|
||||
|
||||
/* Set the Power-On Programming done bit */
|
||||
dctl = dwc2_readl(hsotg->regs + DCTL);
|
||||
dctl |= DCTL_PWRONPRGDONE;
|
||||
dwc2_writel(dctl, hsotg->regs + DCTL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -75,8 +75,6 @@ struct dwc2_qh;
|
||||
* (micro)frame
|
||||
* @xfer_buf: Pointer to current transfer buffer position
|
||||
* @xfer_dma: DMA address of xfer_buf
|
||||
* @align_buf: In Buffer DMA mode this will be used if xfer_buf is not
|
||||
* DWORD aligned
|
||||
* @xfer_len: Total number of bytes to transfer
|
||||
* @xfer_count: Number of bytes transferred so far
|
||||
* @start_pkt_count: Packet count at start of transfer
|
||||
@ -108,6 +106,7 @@ struct dwc2_qh;
|
||||
* @hc_list_entry: For linking to list of host channels
|
||||
* @desc_list_addr: Current QH's descriptor list DMA address
|
||||
* @desc_list_sz: Current QH's descriptor list size
|
||||
* @split_order_list_entry: List entry for keeping track of the order of splits
|
||||
*
|
||||
* This structure represents the state of a single host channel when acting in
|
||||
* host mode. It contains the data items needed to transfer packets to an
|
||||
@ -133,7 +132,6 @@ struct dwc2_host_chan {
|
||||
|
||||
u8 *xfer_buf;
|
||||
dma_addr_t xfer_dma;
|
||||
dma_addr_t align_buf;
|
||||
u32 xfer_len;
|
||||
u32 xfer_count;
|
||||
u16 start_pkt_count;
|
||||
@ -161,6 +159,7 @@ struct dwc2_host_chan {
|
||||
struct list_head hc_list_entry;
|
||||
dma_addr_t desc_list_addr;
|
||||
u32 desc_list_sz;
|
||||
struct list_head split_order_list_entry;
|
||||
};
|
||||
|
||||
struct dwc2_hcd_pipe_info {
|
||||
@ -213,9 +212,47 @@ enum dwc2_transaction_type {
|
||||
DWC2_TRANSACTION_ALL,
|
||||
};
|
||||
|
||||
/* The number of elements per LS bitmap (per port on multi_tt) */
|
||||
#define DWC2_ELEMENTS_PER_LS_BITMAP DIV_ROUND_UP(DWC2_LS_SCHEDULE_SLICES, \
|
||||
BITS_PER_LONG)
|
||||
|
||||
/**
|
||||
* struct dwc2_tt - dwc2 data associated with a usb_tt
|
||||
*
|
||||
* @refcount: Number of Queue Heads (QHs) holding a reference.
|
||||
* @usb_tt: Pointer back to the official usb_tt.
|
||||
* @periodic_bitmaps: Bitmap for which parts of the 1ms frame are accounted
|
||||
* for already. Each is DWC2_ELEMENTS_PER_LS_BITMAP
|
||||
* elements (so sizeof(long) times that in bytes).
|
||||
*
|
||||
* This structure is stored in the hcpriv of the official usb_tt.
|
||||
*/
|
||||
struct dwc2_tt {
|
||||
int refcount;
|
||||
struct usb_tt *usb_tt;
|
||||
unsigned long periodic_bitmaps[];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dwc2_hs_transfer_time - Info about a transfer on the high speed bus.
|
||||
*
|
||||
* @start_schedule_usecs: The start time on the main bus schedule. Note that
|
||||
* the main bus schedule is tightly packed and this
|
||||
* time should be interpreted as tightly packed (so
|
||||
* uFrame 0 starts at 0 us, uFrame 1 starts at 100 us
|
||||
* instead of 125 us).
|
||||
* @duration_us: How long this transfer goes.
|
||||
*/
|
||||
|
||||
struct dwc2_hs_transfer_time {
|
||||
u32 start_schedule_us;
|
||||
u16 duration_us;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dwc2_qh - Software queue head structure
|
||||
*
|
||||
* @hsotg: The HCD state structure for the DWC OTG controller
|
||||
* @ep_type: Endpoint type. One of the following values:
|
||||
* - USB_ENDPOINT_XFER_CONTROL
|
||||
* - USB_ENDPOINT_XFER_BULK
|
||||
@ -236,17 +273,35 @@ enum dwc2_transaction_type {
|
||||
* @do_split: Full/low speed endpoint on high-speed hub requires split
|
||||
* @td_first: Index of first activated isochronous transfer descriptor
|
||||
* @td_last: Index of last activated isochronous transfer descriptor
|
||||
* @usecs: Bandwidth in microseconds per (micro)frame
|
||||
* @interval: Interval between transfers in (micro)frames
|
||||
* @sched_frame: (Micro)frame to initialize a periodic transfer.
|
||||
* The transfer executes in the following (micro)frame.
|
||||
* @frame_usecs: Internal variable used by the microframe scheduler
|
||||
* @start_split_frame: (Micro)frame at which last start split was initialized
|
||||
* @host_us: Bandwidth in microseconds per transfer as seen by host
|
||||
* @device_us: Bandwidth in microseconds per transfer as seen by device
|
||||
* @host_interval: Interval between transfers as seen by the host. If
|
||||
* the host is high speed and the device is low speed this
|
||||
* will be 8 times device interval.
|
||||
* @device_interval: Interval between transfers as seen by the device.
|
||||
* interval.
|
||||
* @next_active_frame: (Micro)frame _before_ we next need to put something on
|
||||
* the bus. We'll move the qh to active here. If the
|
||||
* host is in high speed mode this will be a uframe. If
|
||||
* the host is in low speed mode this will be a full frame.
|
||||
* @start_active_frame: If we are partway through a split transfer, this will be
|
||||
* what next_active_frame was when we started. Otherwise
|
||||
* it should always be the same as next_active_frame.
|
||||
* @num_hs_transfers: Number of transfers in hs_transfers.
|
||||
* Normally this is 1 but can be more than one for splits.
|
||||
* Always >= 1 unless the host is in low/full speed mode.
|
||||
* @hs_transfers: Transfers that are scheduled as seen by the high speed
|
||||
* bus. Not used if host is in low or full speed mode (but
|
||||
* note that it IS USED if the device is low or full speed
|
||||
* as long as the HOST is in high speed mode).
|
||||
* @ls_start_schedule_slice: Start time (in slices) on the low speed bus
|
||||
* schedule that's being used by this device. This
|
||||
* will be on the periodic_bitmap in a
|
||||
* "struct dwc2_tt". Not used if this device is high
|
||||
* speed. Note that this is in "schedule slice" which
|
||||
* is tightly packed.
|
||||
* @ls_duration_us: Duration on the low speed bus schedule.
|
||||
* @ntd: Actual number of transfer descriptors in a list
|
||||
* @dw_align_buf: Used instead of original buffer if its physical address
|
||||
* is not dword-aligned
|
||||
* @dw_align_buf_size: Size of dw_align_buf
|
||||
* @dw_align_buf_dma: DMA address for dw_align_buf
|
||||
* @qtd_list: List of QTDs for this QH
|
||||
* @channel: Host channel currently processing transfers for this QH
|
||||
* @qh_list_entry: Entry for QH in either the periodic or non-periodic
|
||||
@ -257,13 +312,20 @@ enum dwc2_transaction_type {
|
||||
* @n_bytes: Xfer Bytes array. Each element corresponds to a transfer
|
||||
* descriptor and indicates original XferSize value for the
|
||||
* descriptor
|
||||
* @unreserve_timer: Timer for releasing periodic reservation.
|
||||
* @dwc2_tt: Pointer to our tt info (or NULL if no tt).
|
||||
* @ttport: Port number within our tt.
|
||||
* @tt_buffer_dirty True if clear_tt_buffer_complete is pending
|
||||
* @unreserve_pending: True if we planned to unreserve but haven't yet.
|
||||
* @schedule_low_speed: True if we have a low/full speed component (either the
|
||||
* host is in low/full speed mode or do_split).
|
||||
*
|
||||
* A Queue Head (QH) holds the static characteristics of an endpoint and
|
||||
* maintains a list of transfers (QTDs) for that endpoint. A QH structure may
|
||||
* be entered in either the non-periodic or periodic schedule.
|
||||
*/
|
||||
struct dwc2_qh {
|
||||
struct dwc2_hsotg *hsotg;
|
||||
u8 ep_type;
|
||||
u8 ep_is_in;
|
||||
u16 maxp;
|
||||
@ -273,15 +335,16 @@ struct dwc2_qh {
|
||||
u8 do_split;
|
||||
u8 td_first;
|
||||
u8 td_last;
|
||||
u16 usecs;
|
||||
u16 interval;
|
||||
u16 sched_frame;
|
||||
u16 frame_usecs[8];
|
||||
u16 start_split_frame;
|
||||
u16 host_us;
|
||||
u16 device_us;
|
||||
u16 host_interval;
|
||||
u16 device_interval;
|
||||
u16 next_active_frame;
|
||||
u16 start_active_frame;
|
||||
s16 num_hs_transfers;
|
||||
struct dwc2_hs_transfer_time hs_transfers[DWC2_HS_SCHEDULE_UFRAMES];
|
||||
u32 ls_start_schedule_slice;
|
||||
u16 ntd;
|
||||
u8 *dw_align_buf;
|
||||
int dw_align_buf_size;
|
||||
dma_addr_t dw_align_buf_dma;
|
||||
struct list_head qtd_list;
|
||||
struct dwc2_host_chan *channel;
|
||||
struct list_head qh_list_entry;
|
||||
@ -289,7 +352,12 @@ struct dwc2_qh {
|
||||
dma_addr_t desc_list_dma;
|
||||
u32 desc_list_sz;
|
||||
u32 *n_bytes;
|
||||
struct timer_list unreserve_timer;
|
||||
struct dwc2_tt *dwc_tt;
|
||||
int ttport;
|
||||
unsigned tt_buffer_dirty:1;
|
||||
unsigned unreserve_pending:1;
|
||||
unsigned schedule_low_speed:1;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -362,6 +430,8 @@ struct hc_xfer_info {
|
||||
};
|
||||
#endif
|
||||
|
||||
u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg);
|
||||
|
||||
/* Gets the struct usb_hcd that contains a struct dwc2_hsotg */
|
||||
static inline struct usb_hcd *dwc2_hsotg_to_hcd(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
@ -383,6 +453,12 @@ static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
|
||||
dwc2_writel(mask, hsotg->regs + HCINTMSK(chnum));
|
||||
}
|
||||
|
||||
void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan);
|
||||
void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
|
||||
enum dwc2_halt_status halt_status);
|
||||
void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_host_chan *chan);
|
||||
|
||||
/*
|
||||
* Reads HPRT0 in preparation to modify. It keeps the WC bits 0 so that if they
|
||||
* are read as 1, they won't clear when written back.
|
||||
@ -456,7 +532,6 @@ extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
|
||||
|
||||
/* Schedule Queue Functions */
|
||||
/* Implemented in hcd_queue.c */
|
||||
extern void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg);
|
||||
extern struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_hcd_urb *urb,
|
||||
gfp_t mem_flags);
|
||||
@ -571,6 +646,11 @@ static inline u16 dwc2_frame_num_inc(u16 frame, u16 inc)
|
||||
return (frame + inc) & HFNUM_MAX_FRNUM;
|
||||
}
|
||||
|
||||
static inline u16 dwc2_frame_num_dec(u16 frame, u16 dec)
|
||||
{
|
||||
return (frame + HFNUM_MAX_FRNUM + 1 - dec) & HFNUM_MAX_FRNUM;
|
||||
}
|
||||
|
||||
static inline u16 dwc2_full_frame_num(u16 frame)
|
||||
{
|
||||
return (frame & HFNUM_MAX_FRNUM) >> 3;
|
||||
@ -648,7 +728,7 @@ static inline u16 dwc2_hcd_get_ep_bandwidth(struct dwc2_hsotg *hsotg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
return qh->usecs;
|
||||
return qh->host_us;
|
||||
}
|
||||
|
||||
extern void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
|
||||
@ -717,6 +797,12 @@ extern void dwc2_host_start(struct dwc2_hsotg *hsotg);
|
||||
extern void dwc2_host_disconnect(struct dwc2_hsotg *hsotg);
|
||||
extern void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context,
|
||||
int *hub_addr, int *hub_port);
|
||||
extern struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg,
|
||||
void *context, gfp_t mem_flags,
|
||||
int *ttport);
|
||||
|
||||
extern void dwc2_host_put_tt_info(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_tt *dwc_tt);
|
||||
extern int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context);
|
||||
extern void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
|
||||
int status);
|
||||
@ -739,7 +825,7 @@ do { \
|
||||
_qtd_ = list_entry((_qh_)->qtd_list.next, struct dwc2_qtd, \
|
||||
qtd_list_entry); \
|
||||
if (usb_pipeint(_qtd_->urb->pipe) && \
|
||||
(_qh_)->start_split_frame != 0 && !_qtd_->complete_split) { \
|
||||
(_qh_)->start_active_frame != 0 && !_qtd_->complete_split) { \
|
||||
_hfnum_.d32 = dwc2_readl((_hcd_)->regs + HFNUM); \
|
||||
switch (_hfnum_.b.frnum & 0x7) { \
|
||||
case 7: \
|
||||
|
@ -81,7 +81,7 @@ static u16 dwc2_max_desc_num(struct dwc2_qh *qh)
|
||||
static u16 dwc2_frame_incr_val(struct dwc2_qh *qh)
|
||||
{
|
||||
return qh->dev_speed == USB_SPEED_HIGH ?
|
||||
(qh->interval + 8 - 1) / 8 : qh->interval;
|
||||
(qh->host_interval + 8 - 1) / 8 : qh->host_interval;
|
||||
}
|
||||
|
||||
static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
|
||||
@ -111,7 +111,7 @@ static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
|
||||
dma_unmap_single(hsotg->dev, qh->desc_list_dma,
|
||||
qh->desc_list_sz,
|
||||
DMA_FROM_DEVICE);
|
||||
kfree(qh->desc_list);
|
||||
kmem_cache_free(desc_cache, qh->desc_list);
|
||||
qh->desc_list = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -252,7 +252,7 @@ static void dwc2_update_frame_list(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
|
||||
chan = qh->channel;
|
||||
inc = dwc2_frame_incr_val(qh);
|
||||
if (qh->ep_type == USB_ENDPOINT_XFER_ISOC)
|
||||
i = dwc2_frame_list_idx(qh->sched_frame);
|
||||
i = dwc2_frame_list_idx(qh->next_active_frame);
|
||||
else
|
||||
i = 0;
|
||||
|
||||
@ -278,13 +278,13 @@ static void dwc2_update_frame_list(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
|
||||
return;
|
||||
|
||||
chan->schinfo = 0;
|
||||
if (chan->speed == USB_SPEED_HIGH && qh->interval) {
|
||||
if (chan->speed == USB_SPEED_HIGH && qh->host_interval) {
|
||||
j = 1;
|
||||
/* TODO - check this */
|
||||
inc = (8 + qh->interval - 1) / qh->interval;
|
||||
inc = (8 + qh->host_interval - 1) / qh->host_interval;
|
||||
for (i = 0; i < inc; i++) {
|
||||
chan->schinfo |= j;
|
||||
j = j << qh->interval;
|
||||
j = j << qh->host_interval;
|
||||
}
|
||||
} else {
|
||||
chan->schinfo = 0xff;
|
||||
@ -431,7 +431,10 @@ static u16 dwc2_calc_starting_frame(struct dwc2_hsotg *hsotg,
|
||||
|
||||
hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
|
||||
|
||||
/* sched_frame is always frame number (not uFrame) both in FS and HS! */
|
||||
/*
|
||||
* next_active_frame is always frame number (not uFrame) both in FS
|
||||
* and HS!
|
||||
*/
|
||||
|
||||
/*
|
||||
* skip_frames is used to limit activated descriptors number
|
||||
@ -514,13 +517,13 @@ static u16 dwc2_recalc_initial_desc_idx(struct dwc2_hsotg *hsotg,
|
||||
*/
|
||||
fr_idx_tmp = dwc2_frame_list_idx(frame);
|
||||
fr_idx = (FRLISTEN_64_SIZE +
|
||||
dwc2_frame_list_idx(qh->sched_frame) - fr_idx_tmp)
|
||||
% dwc2_frame_incr_val(qh);
|
||||
dwc2_frame_list_idx(qh->next_active_frame) -
|
||||
fr_idx_tmp) % dwc2_frame_incr_val(qh);
|
||||
fr_idx = (fr_idx + fr_idx_tmp) % FRLISTEN_64_SIZE;
|
||||
} else {
|
||||
qh->sched_frame = dwc2_calc_starting_frame(hsotg, qh,
|
||||
qh->next_active_frame = dwc2_calc_starting_frame(hsotg, qh,
|
||||
&skip_frames);
|
||||
fr_idx = dwc2_frame_list_idx(qh->sched_frame);
|
||||
fr_idx = dwc2_frame_list_idx(qh->next_active_frame);
|
||||
}
|
||||
|
||||
qh->td_first = qh->td_last = dwc2_frame_to_desc_idx(qh, fr_idx);
|
||||
@ -583,7 +586,7 @@ static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
|
||||
u16 next_idx;
|
||||
|
||||
idx = qh->td_last;
|
||||
inc = qh->interval;
|
||||
inc = qh->host_interval;
|
||||
hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
|
||||
cur_idx = dwc2_frame_list_idx(hsotg->frame_number);
|
||||
next_idx = dwc2_desclist_idx_inc(qh->td_last, inc, qh->dev_speed);
|
||||
@ -605,11 +608,11 @@ static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
|
||||
}
|
||||
}
|
||||
|
||||
if (qh->interval) {
|
||||
ntd_max = (dwc2_max_desc_num(qh) + qh->interval - 1) /
|
||||
qh->interval;
|
||||
if (qh->host_interval) {
|
||||
ntd_max = (dwc2_max_desc_num(qh) + qh->host_interval - 1) /
|
||||
qh->host_interval;
|
||||
if (skip_frames && !qh->channel)
|
||||
ntd_max -= skip_frames / qh->interval;
|
||||
ntd_max -= skip_frames / qh->host_interval;
|
||||
}
|
||||
|
||||
max_xfer_size = qh->dev_speed == USB_SPEED_HIGH ?
|
||||
@ -1029,7 +1032,7 @@ static void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
|
||||
idx);
|
||||
if (rc < 0)
|
||||
return;
|
||||
idx = dwc2_desclist_idx_inc(idx, qh->interval,
|
||||
idx = dwc2_desclist_idx_inc(idx, qh->host_interval,
|
||||
chan->speed);
|
||||
if (!rc)
|
||||
continue;
|
||||
@ -1039,7 +1042,7 @@ static void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
|
||||
|
||||
/* rc == DWC2_CMPL_STOP */
|
||||
|
||||
if (qh->interval >= 32)
|
||||
if (qh->host_interval >= 32)
|
||||
goto stop_scan;
|
||||
|
||||
qh->td_first = idx;
|
||||
@ -1242,8 +1245,10 @@ static void dwc2_complete_non_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
|
||||
for (i = 0; i < qtd_desc_count; i++) {
|
||||
if (dwc2_process_non_isoc_desc(hsotg, chan, chnum, qtd,
|
||||
desc_num, halt_status,
|
||||
&xfer_done))
|
||||
&xfer_done)) {
|
||||
qtd = NULL;
|
||||
goto stop_scan;
|
||||
}
|
||||
|
||||
desc_num++;
|
||||
}
|
||||
@ -1258,7 +1263,7 @@ stop_scan:
|
||||
if (halt_status == DWC2_HC_XFER_STALL)
|
||||
qh->data_toggle = DWC2_HC_PID_DATA0;
|
||||
else
|
||||
dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
|
||||
dwc2_hcd_save_data_toggle(hsotg, chan, chnum, NULL);
|
||||
}
|
||||
|
||||
if (halt_status == DWC2_HC_XFER_COMPLETE) {
|
||||
@ -1326,7 +1331,7 @@ void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
|
||||
dwc2_hcd_qh_unlink(hsotg, qh);
|
||||
} else {
|
||||
/* Keep in assigned schedule to continue transfer */
|
||||
list_move(&qh->qh_list_entry,
|
||||
list_move_tail(&qh->qh_list_entry,
|
||||
&hsotg->periodic_sched_assigned);
|
||||
/*
|
||||
* If channel has been halted during giveback of urb
|
||||
|
@ -55,12 +55,16 @@
|
||||
/* This function is for debug only */
|
||||
static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
|
||||
u16 curr_frame_number = hsotg->frame_number;
|
||||
u16 expected = dwc2_frame_num_inc(hsotg->last_frame_num, 1);
|
||||
|
||||
if (expected != curr_frame_number)
|
||||
dwc2_sch_vdbg(hsotg, "MISSED SOF %04x != %04x\n",
|
||||
expected, curr_frame_number);
|
||||
|
||||
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
|
||||
if (hsotg->frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
|
||||
if (((hsotg->last_frame_num + 1) & HFNUM_MAX_FRNUM) !=
|
||||
curr_frame_number) {
|
||||
if (expected != curr_frame_number) {
|
||||
hsotg->frame_num_array[hsotg->frame_num_idx] =
|
||||
curr_frame_number;
|
||||
hsotg->last_frame_num_array[hsotg->frame_num_idx] =
|
||||
@ -79,14 +83,15 @@ static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg)
|
||||
}
|
||||
hsotg->dumped_frame_num_array = 1;
|
||||
}
|
||||
hsotg->last_frame_num = curr_frame_number;
|
||||
#endif
|
||||
hsotg->last_frame_num = curr_frame_number;
|
||||
}
|
||||
|
||||
static void dwc2_hc_handle_tt_clear(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_host_chan *chan,
|
||||
struct dwc2_qtd *qtd)
|
||||
{
|
||||
struct usb_device *root_hub = dwc2_hsotg_to_hcd(hsotg)->self.root_hub;
|
||||
struct urb *usb_urb;
|
||||
|
||||
if (!chan->qh)
|
||||
@ -102,6 +107,15 @@ static void dwc2_hc_handle_tt_clear(struct dwc2_hsotg *hsotg,
|
||||
if (!usb_urb || !usb_urb->dev || !usb_urb->dev->tt)
|
||||
return;
|
||||
|
||||
/*
|
||||
* The root hub doesn't really have a TT, but Linux thinks it
|
||||
* does because how could you have a "high speed hub" that
|
||||
* directly talks directly to low speed devices without a TT?
|
||||
* It's all lies. Lies, I tell you.
|
||||
*/
|
||||
if (usb_urb->dev->tt->hub == root_hub)
|
||||
return;
|
||||
|
||||
if (qtd->urb->status != -EPIPE && qtd->urb->status != -EREMOTEIO) {
|
||||
chan->qh->tt_buffer_dirty = 1;
|
||||
if (usb_hub_clear_tt_buffer(usb_urb))
|
||||
@ -138,14 +152,20 @@ static void dwc2_sof_intr(struct dwc2_hsotg *hsotg)
|
||||
while (qh_entry != &hsotg->periodic_sched_inactive) {
|
||||
qh = list_entry(qh_entry, struct dwc2_qh, qh_list_entry);
|
||||
qh_entry = qh_entry->next;
|
||||
if (dwc2_frame_num_le(qh->sched_frame, hsotg->frame_number))
|
||||
if (dwc2_frame_num_le(qh->next_active_frame,
|
||||
hsotg->frame_number)) {
|
||||
dwc2_sch_vdbg(hsotg, "QH=%p ready fn=%04x, nxt=%04x\n",
|
||||
qh, hsotg->frame_number,
|
||||
qh->next_active_frame);
|
||||
|
||||
/*
|
||||
* Move QH to the ready list to be executed next
|
||||
* (micro)frame
|
||||
*/
|
||||
list_move(&qh->qh_list_entry,
|
||||
list_move_tail(&qh->qh_list_entry,
|
||||
&hsotg->periodic_sched_ready);
|
||||
}
|
||||
}
|
||||
tr_type = dwc2_hcd_select_transactions(hsotg);
|
||||
if (tr_type != DWC2_TRANSACTION_NONE)
|
||||
dwc2_hcd_queue_transactions(hsotg, tr_type);
|
||||
@ -472,18 +492,6 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
|
||||
xfer_length = urb->length - urb->actual_length;
|
||||
}
|
||||
|
||||
/* Non DWORD-aligned buffer case handling */
|
||||
if (chan->align_buf && xfer_length) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
|
||||
dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
|
||||
chan->qh->dw_align_buf_size,
|
||||
chan->ep_is_in ?
|
||||
DMA_FROM_DEVICE : DMA_TO_DEVICE);
|
||||
if (chan->ep_is_in)
|
||||
memcpy(urb->buf + urb->actual_length,
|
||||
chan->qh->dw_align_buf, xfer_length);
|
||||
}
|
||||
|
||||
dev_vdbg(hsotg->dev, "urb->actual_length=%d xfer_length=%d\n",
|
||||
urb->actual_length, xfer_length);
|
||||
urb->actual_length += xfer_length;
|
||||
@ -573,21 +581,6 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
|
||||
frame_desc->status = 0;
|
||||
frame_desc->actual_length = dwc2_get_actual_xfer_length(hsotg,
|
||||
chan, chnum, qtd, halt_status, NULL);
|
||||
|
||||
/* Non DWORD-aligned buffer case handling */
|
||||
if (chan->align_buf && frame_desc->actual_length) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
|
||||
__func__);
|
||||
dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
|
||||
chan->qh->dw_align_buf_size,
|
||||
chan->ep_is_in ?
|
||||
DMA_FROM_DEVICE : DMA_TO_DEVICE);
|
||||
if (chan->ep_is_in)
|
||||
memcpy(urb->buf + frame_desc->offset +
|
||||
qtd->isoc_split_offset,
|
||||
chan->qh->dw_align_buf,
|
||||
frame_desc->actual_length);
|
||||
}
|
||||
break;
|
||||
case DWC2_HC_XFER_FRAME_OVERRUN:
|
||||
urb->error_count++;
|
||||
@ -608,21 +601,6 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
|
||||
frame_desc->actual_length = dwc2_get_actual_xfer_length(hsotg,
|
||||
chan, chnum, qtd, halt_status, NULL);
|
||||
|
||||
/* Non DWORD-aligned buffer case handling */
|
||||
if (chan->align_buf && frame_desc->actual_length) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
|
||||
__func__);
|
||||
dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
|
||||
chan->qh->dw_align_buf_size,
|
||||
chan->ep_is_in ?
|
||||
DMA_FROM_DEVICE : DMA_TO_DEVICE);
|
||||
if (chan->ep_is_in)
|
||||
memcpy(urb->buf + frame_desc->offset +
|
||||
qtd->isoc_split_offset,
|
||||
chan->qh->dw_align_buf,
|
||||
frame_desc->actual_length);
|
||||
}
|
||||
|
||||
/* Skip whole frame */
|
||||
if (chan->qh->do_split &&
|
||||
chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in &&
|
||||
@ -688,8 +666,6 @@ static void dwc2_deactivate_qh(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
|
||||
}
|
||||
|
||||
no_qtd:
|
||||
if (qh->channel)
|
||||
qh->channel->align_buf = 0;
|
||||
qh->channel = NULL;
|
||||
dwc2_hcd_qh_deactivate(hsotg, qh, continue_split);
|
||||
}
|
||||
@ -846,7 +822,7 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
|
||||
* halt to be queued when the periodic schedule is
|
||||
* processed.
|
||||
*/
|
||||
list_move(&chan->qh->qh_list_entry,
|
||||
list_move_tail(&chan->qh->qh_list_entry,
|
||||
&hsotg->periodic_sched_assigned);
|
||||
|
||||
/*
|
||||
@ -954,14 +930,6 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
|
||||
|
||||
frame_desc->actual_length += len;
|
||||
|
||||
if (chan->align_buf) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
|
||||
dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
|
||||
chan->qh->dw_align_buf_size, DMA_FROM_DEVICE);
|
||||
memcpy(qtd->urb->buf + frame_desc->offset +
|
||||
qtd->isoc_split_offset, chan->qh->dw_align_buf, len);
|
||||
}
|
||||
|
||||
qtd->isoc_split_offset += len;
|
||||
|
||||
if (frame_desc->actual_length >= frame_desc->length) {
|
||||
@ -1184,19 +1152,6 @@ static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
|
||||
xfer_length = urb->length - urb->actual_length;
|
||||
}
|
||||
|
||||
/* Non DWORD-aligned buffer case handling */
|
||||
if (chan->align_buf && xfer_length && chan->ep_is_in) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
|
||||
dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
|
||||
chan->qh->dw_align_buf_size,
|
||||
chan->ep_is_in ?
|
||||
DMA_FROM_DEVICE : DMA_TO_DEVICE);
|
||||
if (chan->ep_is_in)
|
||||
memcpy(urb->buf + urb->actual_length,
|
||||
chan->qh->dw_align_buf,
|
||||
xfer_length);
|
||||
}
|
||||
|
||||
urb->actual_length += xfer_length;
|
||||
|
||||
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
||||
@ -1416,14 +1371,50 @@ static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg,
|
||||
|
||||
if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
|
||||
chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
|
||||
struct dwc2_qh *qh = chan->qh;
|
||||
bool past_end;
|
||||
|
||||
if (hsotg->core_params->uframe_sched <= 0) {
|
||||
int frnum = dwc2_hcd_get_frame_number(hsotg);
|
||||
|
||||
if (dwc2_full_frame_num(frnum) !=
|
||||
dwc2_full_frame_num(chan->qh->sched_frame)) {
|
||||
/* Don't have num_hs_transfers; simple logic */
|
||||
past_end = dwc2_full_frame_num(frnum) !=
|
||||
dwc2_full_frame_num(qh->next_active_frame);
|
||||
} else {
|
||||
int end_frnum;
|
||||
|
||||
/*
|
||||
* No longer in the same full speed frame.
|
||||
* Treat this as a transaction error.
|
||||
* Figure out the end frame based on schedule.
|
||||
*
|
||||
* We don't want to go on trying again and again
|
||||
* forever. Let's stop when we've done all the
|
||||
* transfers that were scheduled.
|
||||
*
|
||||
* We're going to be comparing start_active_frame
|
||||
* and next_active_frame, both of which are 1
|
||||
* before the time the packet goes on the wire,
|
||||
* so that cancels out. Basically if had 1
|
||||
* transfer and we saw 1 NYET then we're done.
|
||||
* We're getting a NYET here so if next >=
|
||||
* (start + num_transfers) we're done. The
|
||||
* complexity is that for all but ISOC_OUT we
|
||||
* skip one slot.
|
||||
*/
|
||||
end_frnum = dwc2_frame_num_inc(
|
||||
qh->start_active_frame,
|
||||
qh->num_hs_transfers);
|
||||
|
||||
if (qh->ep_type != USB_ENDPOINT_XFER_ISOC ||
|
||||
qh->ep_is_in)
|
||||
end_frnum =
|
||||
dwc2_frame_num_inc(end_frnum, 1);
|
||||
|
||||
past_end = dwc2_frame_num_le(
|
||||
end_frnum, qh->next_active_frame);
|
||||
}
|
||||
|
||||
if (past_end) {
|
||||
/* Treat this as a transaction error. */
|
||||
#if 0
|
||||
/*
|
||||
* Todo: Fix system performance so this can
|
||||
@ -2008,6 +1999,16 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
|
||||
}
|
||||
|
||||
dwc2_writel(hcint, hsotg->regs + HCINT(chnum));
|
||||
|
||||
/*
|
||||
* If we got an interrupt after someone called
|
||||
* dwc2_hcd_endpoint_disable() we don't want to crash below
|
||||
*/
|
||||
if (!chan->qh) {
|
||||
dev_warn(hsotg->dev, "Interrupt on disabled channel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
chan->hcint = hcint;
|
||||
hcint &= hcintmsk;
|
||||
|
||||
@ -2130,6 +2131,7 @@ static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
u32 haint;
|
||||
int i;
|
||||
struct dwc2_host_chan *chan, *chan_tmp;
|
||||
|
||||
haint = dwc2_readl(hsotg->regs + HAINT);
|
||||
if (dbg_perio()) {
|
||||
@ -2138,6 +2140,22 @@ static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
|
||||
dev_vdbg(hsotg->dev, "HAINT=%08x\n", haint);
|
||||
}
|
||||
|
||||
/*
|
||||
* According to USB 2.0 spec section 11.18.8, a host must
|
||||
* issue complete-split transactions in a microframe for a
|
||||
* set of full-/low-speed endpoints in the same relative
|
||||
* order as the start-splits were issued in a microframe for.
|
||||
*/
|
||||
list_for_each_entry_safe(chan, chan_tmp, &hsotg->split_order,
|
||||
split_order_list_entry) {
|
||||
int hc_num = chan->hc_num;
|
||||
|
||||
if (haint & (1 << hc_num)) {
|
||||
dwc2_hc_n_intr(hsotg, hc_num);
|
||||
haint &= ~(1 << hc_num);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < hsotg->core_params->host_channels; i++) {
|
||||
if (haint & (1 << i))
|
||||
dwc2_hc_n_intr(hsotg, i);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -126,10 +126,10 @@ static const struct dwc2_core_params params_rk3066 = {
|
||||
.speed = -1,
|
||||
.enable_dynamic_fifo = 1,
|
||||
.en_multiple_tx_fifo = -1,
|
||||
.host_rx_fifo_size = 520, /* 520 DWORDs */
|
||||
.host_rx_fifo_size = 525, /* 525 DWORDs */
|
||||
.host_nperio_tx_fifo_size = 128, /* 128 DWORDs */
|
||||
.host_perio_tx_fifo_size = 256, /* 256 DWORDs */
|
||||
.max_transfer_size = 65535,
|
||||
.max_transfer_size = -1,
|
||||
.max_packet_count = -1,
|
||||
.host_channels = -1,
|
||||
.phy_type = -1,
|
||||
@ -149,6 +149,38 @@ static const struct dwc2_core_params params_rk3066 = {
|
||||
.hibernation = -1,
|
||||
};
|
||||
|
||||
static const struct dwc2_core_params params_ltq = {
|
||||
.otg_cap = 2, /* non-HNP/non-SRP */
|
||||
.otg_ver = -1,
|
||||
.dma_enable = -1,
|
||||
.dma_desc_enable = -1,
|
||||
.dma_desc_fs_enable = -1,
|
||||
.speed = -1,
|
||||
.enable_dynamic_fifo = -1,
|
||||
.en_multiple_tx_fifo = -1,
|
||||
.host_rx_fifo_size = 288, /* 288 DWORDs */
|
||||
.host_nperio_tx_fifo_size = 128, /* 128 DWORDs */
|
||||
.host_perio_tx_fifo_size = 96, /* 96 DWORDs */
|
||||
.max_transfer_size = 65535,
|
||||
.max_packet_count = 511,
|
||||
.host_channels = -1,
|
||||
.phy_type = -1,
|
||||
.phy_utmi_width = -1,
|
||||
.phy_ulpi_ddr = -1,
|
||||
.phy_ulpi_ext_vbus = -1,
|
||||
.i2c_enable = -1,
|
||||
.ulpi_fs_ls = -1,
|
||||
.host_support_fs_ls_low_power = -1,
|
||||
.host_ls_low_power_phy_clk = -1,
|
||||
.ts_dline = -1,
|
||||
.reload_ctl = -1,
|
||||
.ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
|
||||
GAHBCFG_HBSTLEN_SHIFT,
|
||||
.uframe_sched = -1,
|
||||
.external_id_pin_ctl = -1,
|
||||
.hibernation = -1,
|
||||
};
|
||||
|
||||
/*
|
||||
* Check the dr_mode against the module configuration and hardware
|
||||
* capabilities.
|
||||
@ -428,6 +460,8 @@ static const struct of_device_id dwc2_of_match_table[] = {
|
||||
{ .compatible = "brcm,bcm2835-usb", .data = ¶ms_bcm2835 },
|
||||
{ .compatible = "hisilicon,hi6220-usb", .data = ¶ms_hi6220 },
|
||||
{ .compatible = "rockchip,rk3066-usb", .data = ¶ms_rk3066 },
|
||||
{ .compatible = "lantiq,arx100-usb", .data = ¶ms_ltq },
|
||||
{ .compatible = "lantiq,xrx200-usb", .data = ¶ms_ltq },
|
||||
{ .compatible = "snps,dwc2", .data = NULL },
|
||||
{ .compatible = "samsung,s3c6400-hsotg", .data = NULL},
|
||||
{},
|
||||
|
@ -962,10 +962,6 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
fladj = pdata->fladj_value;
|
||||
}
|
||||
|
||||
/* default to superspeed if no maximum_speed passed */
|
||||
if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
|
||||
dwc->maximum_speed = USB_SPEED_SUPER;
|
||||
|
||||
dwc->lpm_nyet_threshold = lpm_nyet_threshold;
|
||||
dwc->tx_de_emphasis = tx_de_emphasis;
|
||||
|
||||
@ -1016,6 +1012,33 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/* Check the maximum_speed parameter */
|
||||
switch (dwc->maximum_speed) {
|
||||
case USB_SPEED_LOW:
|
||||
case USB_SPEED_FULL:
|
||||
case USB_SPEED_HIGH:
|
||||
case USB_SPEED_SUPER:
|
||||
case USB_SPEED_SUPER_PLUS:
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "invalid maximum_speed parameter %d\n",
|
||||
dwc->maximum_speed);
|
||||
/* fall through */
|
||||
case USB_SPEED_UNKNOWN:
|
||||
/* default to superspeed */
|
||||
dwc->maximum_speed = USB_SPEED_SUPER;
|
||||
|
||||
/*
|
||||
* default to superspeed plus if we are capable.
|
||||
*/
|
||||
if (dwc3_is_usb31(dwc) &&
|
||||
(DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) ==
|
||||
DWC3_GHWPARAMS3_SSPHY_IFC_GEN2))
|
||||
dwc->maximum_speed = USB_SPEED_SUPER_PLUS;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Adjust Frame Length */
|
||||
dwc3_frame_length_adjustment(dwc, fladj);
|
||||
|
||||
|
@ -223,7 +223,8 @@
|
||||
/* Global HWPARAMS3 Register */
|
||||
#define DWC3_GHWPARAMS3_SSPHY_IFC(n) ((n) & 3)
|
||||
#define DWC3_GHWPARAMS3_SSPHY_IFC_DIS 0
|
||||
#define DWC3_GHWPARAMS3_SSPHY_IFC_ENA 1
|
||||
#define DWC3_GHWPARAMS3_SSPHY_IFC_GEN1 1
|
||||
#define DWC3_GHWPARAMS3_SSPHY_IFC_GEN2 2 /* DWC_usb31 only */
|
||||
#define DWC3_GHWPARAMS3_HSPHY_IFC(n) (((n) & (3 << 2)) >> 2)
|
||||
#define DWC3_GHWPARAMS3_HSPHY_IFC_DIS 0
|
||||
#define DWC3_GHWPARAMS3_HSPHY_IFC_UTMI 1
|
||||
@ -249,6 +250,7 @@
|
||||
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
|
||||
|
||||
#define DWC3_DCFG_SPEED_MASK (7 << 0)
|
||||
#define DWC3_DCFG_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */
|
||||
#define DWC3_DCFG_SUPERSPEED (4 << 0)
|
||||
#define DWC3_DCFG_HIGHSPEED (0 << 0)
|
||||
#define DWC3_DCFG_FULLSPEED2 (1 << 0)
|
||||
@ -339,6 +341,7 @@
|
||||
|
||||
#define DWC3_DSTS_CONNECTSPD (7 << 0)
|
||||
|
||||
#define DWC3_DSTS_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */
|
||||
#define DWC3_DSTS_SUPERSPEED (4 << 0)
|
||||
#define DWC3_DSTS_HIGHSPEED (0 << 0)
|
||||
#define DWC3_DSTS_FULLSPEED2 (1 << 0)
|
||||
@ -1024,6 +1027,12 @@ struct dwc3_gadget_ep_cmd_params {
|
||||
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
|
||||
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
|
||||
|
||||
/* check whether we are on the DWC_usb31 core */
|
||||
static inline bool dwc3_is_usb31(struct dwc3 *dwc)
|
||||
{
|
||||
return !!(dwc->revision & DWC3_REVISION_IS_DWC31);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
|
||||
int dwc3_host_init(struct dwc3 *dwc);
|
||||
void dwc3_host_exit(struct dwc3 *dwc);
|
||||
|
@ -356,7 +356,8 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
|
||||
*/
|
||||
usb_status |= dwc->gadget.is_selfpowered;
|
||||
|
||||
if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
|
||||
if ((dwc->speed == DWC3_DSTS_SUPERSPEED) ||
|
||||
(dwc->speed == DWC3_DSTS_SUPERSPEED_PLUS)) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
if (reg & DWC3_DCTL_INITU1ENA)
|
||||
usb_status |= 1 << USB_DEV_STAT_U1_ENABLED;
|
||||
@ -426,7 +427,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
|
||||
case USB_DEVICE_U1_ENABLE:
|
||||
if (state != USB_STATE_CONFIGURED)
|
||||
return -EINVAL;
|
||||
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
|
||||
if ((dwc->speed != DWC3_DSTS_SUPERSPEED) &&
|
||||
(dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
|
||||
return -EINVAL;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
@ -440,7 +442,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
|
||||
case USB_DEVICE_U2_ENABLE:
|
||||
if (state != USB_STATE_CONFIGURED)
|
||||
return -EINVAL;
|
||||
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
|
||||
if ((dwc->speed != DWC3_DSTS_SUPERSPEED) &&
|
||||
(dwc->speed != DWC3_DSTS_SUPERSPEED_PLUS))
|
||||
return -EINVAL;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
|
@ -463,7 +463,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc));
|
||||
|
||||
/* Burst size is only needed in SuperSpeed mode */
|
||||
if (dwc->gadget.speed == USB_SPEED_SUPER) {
|
||||
if (dwc->gadget.speed >= USB_SPEED_SUPER) {
|
||||
u32 burst = dep->endpoint.maxburst - 1;
|
||||
|
||||
params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst);
|
||||
@ -1441,7 +1441,8 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
|
||||
|
||||
speed = reg & DWC3_DSTS_CONNECTSPD;
|
||||
if (speed == DWC3_DSTS_SUPERSPEED) {
|
||||
if ((speed == DWC3_DSTS_SUPERSPEED) ||
|
||||
(speed == DWC3_DSTS_SUPERSPEED_PLUS)) {
|
||||
dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
@ -1666,10 +1667,16 @@ static int dwc3_gadget_start(struct usb_gadget *g,
|
||||
case USB_SPEED_HIGH:
|
||||
reg |= DWC3_DSTS_HIGHSPEED;
|
||||
break;
|
||||
case USB_SPEED_SUPER: /* FALLTHROUGH */
|
||||
case USB_SPEED_UNKNOWN: /* FALTHROUGH */
|
||||
case USB_SPEED_SUPER_PLUS:
|
||||
reg |= DWC3_DSTS_SUPERSPEED_PLUS;
|
||||
break;
|
||||
default:
|
||||
reg |= DWC3_DSTS_SUPERSPEED;
|
||||
dev_err(dwc->dev, "invalid dwc->maximum_speed (%d)\n",
|
||||
dwc->maximum_speed);
|
||||
/* fall through */
|
||||
case USB_SPEED_SUPER:
|
||||
reg |= DWC3_DCFG_SUPERSPEED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
@ -2340,7 +2347,8 @@ static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
|
||||
* this. Maybe it becomes part of the power saving plan.
|
||||
*/
|
||||
|
||||
if (speed != DWC3_DSTS_SUPERSPEED)
|
||||
if ((speed != DWC3_DSTS_SUPERSPEED) &&
|
||||
(speed != DWC3_DSTS_SUPERSPEED_PLUS))
|
||||
return;
|
||||
|
||||
/*
|
||||
@ -2369,6 +2377,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
|
||||
dwc3_update_ram_clk_sel(dwc, speed);
|
||||
|
||||
switch (speed) {
|
||||
case DWC3_DCFG_SUPERSPEED_PLUS:
|
||||
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
dwc->gadget.ep0->maxpacket = 512;
|
||||
dwc->gadget.speed = USB_SPEED_SUPER_PLUS;
|
||||
break;
|
||||
case DWC3_DCFG_SUPERSPEED:
|
||||
/*
|
||||
* WORKAROUND: DWC3 revisions <1.90a have an issue which
|
||||
@ -2410,8 +2423,9 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
|
||||
|
||||
/* Enable USB2 LPM Capability */
|
||||
|
||||
if ((dwc->revision > DWC3_REVISION_194A)
|
||||
&& (speed != DWC3_DCFG_SUPERSPEED)) {
|
||||
if ((dwc->revision > DWC3_REVISION_194A) &&
|
||||
(speed != DWC3_DCFG_SUPERSPEED) &&
|
||||
(speed != DWC3_DCFG_SUPERSPEED_PLUS)) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
|
||||
reg |= DWC3_DCFG_LPM_CAP;
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
|
@ -53,6 +53,36 @@ static struct usb_gadget_strings **get_containers_gs(
|
||||
return (struct usb_gadget_strings **)uc->stash;
|
||||
}
|
||||
|
||||
/**
|
||||
* function_descriptors() - get function descriptors for speed
|
||||
* @f: the function
|
||||
* @speed: the speed
|
||||
*
|
||||
* Returns the descriptors or NULL if not set.
|
||||
*/
|
||||
static struct usb_descriptor_header **
|
||||
function_descriptors(struct usb_function *f,
|
||||
enum usb_device_speed speed)
|
||||
{
|
||||
struct usb_descriptor_header **descriptors;
|
||||
|
||||
switch (speed) {
|
||||
case USB_SPEED_SUPER_PLUS:
|
||||
descriptors = f->ssp_descriptors;
|
||||
break;
|
||||
case USB_SPEED_SUPER:
|
||||
descriptors = f->ss_descriptors;
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
descriptors = f->hs_descriptors;
|
||||
break;
|
||||
default:
|
||||
descriptors = f->fs_descriptors;
|
||||
}
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* next_ep_desc() - advance to the next EP descriptor
|
||||
* @t: currect pointer within descriptor array
|
||||
@ -118,6 +148,13 @@ int config_ep_by_speed(struct usb_gadget *g,
|
||||
|
||||
/* select desired speed */
|
||||
switch (g->speed) {
|
||||
case USB_SPEED_SUPER_PLUS:
|
||||
if (gadget_is_superspeed_plus(g)) {
|
||||
speed_desc = f->ssp_descriptors;
|
||||
want_comp_desc = 1;
|
||||
break;
|
||||
}
|
||||
/* else: Fall trough */
|
||||
case USB_SPEED_SUPER:
|
||||
if (gadget_is_superspeed(g)) {
|
||||
speed_desc = f->ss_descriptors;
|
||||
@ -161,7 +198,7 @@ ep_found:
|
||||
(comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP))
|
||||
return -EIO;
|
||||
_ep->comp_desc = comp_desc;
|
||||
if (g->speed == USB_SPEED_SUPER) {
|
||||
if (g->speed >= USB_SPEED_SUPER) {
|
||||
switch (usb_endpoint_type(_ep->desc)) {
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
/* mult: bits 1:0 of bmAttributes */
|
||||
@ -237,6 +274,8 @@ int usb_add_function(struct usb_configuration *config,
|
||||
config->highspeed = true;
|
||||
if (!config->superspeed && function->ss_descriptors)
|
||||
config->superspeed = true;
|
||||
if (!config->superspeed_plus && function->ssp_descriptors)
|
||||
config->superspeed_plus = true;
|
||||
|
||||
done:
|
||||
if (value)
|
||||
@ -417,17 +456,7 @@ static int config_buf(struct usb_configuration *config,
|
||||
list_for_each_entry(f, &config->functions, list) {
|
||||
struct usb_descriptor_header **descriptors;
|
||||
|
||||
switch (speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
descriptors = f->ss_descriptors;
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
descriptors = f->hs_descriptors;
|
||||
break;
|
||||
default:
|
||||
descriptors = f->fs_descriptors;
|
||||
}
|
||||
|
||||
descriptors = function_descriptors(f, speed);
|
||||
if (!descriptors)
|
||||
continue;
|
||||
status = usb_descriptor_fillbuf(next, len,
|
||||
@ -451,7 +480,7 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
|
||||
u8 type = w_value >> 8;
|
||||
enum usb_device_speed speed = USB_SPEED_UNKNOWN;
|
||||
|
||||
if (gadget->speed == USB_SPEED_SUPER)
|
||||
if (gadget->speed >= USB_SPEED_SUPER)
|
||||
speed = gadget->speed;
|
||||
else if (gadget_is_dualspeed(gadget)) {
|
||||
int hs = 0;
|
||||
@ -482,6 +511,10 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
|
||||
check_config:
|
||||
/* ignore configs that won't work at this speed */
|
||||
switch (speed) {
|
||||
case USB_SPEED_SUPER_PLUS:
|
||||
if (!c->superspeed_plus)
|
||||
continue;
|
||||
break;
|
||||
case USB_SPEED_SUPER:
|
||||
if (!c->superspeed)
|
||||
continue;
|
||||
@ -509,18 +542,24 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
|
||||
unsigned count = 0;
|
||||
int hs = 0;
|
||||
int ss = 0;
|
||||
int ssp = 0;
|
||||
|
||||
if (gadget_is_dualspeed(gadget)) {
|
||||
if (gadget->speed == USB_SPEED_HIGH)
|
||||
hs = 1;
|
||||
if (gadget->speed == USB_SPEED_SUPER)
|
||||
ss = 1;
|
||||
if (gadget->speed == USB_SPEED_SUPER_PLUS)
|
||||
ssp = 1;
|
||||
if (type == USB_DT_DEVICE_QUALIFIER)
|
||||
hs = !hs;
|
||||
}
|
||||
list_for_each_entry(c, &cdev->configs, list) {
|
||||
/* ignore configs that won't work at this speed */
|
||||
if (ss) {
|
||||
if (ssp) {
|
||||
if (!c->superspeed_plus)
|
||||
continue;
|
||||
} else if (ss) {
|
||||
if (!c->superspeed)
|
||||
continue;
|
||||
} else if (hs) {
|
||||
@ -597,6 +636,48 @@ static int bos_desc(struct usb_composite_dev *cdev)
|
||||
ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
|
||||
ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
|
||||
|
||||
/* The SuperSpeedPlus USB Device Capability descriptor */
|
||||
if (gadget_is_superspeed_plus(cdev->gadget)) {
|
||||
struct usb_ssp_cap_descriptor *ssp_cap;
|
||||
|
||||
ssp_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
|
||||
bos->bNumDeviceCaps++;
|
||||
|
||||
/*
|
||||
* Report typical values.
|
||||
*/
|
||||
|
||||
le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SSP_CAP_SIZE(1));
|
||||
ssp_cap->bLength = USB_DT_USB_SSP_CAP_SIZE(1);
|
||||
ssp_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
|
||||
ssp_cap->bDevCapabilityType = USB_SSP_CAP_TYPE;
|
||||
|
||||
/* SSAC = 1 (2 attributes) */
|
||||
ssp_cap->bmAttributes = cpu_to_le32(1);
|
||||
|
||||
/* Min RX/TX Lane Count = 1 */
|
||||
ssp_cap->wFunctionalitySupport = (1 << 8) | (1 << 12);
|
||||
|
||||
/*
|
||||
* bmSublinkSpeedAttr[0]:
|
||||
* ST = Symmetric, RX
|
||||
* LSE = 3 (Gbps)
|
||||
* LP = 1 (SuperSpeedPlus)
|
||||
* LSM = 10 (10 Gbps)
|
||||
*/
|
||||
ssp_cap->bmSublinkSpeedAttr[0] =
|
||||
(3 << 4) | (1 << 14) | (0xa << 16);
|
||||
/*
|
||||
* bmSublinkSpeedAttr[1] =
|
||||
* ST = Symmetric, TX
|
||||
* LSE = 3 (Gbps)
|
||||
* LP = 1 (SuperSpeedPlus)
|
||||
* LSM = 10 (10 Gbps)
|
||||
*/
|
||||
ssp_cap->bmSublinkSpeedAttr[1] =
|
||||
(3 << 4) | (1 << 14) | (0xa << 16) | (1 << 7);
|
||||
}
|
||||
|
||||
return le16_to_cpu(bos->wTotalLength);
|
||||
}
|
||||
|
||||
@ -690,16 +771,7 @@ static int set_config(struct usb_composite_dev *cdev,
|
||||
* function's setup callback instead of the current
|
||||
* configuration's setup callback.
|
||||
*/
|
||||
switch (gadget->speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
descriptors = f->ss_descriptors;
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
descriptors = f->hs_descriptors;
|
||||
break;
|
||||
default:
|
||||
descriptors = f->fs_descriptors;
|
||||
}
|
||||
descriptors = function_descriptors(f, gadget->speed);
|
||||
|
||||
for (; *descriptors; ++descriptors) {
|
||||
struct usb_endpoint_descriptor *ep;
|
||||
@ -819,8 +891,9 @@ int usb_add_config(struct usb_composite_dev *cdev,
|
||||
} else {
|
||||
unsigned i;
|
||||
|
||||
DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
|
||||
DBG(cdev, "cfg %d/%p speeds:%s%s%s%s\n",
|
||||
config->bConfigurationValue, config,
|
||||
config->superspeed_plus ? " superplus" : "",
|
||||
config->superspeed ? " super" : "",
|
||||
config->highspeed ? " high" : "",
|
||||
config->fullspeed
|
||||
@ -1499,7 +1572,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
cdev->gadget->ep0->maxpacket;
|
||||
if (gadget_is_superspeed(gadget)) {
|
||||
if (gadget->speed >= USB_SPEED_SUPER) {
|
||||
cdev->desc.bcdUSB = cpu_to_le16(0x0300);
|
||||
cdev->desc.bcdUSB = cpu_to_le16(0x0310);
|
||||
cdev->desc.bMaxPacketSize0 = 9;
|
||||
} else {
|
||||
cdev->desc.bcdUSB = cpu_to_le16(0x0210);
|
||||
@ -1634,15 +1707,24 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
*((u8 *)req->buf) = value;
|
||||
value = min(w_length, (u16) 1);
|
||||
break;
|
||||
case USB_REQ_GET_STATUS:
|
||||
if (gadget_is_otg(gadget) && gadget->hnp_polling_support &&
|
||||
(w_index == OTG_STS_SELECTOR)) {
|
||||
if (ctrl->bRequestType != (USB_DIR_IN |
|
||||
USB_RECIP_DEVICE))
|
||||
goto unknown;
|
||||
*((u8 *)req->buf) = gadget->host_request_flag;
|
||||
value = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* USB 3.0 additions:
|
||||
* Function driver should handle get_status request. If such cb
|
||||
* wasn't supplied we respond with default value = 0
|
||||
* Note: function driver should supply such cb only for the first
|
||||
* interface of the function
|
||||
* Note: function driver should supply such cb only for the
|
||||
* first interface of the function
|
||||
*/
|
||||
case USB_REQ_GET_STATUS:
|
||||
if (!gadget_is_superspeed(gadget))
|
||||
goto unknown;
|
||||
if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
|
||||
|
@ -163,7 +163,8 @@ EXPORT_SYMBOL_GPL(usb_copy_descriptors);
|
||||
int usb_assign_descriptors(struct usb_function *f,
|
||||
struct usb_descriptor_header **fs,
|
||||
struct usb_descriptor_header **hs,
|
||||
struct usb_descriptor_header **ss)
|
||||
struct usb_descriptor_header **ss,
|
||||
struct usb_descriptor_header **ssp)
|
||||
{
|
||||
struct usb_gadget *g = f->config->cdev->gadget;
|
||||
|
||||
@ -182,6 +183,11 @@ int usb_assign_descriptors(struct usb_function *f,
|
||||
if (!f->ss_descriptors)
|
||||
goto err;
|
||||
}
|
||||
if (ssp && gadget_is_superspeed_plus(g)) {
|
||||
f->ssp_descriptors = usb_copy_descriptors(ssp);
|
||||
if (!f->ssp_descriptors)
|
||||
goto err;
|
||||
}
|
||||
return 0;
|
||||
err:
|
||||
usb_free_all_descriptors(f);
|
||||
@ -194,6 +200,7 @@ void usb_free_all_descriptors(struct usb_function *f)
|
||||
usb_free_descriptors(f->fs_descriptors);
|
||||
usb_free_descriptors(f->hs_descriptors);
|
||||
usb_free_descriptors(f->ss_descriptors);
|
||||
usb_free_descriptors(f->ssp_descriptors);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_free_all_descriptors);
|
||||
|
||||
|
@ -1229,6 +1229,7 @@ static void purge_configs_funcs(struct gadget_info *gi)
|
||||
}
|
||||
c->next_interface_id = 0;
|
||||
memset(c->interface, 0, sizeof(c->interface));
|
||||
c->superspeed_plus = 0;
|
||||
c->superspeed = 0;
|
||||
c->highspeed = 0;
|
||||
c->fullspeed = 0;
|
||||
|
@ -685,7 +685,7 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;
|
||||
|
||||
status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function,
|
||||
acm_ss_function);
|
||||
acm_ss_function, NULL);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
@ -777,10 +777,10 @@ static ssize_t f_acm_port_num_show(struct config_item *item, char *page)
|
||||
return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num);
|
||||
}
|
||||
|
||||
CONFIGFS_ATTR_RO(f_acm_port_, num);
|
||||
CONFIGFS_ATTR_RO(f_acm_, port_num);
|
||||
|
||||
static struct configfs_attribute *acm_attrs[] = {
|
||||
&f_acm_port_attr_num,
|
||||
&f_acm_attr_port_num,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -786,7 +786,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
fs_ecm_notify_desc.bEndpointAddress;
|
||||
|
||||
status = usb_assign_descriptors(f, ecm_fs_function, ecm_hs_function,
|
||||
ecm_ss_function);
|
||||
ecm_ss_function, NULL);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
|
@ -309,7 +309,7 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
eem_ss_out_desc.bEndpointAddress = eem_fs_out_desc.bEndpointAddress;
|
||||
|
||||
status = usb_assign_descriptors(f, eem_fs_function, eem_hs_function,
|
||||
eem_ss_function);
|
||||
eem_ss_function, NULL);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
|
@ -684,44 +684,38 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
|
||||
static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
||||
{
|
||||
struct ffs_epfile *epfile = file->private_data;
|
||||
struct usb_request *req;
|
||||
struct ffs_ep *ep;
|
||||
char *data = NULL;
|
||||
ssize_t ret, data_len = -EINVAL;
|
||||
int halt;
|
||||
|
||||
/* Are we still active? */
|
||||
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) {
|
||||
ret = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
|
||||
return -ENODEV;
|
||||
|
||||
/* Wait for endpoint to be enabled */
|
||||
ep = epfile->ep;
|
||||
if (!ep) {
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
ret = -EAGAIN;
|
||||
goto error;
|
||||
}
|
||||
if (file->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
|
||||
ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep));
|
||||
if (ret) {
|
||||
ret = -EINTR;
|
||||
goto error;
|
||||
}
|
||||
if (ret)
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
/* Do we halt? */
|
||||
halt = (!io_data->read == !epfile->in);
|
||||
if (halt && epfile->isoc) {
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
if (halt && epfile->isoc)
|
||||
return -EINVAL;
|
||||
|
||||
/* Allocate & copy */
|
||||
if (!halt) {
|
||||
/*
|
||||
* if we _do_ wait above, the epfile->ffs->gadget might be NULL
|
||||
* before the waiting completes, so do not assign to 'gadget' earlier
|
||||
* before the waiting completes, so do not assign to 'gadget'
|
||||
* earlier
|
||||
*/
|
||||
struct usb_gadget *gadget = epfile->ffs->gadget;
|
||||
size_t copied;
|
||||
@ -763,17 +757,12 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
||||
if (epfile->ep != ep) {
|
||||
/* In the meantime, endpoint got disabled or changed. */
|
||||
ret = -ESHUTDOWN;
|
||||
spin_unlock_irq(&epfile->ffs->eps_lock);
|
||||
} else if (halt) {
|
||||
/* Halt */
|
||||
if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep))
|
||||
usb_ep_set_halt(ep->ep);
|
||||
spin_unlock_irq(&epfile->ffs->eps_lock);
|
||||
ret = -EBADMSG;
|
||||
} else {
|
||||
/* Fire the request */
|
||||
struct usb_request *req;
|
||||
|
||||
} else if (unlikely(data_len == -EINVAL)) {
|
||||
/*
|
||||
* Sanity Check: even though data_len can't be used
|
||||
* uninitialized at the time I write this comment, some
|
||||
@ -785,17 +774,52 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
||||
* For such reason, we're adding this redundant sanity check
|
||||
* here.
|
||||
*/
|
||||
if (unlikely(data_len == -EINVAL)) {
|
||||
WARN(1, "%s: data_len == -EINVAL\n", __func__);
|
||||
ret = -EINVAL;
|
||||
} else if (!io_data->aio) {
|
||||
DECLARE_COMPLETION_ONSTACK(done);
|
||||
bool interrupted = false;
|
||||
|
||||
req = ep->req;
|
||||
req->buf = data;
|
||||
req->length = data_len;
|
||||
|
||||
req->context = &done;
|
||||
req->complete = ffs_epfile_io_complete;
|
||||
|
||||
ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
|
||||
if (unlikely(ret < 0))
|
||||
goto error_lock;
|
||||
|
||||
spin_unlock_irq(&epfile->ffs->eps_lock);
|
||||
|
||||
if (unlikely(wait_for_completion_interruptible(&done))) {
|
||||
/*
|
||||
* To avoid race condition with ffs_epfile_io_complete,
|
||||
* dequeue the request first then check
|
||||
* status. usb_ep_dequeue API should guarantee no race
|
||||
* condition with req->complete callback.
|
||||
*/
|
||||
usb_ep_dequeue(ep->ep, req);
|
||||
interrupted = ep->status < 0;
|
||||
}
|
||||
|
||||
if (io_data->aio) {
|
||||
req = usb_ep_alloc_request(ep->ep, GFP_KERNEL);
|
||||
if (unlikely(!req))
|
||||
goto error_lock;
|
||||
|
||||
/*
|
||||
* XXX We may end up silently droping data here. Since data_len
|
||||
* (i.e. req->length) may be bigger than len (after being
|
||||
* rounded up to maxpacketsize), we may end up with more data
|
||||
* then user space has space for.
|
||||
*/
|
||||
ret = interrupted ? -EINTR : ep->status;
|
||||
if (io_data->read && ret > 0) {
|
||||
ret = copy_to_iter(data, ret, &io_data->data);
|
||||
if (!ret)
|
||||
ret = -EFAULT;
|
||||
}
|
||||
goto error_mutex;
|
||||
} else if (!(req = usb_ep_alloc_request(ep->ep, GFP_KERNEL))) {
|
||||
ret = -ENOMEM;
|
||||
} else {
|
||||
req->buf = data;
|
||||
req->length = data_len;
|
||||
|
||||
@ -812,53 +836,18 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
||||
usb_ep_free_request(ep->ep, req);
|
||||
goto error_lock;
|
||||
}
|
||||
|
||||
ret = -EIOCBQUEUED;
|
||||
|
||||
spin_unlock_irq(&epfile->ffs->eps_lock);
|
||||
} else {
|
||||
DECLARE_COMPLETION_ONSTACK(done);
|
||||
|
||||
req = ep->req;
|
||||
req->buf = data;
|
||||
req->length = data_len;
|
||||
|
||||
req->context = &done;
|
||||
req->complete = ffs_epfile_io_complete;
|
||||
|
||||
ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
|
||||
|
||||
spin_unlock_irq(&epfile->ffs->eps_lock);
|
||||
|
||||
if (unlikely(ret < 0)) {
|
||||
/* nop */
|
||||
} else if (unlikely(
|
||||
wait_for_completion_interruptible(&done))) {
|
||||
ret = -EINTR;
|
||||
usb_ep_dequeue(ep->ep, req);
|
||||
} else {
|
||||
/*
|
||||
* XXX We may end up silently droping data
|
||||
* here. Since data_len (i.e. req->length) may
|
||||
* be bigger than len (after being rounded up
|
||||
* to maxpacketsize), we may end up with more
|
||||
* data then user space has space for.
|
||||
* Do not kfree the buffer in this function. It will be freed
|
||||
* by ffs_user_copy_worker.
|
||||
*/
|
||||
ret = ep->status;
|
||||
if (io_data->read && ret > 0) {
|
||||
ret = copy_to_iter(data, ret, &io_data->data);
|
||||
if (!ret)
|
||||
ret = -EFAULT;
|
||||
data = NULL;
|
||||
}
|
||||
}
|
||||
kfree(data);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&epfile->mutex);
|
||||
return ret;
|
||||
|
||||
error_lock:
|
||||
spin_unlock_irq(&epfile->ffs->eps_lock);
|
||||
error_mutex:
|
||||
mutex_unlock(&epfile->mutex);
|
||||
error:
|
||||
kfree(data);
|
||||
|
@ -646,7 +646,7 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
hidg_fs_out_ep_desc.bEndpointAddress;
|
||||
|
||||
status = usb_assign_descriptors(f, hidg_fs_descriptors,
|
||||
hidg_hs_descriptors, NULL);
|
||||
hidg_hs_descriptors, NULL, NULL);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
|
@ -211,7 +211,7 @@ autoconf_fail:
|
||||
ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
|
||||
|
||||
ret = usb_assign_descriptors(f, fs_loopback_descs, hs_loopback_descs,
|
||||
ss_loopback_descs);
|
||||
ss_loopback_descs, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -3093,7 +3093,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
|
||||
|
||||
ret = usb_assign_descriptors(f, fsg_fs_function, fsg_hs_function,
|
||||
fsg_ss_function);
|
||||
fsg_ss_function, fsg_ss_function);
|
||||
if (ret)
|
||||
goto autoconf_fail;
|
||||
|
||||
|
@ -56,7 +56,7 @@ static const char f_midi_longname[] = "MIDI Gadget";
|
||||
* USB <- IN endpoint <- rawmidi
|
||||
*/
|
||||
struct gmidi_in_port {
|
||||
struct f_midi *midi;
|
||||
struct snd_rawmidi_substream *substream;
|
||||
int active;
|
||||
uint8_t cable;
|
||||
uint8_t state;
|
||||
@ -78,9 +78,7 @@ struct f_midi {
|
||||
struct snd_rawmidi *rmidi;
|
||||
u8 ms_id;
|
||||
|
||||
struct snd_rawmidi_substream *in_substream[MAX_PORTS];
|
||||
struct snd_rawmidi_substream *out_substream[MAX_PORTS];
|
||||
struct gmidi_in_port *in_port[MAX_PORTS];
|
||||
|
||||
unsigned long out_triggered;
|
||||
struct tasklet_struct tasklet;
|
||||
@ -92,6 +90,8 @@ struct f_midi {
|
||||
/* This fifo is used as a buffer ring for pre-allocated IN usb_requests */
|
||||
DECLARE_KFIFO_PTR(in_req_fifo, struct usb_request *);
|
||||
unsigned int in_last_port;
|
||||
|
||||
struct gmidi_in_port in_ports_array[/* in_ports */];
|
||||
};
|
||||
|
||||
static inline struct f_midi *func_to_midi(struct usb_function *f)
|
||||
@ -518,58 +518,43 @@ static void f_midi_drop_out_substreams(struct f_midi *midi)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
struct gmidi_in_port *port = midi->in_port[i];
|
||||
struct snd_rawmidi_substream *substream = midi->in_substream[i];
|
||||
|
||||
if (!port)
|
||||
break;
|
||||
|
||||
if (!port->active || !substream)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < midi->in_ports; i++) {
|
||||
struct gmidi_in_port *port = midi->in_ports_array + i;
|
||||
struct snd_rawmidi_substream *substream = port->substream;
|
||||
if (port->active && substream)
|
||||
snd_rawmidi_drop_output(substream);
|
||||
}
|
||||
}
|
||||
|
||||
static void f_midi_transmit(struct f_midi *midi)
|
||||
static int f_midi_do_transmit(struct f_midi *midi, struct usb_ep *ep)
|
||||
{
|
||||
struct usb_ep *ep = midi->in_ep;
|
||||
bool active;
|
||||
|
||||
/* We only care about USB requests if IN endpoint is enabled */
|
||||
if (!ep || !ep->enabled)
|
||||
goto drop_out;
|
||||
|
||||
do {
|
||||
struct usb_request *req = NULL;
|
||||
unsigned int len, i;
|
||||
bool active = false;
|
||||
int err;
|
||||
|
||||
active = false;
|
||||
|
||||
/* We peek the request in order to reuse it if it fails
|
||||
* to enqueue on its endpoint */
|
||||
/*
|
||||
* We peek the request in order to reuse it if it fails to enqueue on
|
||||
* its endpoint
|
||||
*/
|
||||
len = kfifo_peek(&midi->in_req_fifo, &req);
|
||||
if (len != 1) {
|
||||
ERROR(midi, "%s: Couldn't get usb request\n", __func__);
|
||||
goto drop_out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If buffer overrun, then we ignore this transmission.
|
||||
* IMPORTANT: This will cause the user-space rawmidi device to block until a) usb
|
||||
* requests have been completed or b) snd_rawmidi_write() times out. */
|
||||
/*
|
||||
* If buffer overrun, then we ignore this transmission.
|
||||
* IMPORTANT: This will cause the user-space rawmidi device to block
|
||||
* until a) usb requests have been completed or b) snd_rawmidi_write()
|
||||
* times out.
|
||||
*/
|
||||
if (req->length > 0)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
for (i = midi->in_last_port; i < MAX_PORTS; i++) {
|
||||
struct gmidi_in_port *port = midi->in_port[i];
|
||||
struct snd_rawmidi_substream *substream = midi->in_substream[i];
|
||||
|
||||
if (!port) {
|
||||
/* Reset counter when we reach the last available port */
|
||||
midi->in_last_port = 0;
|
||||
break;
|
||||
}
|
||||
for (i = midi->in_last_port; i < midi->in_ports; ++i) {
|
||||
struct gmidi_in_port *port = midi->in_ports_array + i;
|
||||
struct snd_rawmidi_substream *substream = port->substream;
|
||||
|
||||
if (!port->active || !substream)
|
||||
continue;
|
||||
@ -585,18 +570,13 @@ static void f_midi_transmit(struct f_midi *midi)
|
||||
}
|
||||
|
||||
active = !!port->active;
|
||||
/* Check if last port is still active, which means that
|
||||
* there is still data on that substream but this current
|
||||
* request run out of space. */
|
||||
if (active) {
|
||||
midi->in_last_port = i;
|
||||
/* There is no need to re-iterate though midi ports. */
|
||||
if (active)
|
||||
break;
|
||||
}
|
||||
}
|
||||
midi->in_last_port = active ? i : 0;
|
||||
|
||||
if (req->length > 0) {
|
||||
int err;
|
||||
if (req->length <= 0)
|
||||
goto done;
|
||||
|
||||
err = usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
if (err < 0) {
|
||||
@ -608,8 +588,25 @@ static void f_midi_transmit(struct f_midi *midi)
|
||||
kfifo_skip(&midi->in_req_fifo);
|
||||
kfifo_put(&midi->in_req_fifo, req);
|
||||
}
|
||||
|
||||
done:
|
||||
return active;
|
||||
}
|
||||
} while (active);
|
||||
|
||||
static void f_midi_transmit(struct f_midi *midi)
|
||||
{
|
||||
struct usb_ep *ep = midi->in_ep;
|
||||
int ret;
|
||||
|
||||
/* We only care about USB requests if IN endpoint is enabled */
|
||||
if (!ep || !ep->enabled)
|
||||
goto drop_out;
|
||||
|
||||
do {
|
||||
ret = f_midi_do_transmit(midi, ep);
|
||||
if (ret < 0)
|
||||
goto drop_out;
|
||||
} while (ret);
|
||||
|
||||
return;
|
||||
|
||||
@ -626,13 +623,15 @@ static void f_midi_in_tasklet(unsigned long data)
|
||||
static int f_midi_in_open(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
struct f_midi *midi = substream->rmidi->private_data;
|
||||
struct gmidi_in_port *port;
|
||||
|
||||
if (!midi->in_port[substream->number])
|
||||
if (substream->number >= midi->in_ports)
|
||||
return -EINVAL;
|
||||
|
||||
VDBG(midi, "%s()\n", __func__);
|
||||
midi->in_substream[substream->number] = substream;
|
||||
midi->in_port[substream->number]->state = STATE_UNKNOWN;
|
||||
port = midi->in_ports_array + substream->number;
|
||||
port->substream = substream;
|
||||
port->state = STATE_UNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -648,11 +647,11 @@ static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up)
|
||||
{
|
||||
struct f_midi *midi = substream->rmidi->private_data;
|
||||
|
||||
if (!midi->in_port[substream->number])
|
||||
if (substream->number >= midi->in_ports)
|
||||
return;
|
||||
|
||||
VDBG(midi, "%s() %d\n", __func__, up);
|
||||
midi->in_port[substream->number]->active = up;
|
||||
midi->in_ports_array[substream->number].active = up;
|
||||
if (up)
|
||||
tasklet_hi_schedule(&midi->tasklet);
|
||||
}
|
||||
@ -1128,14 +1127,11 @@ static void f_midi_free(struct usb_function *f)
|
||||
{
|
||||
struct f_midi *midi;
|
||||
struct f_midi_opts *opts;
|
||||
int i;
|
||||
|
||||
midi = func_to_midi(f);
|
||||
opts = container_of(f->fi, struct f_midi_opts, func_inst);
|
||||
kfree(midi->id);
|
||||
mutex_lock(&opts->lock);
|
||||
for (i = opts->in_ports - 1; i >= 0; --i)
|
||||
kfree(midi->in_port[i]);
|
||||
kfifo_free(&midi->in_req_fifo);
|
||||
kfree(midi);
|
||||
--opts->refcnt;
|
||||
@ -1163,7 +1159,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
|
||||
{
|
||||
struct f_midi *midi;
|
||||
struct f_midi *midi = NULL;
|
||||
struct f_midi_opts *opts;
|
||||
int status, i;
|
||||
|
||||
@ -1172,37 +1168,26 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
|
||||
mutex_lock(&opts->lock);
|
||||
/* sanity check */
|
||||
if (opts->in_ports > MAX_PORTS || opts->out_ports > MAX_PORTS) {
|
||||
mutex_unlock(&opts->lock);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
/* allocate and initialize one new instance */
|
||||
midi = kzalloc(sizeof(*midi), GFP_KERNEL);
|
||||
if (!midi) {
|
||||
mutex_unlock(&opts->lock);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
for (i = 0; i < opts->in_ports; i++) {
|
||||
struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL);
|
||||
|
||||
if (!port) {
|
||||
status = -ENOMEM;
|
||||
mutex_unlock(&opts->lock);
|
||||
status = -EINVAL;
|
||||
goto setup_fail;
|
||||
}
|
||||
|
||||
port->midi = midi;
|
||||
port->active = 0;
|
||||
port->cable = i;
|
||||
midi->in_port[i] = port;
|
||||
/* allocate and initialize one new instance */
|
||||
midi = kzalloc(
|
||||
sizeof(*midi) + opts->in_ports * sizeof(*midi->in_ports_array),
|
||||
GFP_KERNEL);
|
||||
if (!midi) {
|
||||
status = -ENOMEM;
|
||||
goto setup_fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < opts->in_ports; i++)
|
||||
midi->in_ports_array[i].cable = i;
|
||||
|
||||
/* set up ALSA midi devices */
|
||||
midi->id = kstrdup(opts->id, GFP_KERNEL);
|
||||
if (opts->id && !midi->id) {
|
||||
status = -ENOMEM;
|
||||
mutex_unlock(&opts->lock);
|
||||
goto setup_fail;
|
||||
}
|
||||
midi->in_ports = opts->in_ports;
|
||||
@ -1229,8 +1214,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
|
||||
return &midi->func;
|
||||
|
||||
setup_fail:
|
||||
for (--i; i >= 0; i--)
|
||||
kfree(midi->in_port[i]);
|
||||
mutex_unlock(&opts->lock);
|
||||
kfree(midi);
|
||||
return ERR_PTR(status);
|
||||
}
|
||||
|
@ -1432,7 +1432,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
fs_ncm_notify_desc.bEndpointAddress;
|
||||
|
||||
status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function,
|
||||
NULL);
|
||||
NULL, NULL);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
|
@ -364,7 +364,8 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
obex_hs_ep_out_desc.bEndpointAddress =
|
||||
obex_fs_ep_out_desc.bEndpointAddress;
|
||||
|
||||
status = usb_assign_descriptors(f, fs_function, hs_function, NULL);
|
||||
status = usb_assign_descriptors(f, fs_function, hs_function, NULL,
|
||||
NULL);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
|
@ -541,7 +541,7 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
/* Do not try to bind Phonet twice... */
|
||||
status = usb_assign_descriptors(f, fs_pn_function, hs_pn_function,
|
||||
NULL);
|
||||
NULL, NULL);
|
||||
if (status)
|
||||
goto err;
|
||||
|
||||
|
@ -1051,7 +1051,7 @@ autoconf_fail:
|
||||
ss_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
|
||||
|
||||
ret = usb_assign_descriptors(f, fs_printer_function,
|
||||
hs_printer_function, ss_printer_function);
|
||||
hs_printer_function, ss_printer_function, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -783,7 +783,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
ss_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress;
|
||||
|
||||
status = usb_assign_descriptors(f, eth_fs_function, eth_hs_function,
|
||||
eth_ss_function);
|
||||
eth_ss_function, NULL);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
|
@ -236,7 +236,7 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
|
||||
|
||||
status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function,
|
||||
gser_ss_function);
|
||||
gser_ss_function, NULL);
|
||||
if (status)
|
||||
goto fail;
|
||||
dev_dbg(&cdev->gadget->dev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
|
||||
|
@ -437,7 +437,7 @@ no_iso:
|
||||
ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
|
||||
|
||||
ret = usb_assign_descriptors(f, fs_source_sink_descs,
|
||||
hs_source_sink_descs, ss_source_sink_descs);
|
||||
hs_source_sink_descs, ss_source_sink_descs, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -362,7 +362,7 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
fs_subset_out_desc.bEndpointAddress;
|
||||
|
||||
status = usb_assign_descriptors(f, fs_eth_function, hs_eth_function,
|
||||
ss_eth_function);
|
||||
ss_eth_function, NULL);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
|
@ -2098,7 +2098,7 @@ static int tcm_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
|
||||
|
||||
ret = usb_assign_descriptors(f, uasp_fs_function_desc,
|
||||
uasp_hs_function_desc, uasp_ss_function_desc);
|
||||
uasp_hs_function_desc, uasp_ss_function_desc, NULL);
|
||||
if (ret)
|
||||
goto ep_fail;
|
||||
|
||||
|
@ -721,7 +721,8 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
status = -ENOMEM;
|
||||
|
||||
/* copy descriptors, and track endpoint copies */
|
||||
status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL);
|
||||
status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL,
|
||||
NULL);
|
||||
if (status)
|
||||
goto fail;
|
||||
return 0;
|
||||
|
@ -1100,7 +1100,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
|
||||
hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
|
||||
hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
|
||||
|
||||
ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL);
|
||||
ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL,
|
||||
NULL);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
|
@ -1699,28 +1699,6 @@ static struct usb_gadget_driver gadgetfs_driver = {
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
static void gadgetfs_nop(struct usb_gadget *arg) { }
|
||||
|
||||
static int gadgetfs_probe(struct usb_gadget *gadget,
|
||||
struct usb_gadget_driver *driver)
|
||||
{
|
||||
CHIP = gadget->name;
|
||||
return -EISNAM;
|
||||
}
|
||||
|
||||
static struct usb_gadget_driver probe_driver = {
|
||||
.max_speed = USB_SPEED_HIGH,
|
||||
.bind = gadgetfs_probe,
|
||||
.unbind = gadgetfs_nop,
|
||||
.setup = (void *)gadgetfs_nop,
|
||||
.disconnect = gadgetfs_nop,
|
||||
.driver = {
|
||||
.name = "nop",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/* DEVICE INITIALIZATION
|
||||
*
|
||||
* fd = open ("/dev/gadget/$CHIP", O_RDWR)
|
||||
@ -1971,9 +1949,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
|
||||
if (the_device)
|
||||
return -ESRCH;
|
||||
|
||||
/* fake probe to determine $CHIP */
|
||||
CHIP = NULL;
|
||||
usb_gadget_probe_driver(&probe_driver);
|
||||
CHIP = usb_get_gadget_udc_name();
|
||||
if (!CHIP)
|
||||
return -ENODEV;
|
||||
|
||||
@ -2034,6 +2010,8 @@ gadgetfs_kill_sb (struct super_block *sb)
|
||||
put_dev (the_device);
|
||||
the_device = NULL;
|
||||
}
|
||||
kfree(CHIP);
|
||||
CHIP = NULL;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
@ -74,7 +74,6 @@ config USB_BCM63XX_UDC
|
||||
config USB_FSL_USB2
|
||||
tristate "Freescale Highspeed USB DR Peripheral Controller"
|
||||
depends on FSL_SOC || ARCH_MXC
|
||||
select USB_FSL_MPH_DR_OF if OF
|
||||
help
|
||||
Some of Freescale PowerPC and i.MX processors have a High Speed
|
||||
Dual-Role(DR) USB controller, which supports device mode.
|
||||
@ -177,7 +176,7 @@ config USB_RENESAS_USBHS_UDC
|
||||
|
||||
config USB_RENESAS_USB3
|
||||
tristate 'Renesas USB3.0 Peripheral controller'
|
||||
depends on ARCH_SHMOBILE || COMPILE_TEST
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
help
|
||||
Renesas USB3.0 Peripheral controller is a USB peripheral controller
|
||||
that supports super, high, and full speed USB 3.0 data transfers.
|
||||
|
@ -581,8 +581,13 @@ err0:
|
||||
|
||||
void bdc_udc_exit(struct bdc *bdc)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(bdc->dev, "%s()\n", __func__);
|
||||
spin_lock_irqsave(&bdc->lock, flags);
|
||||
bdc_ep_disable(bdc->bdc_ep_array[1]);
|
||||
spin_unlock_irqrestore(&bdc->lock, flags);
|
||||
|
||||
usb_del_gadget_udc(&bdc->gadget);
|
||||
bdc_free_ep(bdc);
|
||||
}
|
||||
|
@ -49,7 +49,6 @@
|
||||
#endif
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/platform.h>
|
||||
|
||||
/*
|
||||
* USB device configuration structure
|
||||
@ -147,9 +146,7 @@ struct lpc32xx_udc {
|
||||
u32 io_p_size;
|
||||
void __iomem *udp_baseaddr;
|
||||
int udp_irq[4];
|
||||
struct clk *usb_pll_clk;
|
||||
struct clk *usb_slv_clk;
|
||||
struct clk *usb_otg_clk;
|
||||
|
||||
/* DMA support */
|
||||
u32 *udca_v_base;
|
||||
@ -210,16 +207,6 @@ static inline struct lpc32xx_udc *to_udc(struct usb_gadget *g)
|
||||
|
||||
#define UDCA_BUFF_SIZE (128)
|
||||
|
||||
/* TODO: When the clock framework is introduced in LPC32xx, IO_ADDRESS will
|
||||
* be replaced with an inremap()ed pointer
|
||||
* */
|
||||
#define USB_CTRL IO_ADDRESS(LPC32XX_CLK_PM_BASE + 0x64)
|
||||
|
||||
/* USB_CTRL bit defines */
|
||||
#define USB_SLAVE_HCLK_EN (1 << 24)
|
||||
#define USB_HOST_NEED_CLK_EN (1 << 21)
|
||||
#define USB_DEV_NEED_CLK_EN (1 << 22)
|
||||
|
||||
/**********************************************************************
|
||||
* USB device controller register offsets
|
||||
**********************************************************************/
|
||||
@ -639,9 +626,6 @@ static void isp1301_udc_configure(struct lpc32xx_udc *udc)
|
||||
i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
|
||||
ISP1301_I2C_INTERRUPT_RISING, INT_VBUS_VLD);
|
||||
|
||||
/* Enable usb_need_clk clock after transceiver is initialized */
|
||||
writel((readl(USB_CTRL) | USB_DEV_NEED_CLK_EN), USB_CTRL);
|
||||
|
||||
dev_info(udc->dev, "ISP1301 Vendor ID : 0x%04x\n",
|
||||
i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00));
|
||||
dev_info(udc->dev, "ISP1301 Product ID : 0x%04x\n",
|
||||
@ -980,31 +964,13 @@ static void udc_clk_set(struct lpc32xx_udc *udc, int enable)
|
||||
return;
|
||||
|
||||
udc->clocked = 1;
|
||||
|
||||
/* 48MHz PLL up */
|
||||
clk_enable(udc->usb_pll_clk);
|
||||
|
||||
/* Enable the USB device clock */
|
||||
writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN,
|
||||
USB_CTRL);
|
||||
|
||||
clk_enable(udc->usb_otg_clk);
|
||||
clk_prepare_enable(udc->usb_slv_clk);
|
||||
} else {
|
||||
if (!udc->clocked)
|
||||
return;
|
||||
|
||||
udc->clocked = 0;
|
||||
|
||||
/* Never disable the USB_HCLK during normal operation */
|
||||
|
||||
/* 48MHz PLL dpwn */
|
||||
clk_disable(udc->usb_pll_clk);
|
||||
|
||||
/* Disable the USB device clock */
|
||||
writel(readl(USB_CTRL) & ~USB_DEV_NEED_CLK_EN,
|
||||
USB_CTRL);
|
||||
|
||||
clk_disable(udc->usb_otg_clk);
|
||||
clk_disable_unprepare(udc->usb_slv_clk);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3125,58 +3091,21 @@ static int lpc32xx_udc_probe(struct platform_device *pdev)
|
||||
goto io_map_fail;
|
||||
}
|
||||
|
||||
/* Enable AHB slave USB clock, needed for further USB clock control */
|
||||
writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL);
|
||||
|
||||
/* Get required clocks */
|
||||
udc->usb_pll_clk = clk_get(&pdev->dev, "ck_pll5");
|
||||
if (IS_ERR(udc->usb_pll_clk)) {
|
||||
dev_err(udc->dev, "failed to acquire USB PLL\n");
|
||||
retval = PTR_ERR(udc->usb_pll_clk);
|
||||
goto pll_get_fail;
|
||||
}
|
||||
udc->usb_slv_clk = clk_get(&pdev->dev, "ck_usbd");
|
||||
/* Get USB device clock */
|
||||
udc->usb_slv_clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(udc->usb_slv_clk)) {
|
||||
dev_err(udc->dev, "failed to acquire USB device clock\n");
|
||||
retval = PTR_ERR(udc->usb_slv_clk);
|
||||
goto usb_clk_get_fail;
|
||||
}
|
||||
udc->usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg");
|
||||
if (IS_ERR(udc->usb_otg_clk)) {
|
||||
dev_err(udc->dev, "failed to acquire USB otg clock\n");
|
||||
retval = PTR_ERR(udc->usb_otg_clk);
|
||||
goto usb_otg_clk_get_fail;
|
||||
}
|
||||
|
||||
/* Setup PLL clock to 48MHz */
|
||||
retval = clk_enable(udc->usb_pll_clk);
|
||||
if (retval < 0) {
|
||||
dev_err(udc->dev, "failed to start USB PLL\n");
|
||||
goto pll_enable_fail;
|
||||
}
|
||||
|
||||
retval = clk_set_rate(udc->usb_pll_clk, 48000);
|
||||
if (retval < 0) {
|
||||
dev_err(udc->dev, "failed to set USB clock rate\n");
|
||||
goto pll_set_fail;
|
||||
}
|
||||
|
||||
writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN, USB_CTRL);
|
||||
|
||||
/* Enable USB device clock */
|
||||
retval = clk_enable(udc->usb_slv_clk);
|
||||
retval = clk_prepare_enable(udc->usb_slv_clk);
|
||||
if (retval < 0) {
|
||||
dev_err(udc->dev, "failed to start USB device clock\n");
|
||||
goto usb_clk_enable_fail;
|
||||
}
|
||||
|
||||
/* Enable USB OTG clock */
|
||||
retval = clk_enable(udc->usb_otg_clk);
|
||||
if (retval < 0) {
|
||||
dev_err(udc->dev, "failed to start USB otg clock\n");
|
||||
goto usb_otg_clk_enable_fail;
|
||||
}
|
||||
|
||||
/* Setup deferred workqueue data */
|
||||
udc->poweron = udc->pullup = 0;
|
||||
INIT_WORK(&udc->pullup_job, pullup_work);
|
||||
@ -3287,19 +3216,10 @@ dma_alloc_fail:
|
||||
dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
|
||||
udc->udca_v_base, udc->udca_p_base);
|
||||
i2c_fail:
|
||||
clk_disable(udc->usb_otg_clk);
|
||||
usb_otg_clk_enable_fail:
|
||||
clk_disable(udc->usb_slv_clk);
|
||||
clk_disable_unprepare(udc->usb_slv_clk);
|
||||
usb_clk_enable_fail:
|
||||
pll_set_fail:
|
||||
clk_disable(udc->usb_pll_clk);
|
||||
pll_enable_fail:
|
||||
clk_put(udc->usb_otg_clk);
|
||||
usb_otg_clk_get_fail:
|
||||
clk_put(udc->usb_slv_clk);
|
||||
usb_clk_get_fail:
|
||||
clk_put(udc->usb_pll_clk);
|
||||
pll_get_fail:
|
||||
iounmap(udc->udp_baseaddr);
|
||||
io_map_fail:
|
||||
release_mem_region(udc->io_p_start, udc->io_p_size);
|
||||
@ -3336,12 +3256,9 @@ static int lpc32xx_udc_remove(struct platform_device *pdev)
|
||||
free_irq(udc->udp_irq[IRQ_USB_HP], udc);
|
||||
free_irq(udc->udp_irq[IRQ_USB_LP], udc);
|
||||
|
||||
clk_disable(udc->usb_otg_clk);
|
||||
clk_put(udc->usb_otg_clk);
|
||||
clk_disable(udc->usb_slv_clk);
|
||||
clk_disable_unprepare(udc->usb_slv_clk);
|
||||
clk_put(udc->usb_slv_clk);
|
||||
clk_disable(udc->usb_pll_clk);
|
||||
clk_put(udc->usb_pll_clk);
|
||||
|
||||
iounmap(udc->udp_baseaddr);
|
||||
release_mem_region(udc->io_p_start, udc->io_p_size);
|
||||
kfree(udc);
|
||||
@ -3367,7 +3284,7 @@ static int lpc32xx_udc_suspend(struct platform_device *pdev, pm_message_t mesg)
|
||||
udc->clocked = 1;
|
||||
|
||||
/* Kill global USB clock */
|
||||
clk_disable(udc->usb_slv_clk);
|
||||
clk_disable_unprepare(udc->usb_slv_clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -3379,7 +3296,7 @@ static int lpc32xx_udc_resume(struct platform_device *pdev)
|
||||
|
||||
if (udc->clocked) {
|
||||
/* Enable global USB clock */
|
||||
clk_enable(udc->usb_slv_clk);
|
||||
clk_prepare_enable(udc->usb_slv_clk);
|
||||
|
||||
/* Enable clocking */
|
||||
udc_clk_set(udc, 1);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -56,9 +56,9 @@ struct pxa25x_ep {
|
||||
* UDDR = UDC Endpoint Data Register (the fifo)
|
||||
* DRCM = DMA Request Channel Map
|
||||
*/
|
||||
volatile u32 *reg_udccs;
|
||||
volatile u32 *reg_ubcr;
|
||||
volatile u32 *reg_uddr;
|
||||
u32 regoff_udccs;
|
||||
u32 regoff_ubcr;
|
||||
u32 regoff_uddr;
|
||||
};
|
||||
|
||||
struct pxa25x_request {
|
||||
@ -125,6 +125,7 @@ struct pxa25x_udc {
|
||||
#ifdef CONFIG_USB_GADGET_DEBUG_FS
|
||||
struct dentry *debugfs_udc;
|
||||
#endif
|
||||
void __iomem *regs;
|
||||
};
|
||||
#define to_pxa25x(g) (container_of((g), struct pxa25x_udc, gadget))
|
||||
|
||||
@ -197,6 +198,8 @@ dump_udccs0(const char *label)
|
||||
(udccs0 & UDCCS0_OPR) ? " opr" : "");
|
||||
}
|
||||
|
||||
static inline u32 udc_ep_get_UDCCS(struct pxa25x_ep *);
|
||||
|
||||
static void __maybe_unused
|
||||
dump_state(struct pxa25x_udc *dev)
|
||||
{
|
||||
@ -228,7 +231,7 @@ dump_state(struct pxa25x_udc *dev)
|
||||
for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) {
|
||||
if (dev->ep[i].ep.desc == NULL)
|
||||
continue;
|
||||
DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccs);
|
||||
DMSG ("udccs%d = %02x\n", i, udc_ep_get_UDCCS(&dev->ep[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -442,6 +442,36 @@ err1:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
|
||||
|
||||
/**
|
||||
* usb_get_gadget_udc_name - get the name of the first UDC controller
|
||||
* This functions returns the name of the first UDC controller in the system.
|
||||
* Please note that this interface is usefull only for legacy drivers which
|
||||
* assume that there is only one UDC controller in the system and they need to
|
||||
* get its name before initialization. There is no guarantee that the UDC
|
||||
* of the returned name will be still available, when gadget driver registers
|
||||
* itself.
|
||||
*
|
||||
* Returns pointer to string with UDC controller name on success, NULL
|
||||
* otherwise. Caller should kfree() returned string.
|
||||
*/
|
||||
char *usb_get_gadget_udc_name(void)
|
||||
{
|
||||
struct usb_udc *udc;
|
||||
char *name = NULL;
|
||||
|
||||
/* For now we take the first available UDC */
|
||||
mutex_lock(&udc_lock);
|
||||
list_for_each_entry(udc, &udc_list, list) {
|
||||
if (!udc->driver) {
|
||||
name = kstrdup(udc->gadget->name, GFP_KERNEL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&udc_lock);
|
||||
return name;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_get_gadget_udc_name);
|
||||
|
||||
/**
|
||||
* usb_add_gadget_udc - adds a new gadget to the udc class driver list
|
||||
* @parent: the parent device to this udc. Usually the controller
|
||||
|
@ -125,9 +125,6 @@ config USB_EHCI_TT_NEWSCHED
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config USB_FSL_MPH_DR_OF
|
||||
tristate
|
||||
|
||||
if USB_EHCI_HCD
|
||||
|
||||
config USB_EHCI_PCI
|
||||
@ -160,7 +157,6 @@ config USB_EHCI_FSL
|
||||
tristate "Support for Freescale PPC on-chip EHCI USB controller"
|
||||
depends on FSL_SOC
|
||||
select USB_EHCI_ROOT_HUB_TT
|
||||
select USB_FSL_MPH_DR_OF if OF
|
||||
---help---
|
||||
Variation of ARC USB block used in some Freescale chips.
|
||||
|
||||
|
@ -74,7 +74,8 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
|
||||
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
|
||||
obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
|
||||
obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
|
||||
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
|
||||
obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o
|
||||
obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o
|
||||
obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
|
||||
obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
|
||||
obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
|
||||
|
@ -1901,7 +1901,7 @@ static void musb_recover_from_babble(struct musb *musb)
|
||||
*/
|
||||
|
||||
static struct musb *allocate_instance(struct device *dev,
|
||||
struct musb_hdrc_config *config, void __iomem *mbase)
|
||||
const struct musb_hdrc_config *config, void __iomem *mbase)
|
||||
{
|
||||
struct musb *musb;
|
||||
struct musb_hw_ep *ep;
|
||||
|
@ -438,7 +438,7 @@ struct musb {
|
||||
*/
|
||||
unsigned double_buffer_not_ok:1;
|
||||
|
||||
struct musb_hdrc_config *config;
|
||||
const struct musb_hdrc_config *config;
|
||||
|
||||
int xceiv_old_state;
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
@ -117,8 +117,8 @@ static void configure_channel(struct dma_channel *channel,
|
||||
u8 bchannel = musb_channel->idx;
|
||||
u16 csr = 0;
|
||||
|
||||
dev_dbg(musb->controller, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n",
|
||||
channel, packet_sz, dma_addr, len, mode);
|
||||
dev_dbg(musb->controller, "%p, pkt_sz %d, addr %pad, len %d, mode %d\n",
|
||||
channel, packet_sz, &dma_addr, len, mode);
|
||||
|
||||
if (mode) {
|
||||
csr |= 1 << MUSB_HSDMA_MODE1_SHIFT;
|
||||
@ -152,10 +152,10 @@ static int dma_channel_program(struct dma_channel *channel,
|
||||
struct musb_dma_controller *controller = musb_channel->controller;
|
||||
struct musb *musb = controller->private_data;
|
||||
|
||||
dev_dbg(musb->controller, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",
|
||||
dev_dbg(musb->controller, "ep%d-%s pkt_sz %d, dma_addr %pad length %d, mode %d\n",
|
||||
musb_channel->epnum,
|
||||
musb_channel->transmit ? "Tx" : "Rx",
|
||||
packet_sz, dma_addr, len, mode);
|
||||
packet_sz, &dma_addr, len, mode);
|
||||
|
||||
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
|
||||
channel->status == MUSB_DMA_STATUS_BUSY);
|
||||
|
@ -752,6 +752,7 @@ static const struct of_device_id sunxi_musb_match[] = {
|
||||
{ .compatible = "allwinner,sun8i-a33-musb", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sunxi_musb_match);
|
||||
|
||||
static struct platform_driver sunxi_musb_driver = {
|
||||
.probe = sunxi_musb_probe,
|
||||
|
@ -310,9 +310,9 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
|
||||
|
||||
dma_params.frame_count = chdat->transfer_len / 32; /* Burst sz frame */
|
||||
|
||||
dev_dbg(musb->controller, "ep%i %s dma ch%i dma: %08x len: %u(%u) packet_sz: %i(%i)\n",
|
||||
dev_dbg(musb->controller, "ep%i %s dma ch%i dma: %pad len: %u(%u) packet_sz: %i(%i)\n",
|
||||
chdat->epnum, chdat->tx ? "tx" : "rx",
|
||||
ch, dma_addr, chdat->transfer_len, len,
|
||||
ch, &dma_addr, chdat->transfer_len, len,
|
||||
chdat->transfer_packet_sz, packet_sz);
|
||||
|
||||
/*
|
||||
|
@ -207,9 +207,6 @@ static int ux500_dma_channel_program(struct dma_channel *channel,
|
||||
BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
|
||||
channel->status == MUSB_DMA_STATUS_BUSY);
|
||||
|
||||
if (!ux500_dma_is_compatible(channel, packet_sz, (void *)dma_addr, len))
|
||||
return false;
|
||||
|
||||
channel->status = MUSB_DMA_STATUS_BUSY;
|
||||
channel->actual_len = 0;
|
||||
ret = ux500_configure_channel(channel, packet_sz, mode, dma_addr, len);
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <linux/usb/usb_phy_generic.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/usb/of.h>
|
||||
|
@ -118,6 +118,7 @@ static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
|
||||
status = USB_EVENT_VBUS;
|
||||
otg->state = OTG_STATE_B_PERIPHERAL;
|
||||
nop->phy.last_event = status;
|
||||
if (otg->gadget)
|
||||
usb_gadget_vbus_connect(otg->gadget);
|
||||
|
||||
/* drawing a "unit load" is *always* OK, except for OTG */
|
||||
@ -128,6 +129,7 @@ static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
|
||||
} else {
|
||||
nop_set_vbus_draw(nop, 0);
|
||||
|
||||
if (otg->gadget)
|
||||
usb_gadget_vbus_disconnect(otg->gadget);
|
||||
status = USB_EVENT_NONE;
|
||||
otg->state = OTG_STATE_B_IDLE;
|
||||
@ -184,6 +186,9 @@ static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
|
||||
}
|
||||
|
||||
otg->gadget = gadget;
|
||||
if (otg->state == OTG_STATE_B_PERIPHERAL)
|
||||
usb_gadget_vbus_connect(gadget);
|
||||
else
|
||||
otg->state = OTG_STATE_B_IDLE;
|
||||
return 0;
|
||||
}
|
||||
|
@ -258,7 +258,7 @@ static void power_down(struct isp1301 *isp)
|
||||
isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
|
||||
}
|
||||
|
||||
static void power_up(struct isp1301 *isp)
|
||||
static void __maybe_unused power_up(struct isp1301 *isp)
|
||||
{
|
||||
// isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
|
||||
isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND);
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs.o
|
||||
|
||||
renesas_usbhs-y := common.o mod.o pipe.o fifo.o rcar2.o
|
||||
renesas_usbhs-y := common.o mod.o pipe.o fifo.o rcar2.o rcar3.o
|
||||
|
||||
ifneq ($(CONFIG_USB_RENESAS_USBHS_HCD),)
|
||||
renesas_usbhs-y += mod_host.o
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/sysfs.h>
|
||||
#include "common.h"
|
||||
#include "rcar2.h"
|
||||
#include "rcar3.h"
|
||||
|
||||
/*
|
||||
* image of renesas_usbhs
|
||||
@ -477,18 +478,16 @@ static const struct of_device_id usbhs_of_match[] = {
|
||||
.data = (void *)USBHS_TYPE_RCAR_GEN2,
|
||||
},
|
||||
{
|
||||
/* Gen3 is compatible with Gen2 */
|
||||
.compatible = "renesas,usbhs-r8a7795",
|
||||
.data = (void *)USBHS_TYPE_RCAR_GEN2,
|
||||
.data = (void *)USBHS_TYPE_RCAR_GEN3,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,rcar-gen2-usbhs",
|
||||
.data = (void *)USBHS_TYPE_RCAR_GEN2,
|
||||
},
|
||||
{
|
||||
/* Gen3 is compatible with Gen2 */
|
||||
.compatible = "renesas,rcar-gen3-usbhs",
|
||||
.data = (void *)USBHS_TYPE_RCAR_GEN2,
|
||||
.data = (void *)USBHS_TYPE_RCAR_GEN3,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
@ -578,6 +577,13 @@ static int usbhs_probe(struct platform_device *pdev)
|
||||
priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
|
||||
}
|
||||
break;
|
||||
case USBHS_TYPE_RCAR_GEN3:
|
||||
priv->pfunc = usbhs_rcar3_ops;
|
||||
if (!priv->dparam.pipe_configs) {
|
||||
priv->dparam.pipe_configs = usbhsc_new_pipe;
|
||||
priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!info->platform_callback.get_id) {
|
||||
dev_err(&pdev->dev, "no platform callbacks");
|
||||
|
@ -561,7 +561,7 @@ static int usbhsg_pipe_disable(struct usbhsg_uep *uep)
|
||||
if (!pkt)
|
||||
break;
|
||||
|
||||
usbhsg_queue_pop(uep, usbhsg_pkt_to_ureq(pkt), -ECONNRESET);
|
||||
usbhsg_queue_pop(uep, usbhsg_pkt_to_ureq(pkt), -ESHUTDOWN);
|
||||
}
|
||||
|
||||
usbhs_pipe_disable(pipe);
|
||||
|
@ -241,7 +241,7 @@ static int usbhsp_pipe_barrier(struct usbhs_pipe *pipe)
|
||||
{
|
||||
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
|
||||
int timeout = 1024;
|
||||
u16 val;
|
||||
u16 mask = usbhs_mod_is_host(priv) ? (CSSTS | PID_MASK) : PID_MASK;
|
||||
|
||||
/*
|
||||
* make sure....
|
||||
@ -265,9 +265,7 @@ static int usbhsp_pipe_barrier(struct usbhs_pipe *pipe)
|
||||
usbhs_pipe_disable(pipe);
|
||||
|
||||
do {
|
||||
val = usbhsp_pipectrl_get(pipe);
|
||||
val &= CSSTS | PID_MASK;
|
||||
if (!val)
|
||||
if (!(usbhsp_pipectrl_get(pipe) & mask))
|
||||
return 0;
|
||||
|
||||
udelay(10);
|
||||
|
54
drivers/usb/renesas_usbhs/rcar3.c
Normal file
54
drivers/usb/renesas_usbhs/rcar3.c
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Renesas USB driver R-Car Gen. 3 initialization and power control
|
||||
*
|
||||
* Copyright (C) 2016 Renesas Electronics Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include "common.h"
|
||||
#include "rcar3.h"
|
||||
|
||||
#define LPSTS 0x102
|
||||
#define UGCTRL2 0x184 /* 32-bit register */
|
||||
|
||||
/* Low Power Status register (LPSTS) */
|
||||
#define LPSTS_SUSPM 0x4000
|
||||
|
||||
/* USB General control register 2 (UGCTRL2), bit[31:6] should be 0 */
|
||||
#define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */
|
||||
#define UGCTRL2_USB0SEL_OTG 0x00000030
|
||||
|
||||
void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data)
|
||||
{
|
||||
iowrite32(data, priv->base + reg);
|
||||
}
|
||||
|
||||
static int usbhs_rcar3_power_ctrl(struct platform_device *pdev,
|
||||
void __iomem *base, int enable)
|
||||
{
|
||||
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
|
||||
|
||||
usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 | UGCTRL2_USB0SEL_OTG);
|
||||
|
||||
if (enable)
|
||||
usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM);
|
||||
else
|
||||
usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usbhs_rcar3_get_id(struct platform_device *pdev)
|
||||
{
|
||||
return USBHS_GADGET;
|
||||
}
|
||||
|
||||
const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = {
|
||||
.power_ctrl = usbhs_rcar3_power_ctrl,
|
||||
.get_id = usbhs_rcar3_get_id,
|
||||
};
|
3
drivers/usb/renesas_usbhs/rcar3.h
Normal file
3
drivers/usb/renesas_usbhs/rcar3.h
Normal file
@ -0,0 +1,3 @@
|
||||
#include "common.h"
|
||||
|
||||
extern const struct renesas_usbhs_platform_callback usbhs_rcar3_ops;
|
@ -126,6 +126,10 @@ struct usb_os_desc_table {
|
||||
* string identifiers assigned during @bind(). If this
|
||||
* pointer is null after initiation, the function will not
|
||||
* be available at super speed.
|
||||
* @ssp_descriptors: Table of super speed plus descriptors, using
|
||||
* interface and string identifiers assigned during @bind(). If
|
||||
* this pointer is null after initiation, the function will not
|
||||
* be available at super speed plus.
|
||||
* @config: assigned when @usb_add_function() is called; this is the
|
||||
* configuration with which this function is associated.
|
||||
* @os_desc_table: Table of (interface id, os descriptors) pairs. The function
|
||||
@ -186,6 +190,7 @@ struct usb_function {
|
||||
struct usb_descriptor_header **fs_descriptors;
|
||||
struct usb_descriptor_header **hs_descriptors;
|
||||
struct usb_descriptor_header **ss_descriptors;
|
||||
struct usb_descriptor_header **ssp_descriptors;
|
||||
|
||||
struct usb_configuration *config;
|
||||
|
||||
@ -317,6 +322,7 @@ struct usb_configuration {
|
||||
unsigned superspeed:1;
|
||||
unsigned highspeed:1;
|
||||
unsigned fullspeed:1;
|
||||
unsigned superspeed_plus:1;
|
||||
struct usb_function *interface[MAX_CONFIG_INTERFACES];
|
||||
};
|
||||
|
||||
|
@ -595,6 +595,10 @@ struct usb_gadget_ops {
|
||||
* only supports HNP on a different root port.
|
||||
* @b_hnp_enable: OTG device feature flag, indicating that the A-Host
|
||||
* enabled HNP support.
|
||||
* @hnp_polling_support: OTG device feature flag, indicating if the OTG device
|
||||
* in peripheral mode can support HNP polling.
|
||||
* @host_request_flag: OTG device feature flag, indicating if A-Peripheral
|
||||
* or B-Peripheral wants to take host role.
|
||||
* @quirk_ep_out_aligned_size: epout requires buffer size to be aligned to
|
||||
* MaxPacketSize.
|
||||
* @is_selfpowered: if the gadget is self-powered.
|
||||
@ -642,6 +646,8 @@ struct usb_gadget {
|
||||
unsigned b_hnp_enable:1;
|
||||
unsigned a_hnp_support:1;
|
||||
unsigned a_alt_hnp_support:1;
|
||||
unsigned hnp_polling_support:1;
|
||||
unsigned host_request_flag:1;
|
||||
unsigned quirk_ep_out_aligned_size:1;
|
||||
unsigned quirk_altset_not_supp:1;
|
||||
unsigned quirk_stall_not_supp:1;
|
||||
@ -728,6 +734,16 @@ static inline int gadget_is_superspeed(struct usb_gadget *g)
|
||||
return g->max_speed >= USB_SPEED_SUPER;
|
||||
}
|
||||
|
||||
/**
|
||||
* gadget_is_superspeed_plus() - return true if the hardware handles
|
||||
* superspeed plus
|
||||
* @g: controller that might support superspeed plus
|
||||
*/
|
||||
static inline int gadget_is_superspeed_plus(struct usb_gadget *g)
|
||||
{
|
||||
return g->max_speed >= USB_SPEED_SUPER_PLUS;
|
||||
}
|
||||
|
||||
/**
|
||||
* gadget_is_otg - return true iff the hardware is OTG-ready
|
||||
* @g: controller that might have a Mini-AB connector
|
||||
@ -1126,6 +1142,7 @@ extern int usb_add_gadget_udc_release(struct device *parent,
|
||||
struct usb_gadget *gadget, void (*release)(struct device *dev));
|
||||
extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
|
||||
extern void usb_del_gadget_udc(struct usb_gadget *gadget);
|
||||
extern char *usb_get_gadget_udc_name(void);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -1194,7 +1211,8 @@ struct usb_function;
|
||||
int usb_assign_descriptors(struct usb_function *f,
|
||||
struct usb_descriptor_header **fs,
|
||||
struct usb_descriptor_header **hs,
|
||||
struct usb_descriptor_header **ss);
|
||||
struct usb_descriptor_header **ss,
|
||||
struct usb_descriptor_header **ssp);
|
||||
void usb_free_all_descriptors(struct usb_function *f);
|
||||
|
||||
struct usb_descriptor_header *usb_otg_descriptor_alloc(
|
||||
|
@ -124,7 +124,7 @@ struct musb_hdrc_platform_data {
|
||||
int (*set_power)(int state);
|
||||
|
||||
/* MUSB configuration-specific details */
|
||||
struct musb_hdrc_config *config;
|
||||
const struct musb_hdrc_config *config;
|
||||
|
||||
/* Architecture specific board data */
|
||||
void *board_data;
|
||||
|
@ -40,6 +40,18 @@
|
||||
#define PROTO_HOST (1)
|
||||
#define PROTO_GADGET (2)
|
||||
|
||||
#define OTG_STS_SELECTOR 0xF000 /* OTG status selector, according to
|
||||
* OTG and EH 2.0 Chapter 6.2.3
|
||||
* Table:6-4
|
||||
*/
|
||||
|
||||
#define HOST_REQUEST_FLAG 1 /* Host request flag, according to
|
||||
* OTG and EH 2.0 Charpter 6.2.3
|
||||
* Table:6-5
|
||||
*/
|
||||
|
||||
#define T_HOST_REQ_POLL (1500) /* 1500ms, HNP polling interval */
|
||||
|
||||
enum otg_fsm_timer {
|
||||
/* Standard OTG timers */
|
||||
A_WAIT_VRISE,
|
||||
@ -48,6 +60,7 @@ enum otg_fsm_timer {
|
||||
A_AIDL_BDIS,
|
||||
B_ASE0_BRST,
|
||||
A_BIDL_ADIS,
|
||||
B_AIDL_BDIS,
|
||||
|
||||
/* Auxiliary timers */
|
||||
B_SE0_SRP,
|
||||
@ -119,6 +132,8 @@ struct otg_fsm {
|
||||
/* Current usb protocol used: 0:undefine; 1:host; 2:client */
|
||||
int protocol;
|
||||
struct mutex lock;
|
||||
u8 *host_req_flag;
|
||||
struct delayed_work hnp_polling_work;
|
||||
};
|
||||
|
||||
struct otg_fsm_ops {
|
||||
|
@ -184,6 +184,7 @@ struct renesas_usbhs_driver_param {
|
||||
};
|
||||
|
||||
#define USBHS_TYPE_RCAR_GEN2 1
|
||||
#define USBHS_TYPE_RCAR_GEN3 2
|
||||
|
||||
/*
|
||||
* option:
|
||||
|
@ -708,6 +708,7 @@ struct usb_otg20_descriptor {
|
||||
#define USB_OTG_HNP (1 << 1) /* swap host/device roles */
|
||||
#define USB_OTG_ADP (1 << 2) /* support ADP */
|
||||
|
||||
#define OTG_STS_SELECTOR 0xF000 /* OTG status selector */
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* USB_DT_DEBUG: for special highspeed devices, replacing serial console */
|
||||
@ -923,6 +924,12 @@ struct usb_ptm_cap_descriptor {
|
||||
__u8 bDevCapabilityType;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* The size of the descriptor for the Sublink Speed Attribute Count
|
||||
* (SSAC) specified in bmAttributes[4:0].
|
||||
*/
|
||||
#define USB_DT_USB_SSP_CAP_SIZE(ssac) (16 + ssac * 4)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with
|
||||
|
Loading…
Reference in New Issue
Block a user