提交 48d10bda 编写于 作者: L Linus Torvalds

Merge tag 'usb-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB updates from Greg KH:
 "Here is the big USB patchset for 4.6-rc1.

  The normal mess is here, gadget and xhci fixes and updates, and lots
  of other driver updates and cleanups as well.  Full details are in the
  shortlog.

  All have been in linux-next for a while with no reported issues"

* tag 'usb-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (266 commits)
  USB: core: let USB device know device node
  usb: devio: Add ioctl to disallow detaching kernel USB drivers.
  usb: gadget: f_acm: Fix configfs attr name
  usb: udc: lpc32xx: remove USB PLL and USB OTG clock management
  usb: udc: lpc32xx: remove direct access to clock controller registers
  usb: udc: lpc32xx: switch to clock prepare/unprepare model
  usb: renesas_usbhs: gadget: fix giveback status code in usbhsg_pipe_disable()
  usb: gadget: renesas_usb3: Use ARCH_RENESAS
  usb: dwc2: Fix issues in dwc2_complete_non_isoc_xfer_ddma()
  usb: dwc2: Add support for Lantiq ARX and XRX SoCs
  usb: phy: generic: Handle late registration of gadget
  usb: gadget: bdc_udc: fix race condition in bdc_udc_exit()
  usb: musb: core: added missing const qualifier to musb_hdrc_platform_data::config
  usb: dwc2: Move host-specific core functions into hcd.c
  usb: dwc2: Move register save and restore functions
  usb: dwc2: Use kmem_cache_free()
  usb: dwc2: host: If using uframe scheduler, end splits better
  usb: dwc2: host: Totally redo the microframe scheduler
  usb: dwc2: host: Properly set even/odd frame
  usb: dwc2: host: Add dwc2_hcd_get_future_frame_number() call
  ...
......@@ -732,6 +732,18 @@ usbdev_ioctl (int fd, int ifno, unsigned request, void *param)
or SET_INTERFACE.
</para></warning></listitem></varlistentry>
<varlistentry><term>USBDEVFS_DROP_PRIVILEGES</term>
<listitem><para>This is used to relinquish the ability
to do certain operations which are considered to be
privileged on a usbfs file descriptor.
This includes claiming arbitrary interfaces, resetting
a device on which there are currently claimed interfaces
from other users, and issuing USBDEVFS_IOCTL calls.
The ioctl parameter is a 32 bit mask of interfaces
the user is allowed to claim on this file descriptor.
You may issue this ioctl more than one time to narrow
said mask.
</para></listitem></varlistentry>
</variablelist>
</sect2>
......
......@@ -7,33 +7,26 @@ Required properties:
- compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795
SoC.
- reg: offset and length of the partial USB 2.0 Host register block.
- reg-names: must be "usb2_host".
- clocks: clock phandle and specifier pair(s).
- #phy-cells: see phy-bindings.txt in the same directory, must be <0>.
Optional properties:
To use a USB channel where USB 2.0 Host and HSUSB (USB 2.0 Peripheral) are
combined, the device tree node should set HSUSB properties to reg and reg-names
properties. This is because HSUSB has registers to select USB 2.0 host or
peripheral at that channel:
- reg: offset and length of the partial HSUSB register block.
- reg-names: must be "hsusb".
combined, the device tree node should set interrupt properties to use the
channel as USB OTG:
- interrupts: interrupt specifier for the PHY.
Example (R-Car H3):
usb-phy@ee080200 {
compatible = "renesas,usb2-phy-r8a7795";
reg = <0 0xee080200 0 0x700>, <0 0xe6590100 0 0x100>;
reg-names = "usb2_host", "hsusb";
reg = <0 0xee080200 0 0x700>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7795_CLK_EHCI0>,
<&mstp7_clks R8A7795_CLK_HSUSB>;
clocks = <&mstp7_clks R8A7795_CLK_EHCI0>;
};
usb-phy@ee0a0200 {
compatible = "renesas,usb2-phy-r8a7795";
reg = <0 0xee0a0200 0 0x700>;
reg-names = "usb2_host";
clocks = <&mstp7_clks R8A7795_CLK_EHCI0>;
};
Rockchip specific extensions to the Analogix Display Port PHY
------------------------------------
Required properties:
- compatible : should be one of the following supported values:
- "rockchip.rk3288-dp-phy"
- clocks: from common clock binding: handle to dp clock.
of memory mapped region.
- clock-names: from common clock binding:
Required elements: "24m"
- rockchip,grf: phandle to the syscon managing the "general register files"
- #phy-cells : from the generic PHY bindings, must be 0;
Example:
edp_phy: edp-phy {
compatible = "rockchip,rk3288-dp-phy";
rockchip,grf = <&grf>;
clocks = <&cru SCLK_EDP_24M>;
clock-names = "24m";
#phy-cells = <0>;
};
Rockchip EMMC PHY
-----------------------
Required properties:
- compatible: rockchip,rk3399-emmc-phy
- rockchip,grf : phandle to the syscon managing the "general
register files"
- #phy-cells: must be 0
- reg: PHY configure reg address offset in "general
register files"
Example:
emmcphy: phy {
compatible = "rockchip,rk3399-emmc-phy";
rockchip,grf = <&grf>;
reg = <0xf780>;
#phy-cells = <0>;
};
......@@ -2,7 +2,14 @@
Required properties:
- compatible: should be one of:
"fsl,imx23-usb"
"fsl,imx27-usb"
"fsl,imx28-usb"
"fsl,imx6q-usb"
"fsl,imx6sl-usb"
"fsl,imx6sx-usb"
"fsl,imx6ul-usb"
"fsl,imx7d-usb"
"lsi,zevio-usb"
"qcom,ci-hdrc"
"chipidea,usb2"
......@@ -53,6 +60,22 @@ Optional properties:
be specified.
- phy-clkgate-delay-us: the delay time (us) between putting the PHY into
low power mode and gating the PHY clock.
- non-zero-ttctrl-ttha: after setting this property, the value of register
ttctrl.ttha will be 0x7f; if not, the value will be 0x0, this is the default
value. It needs to be very carefully for setting this property, it is
recommended that consult with your IC engineer before setting this value.
On the most of chipidea platforms, the "usage_tt" flag at RTL is 0, so this
property only affects siTD.
If this property is not set, the max packet size is 1023 bytes, and if
the total of packet size for pervious transactions are more than 256 bytes,
it can't accept any transactions within this frame. The use case is single
transaction, but higher frame rate.
If this property is set, the max packet size is 188 bytes, it can handle
more transactions than above case, it can accept transactions until it
considers the left room size within frame is less than 188 bytes, software
needs to make sure it does not send more than 90%
maximum_periodic_data_per_frame. The use case is multiple transactions, but
less frame rate.
i.mx specific properties
- fsl,usbmisc: phandler of non-core register device, with one
......
......@@ -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
......
Generic USB Device Properties
Usually, we only use device tree for hard wired USB device.
The reference binding doc is from:
http://www.firmware.org/1275/bindings/usb/usb-1_0.ps
Required properties:
- compatible: usbVID,PID. The textual representation of VID, PID shall
be in lower case hexadecimal with leading zeroes suppressed. The
other compatible strings from the above standard binding could also
be used, but a device adhering to this binding may leave out all except
for usbVID,PID.
- reg: the port number which this device is connecting to, the range
is 1-31.
Example:
&usb1 {
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
hub: genesys@1 {
compatible = "usb5e3,608";
reg = <1>;
};
}
USB xHCI controllers
Required properties:
- compatible: should be one of "generic-xhci",
"marvell,armada-375-xhci", "marvell,armada-380-xhci",
"renesas,xhci-r8a7790", "renesas,xhci-r8a7791", "renesas,xhci-r8a7793",
"renesas,xhci-r8a7795" (deprecated: "xhci-platform").
- compatible: should be one or more of
- "generic-xhci" for generic XHCI device
- "marvell,armada-375-xhci" for Armada 375 SoCs
- "marvell,armada-380-xhci" for Armada 38x SoCs
- "renesas,xhci-r8a7790" for r8a7790 SoC
- "renesas,xhci-r8a7791" for r8a7791 SoC
- "renesas,xhci-r8a7793" for r8a7793 SoC
- "renesas,xhci-r8a7795" for r8a7795 SoC
- "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 compatible device
- "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device
- "xhci-platform" (deprecated)
When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first
followed by the generic version.
- reg: should contain address and length of the standard XHCI
register set for the device.
- interrupts: one XHCI interrupt should be described here.
......
......@@ -3533,6 +3533,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
on Mark read-only kernel memory as read-only (default).
off Leave read-only kernel memory writable for debugging.
rockchip.usb_uart
Enable the uart passthrough on the designated usb port
on Rockchip SoCs. When active, the signals of the
debug-uart get routed to the D+ and D- pins of the usb
port and the regular usb controller gets disabled.
root= [KNL] Root filesystem
See name_to_dev_t comment in init/do_mounts.c.
......
......@@ -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,
......
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
#include <linux/usbdevice_fs.h>
/* For building without an updated set of headers */
#ifndef USBDEVFS_DROP_PRIVILEGES
#define USBDEVFS_DROP_PRIVILEGES _IOW('U', 30, __u32)
#define USBDEVFS_CAP_DROP_PRIVILEGES 0x40
#endif
void drop_privileges(int fd, uint32_t mask)
{
int res;
res = ioctl(fd, USBDEVFS_DROP_PRIVILEGES, &mask);
if (res)
printf("ERROR: USBDEVFS_DROP_PRIVILEGES returned %d\n", res);
else
printf("OK: privileges dropped!\n");
}
void reset_device(int fd)
{
int res;
res = ioctl(fd, USBDEVFS_RESET);
if (!res)
printf("OK: USBDEVFS_RESET succeeded\n");
else
printf("ERROR: reset failed! (%d - %s)\n",
-res, strerror(-res));
}
void claim_some_intf(int fd)
{
int i, res;
for (i = 0; i < 4; i++) {
res = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &i);
if (!res)
printf("OK: claimed if %d\n", i);
else
printf("ERROR claiming if %d (%d - %s)\n",
i, -res, strerror(-res));
}
}
int main(int argc, char *argv[])
{
uint32_t mask, caps;
int c, fd;
fd = open(argv[1], O_RDWR);
if (fd < 0) {
printf("Failed to open file\n");
goto err_fd;
}
/*
* check if dropping privileges is supported,
* bail on systems where the capability is not present
*/
ioctl(fd, USBDEVFS_GET_CAPABILITIES, &caps);
if (!(caps & USBDEVFS_CAP_DROP_PRIVILEGES)) {
printf("DROP_PRIVILEGES not supported\n");
goto err;
}
/*
* Drop privileges but keep the ability to claim all
* free interfaces (i.e., those not used by kernel drivers)
*/
drop_privileges(fd, -1U);
printf("Available options:\n"
"[0] Exit now\n"
"[1] Reset device. Should fail if device is in use\n"
"[2] Claim 4 interfaces. Should succeed where not in use\n"
"[3] Narrow interface permission mask\n"
"Which option shall I run?: ");
while (scanf("%d", &c) == 1) {
switch (c) {
case 0:
goto exit;
case 1:
reset_device(fd);
break;
case 2:
claim_some_intf(fd);
break;
case 3:
printf("Insert new mask: ");
scanf("%x", &mask);
drop_privileges(fd, mask);
break;
default:
printf("I don't recognize that\n");
}
printf("Which test shall I run next?: ");
}
exit:
close(fd);
return 0;
err:
close(fd);
err_fd:
return 1;
}
......@@ -11316,7 +11316,7 @@ F: include/linux/mtd/ubi.h
F: include/uapi/mtd/ubi-user.h
USB ACM DRIVER
M: Oliver Neukum <oliver@neukum.org>
M: Oliver Neukum <oneukum@suse.com>
L: linux-usb@vger.kernel.org
S: Maintained
F: Documentation/usb/acm.txt
......@@ -11440,6 +11440,7 @@ M: Valentina Manea <valentina.manea.m@gmail.com>
M: Shuah Khan <shuah.kh@samsung.com>
L: linux-usb@vger.kernel.org
S: Maintained
F: Documentation/usb/usbip_protocol.txt
F: drivers/usb/usbip/
F: tools/usb/usbip/
......
......@@ -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 */
......
#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
......@@ -32,7 +32,7 @@ config PHY_BERLIN_SATA
config ARMADA375_USBCLUSTER_PHY
def_bool y
depends on MACH_ARMADA_375 || COMPILE_TEST
depends on OF
depends on OF && HAS_IOMEM
select GENERIC_PHY
config PHY_DM816X_USB
......@@ -337,6 +337,20 @@ config PHY_ROCKCHIP_USB
help
Enable this to support the Rockchip USB 2.0 PHY.
config PHY_ROCKCHIP_EMMC
tristate "Rockchip EMMC PHY Driver"
depends on ARCH_ROCKCHIP && OF
select GENERIC_PHY
help
Enable this to support the Rockchip EMMC PHY.
config PHY_ROCKCHIP_DP
tristate "Rockchip Display Port PHY Driver"
depends on ARCH_ROCKCHIP && OF
select GENERIC_PHY
help
Enable this to support the Rockchip Display Port PHY.
config PHY_ST_SPEAR1310_MIPHY
tristate "ST SPEAR1310-MIPHY driver"
select GENERIC_PHY
......
......@@ -37,6 +37,8 @@ phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o
obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o
obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o
obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o
obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o
obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
......
......@@ -118,7 +118,7 @@ static const struct phy_ops ops = {
.owner = THIS_MODULE,
};
static int dm816x_usb_phy_runtime_suspend(struct device *dev)
static int __maybe_unused dm816x_usb_phy_runtime_suspend(struct device *dev)
{
struct dm816x_usb_phy *phy = dev_get_drvdata(dev);
unsigned int mask, val;
......@@ -136,7 +136,7 @@ static int dm816x_usb_phy_runtime_suspend(struct device *dev)
return 0;
}
static int dm816x_usb_phy_runtime_resume(struct device *dev)
static int __maybe_unused dm816x_usb_phy_runtime_resume(struct device *dev)
{
struct dm816x_usb_phy *phy = dev_get_drvdata(dev);
unsigned int mask, val;
......
......@@ -74,20 +74,6 @@
#define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */
#define USB2_ADPCTRL_DRVVBUS BIT(4)
/******* HSUSB registers (original offset is +0x100) *******/
#define HSUSB_LPSTS 0x02
#define HSUSB_UGCTRL2 0x84
/* Low Power Status register (LPSTS) */
#define HSUSB_LPSTS_SUSPM 0x4000
/* USB General control register 2 (UGCTRL2) */
#define HSUSB_UGCTRL2_MASK 0x00000031 /* bit[31:6] should be 0 */
#define HSUSB_UGCTRL2_USB0SEL 0x00000030
#define HSUSB_UGCTRL2_USB0SEL_HOST 0x00000010
#define HSUSB_UGCTRL2_USB0SEL_HS_USB 0x00000020
#define HSUSB_UGCTRL2_USB0SEL_OTG 0x00000030
struct rcar_gen3_data {
void __iomem *base;
struct clk *clk;
......@@ -95,8 +81,8 @@ struct rcar_gen3_data {
struct rcar_gen3_chan {
struct rcar_gen3_data usb2;
struct rcar_gen3_data hsusb;
struct phy *phy;
bool has_otg;
};
static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host)
......@@ -202,24 +188,15 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
{
struct rcar_gen3_chan *channel = phy_get_drvdata(p);
void __iomem *usb2_base = channel->usb2.base;
void __iomem *hsusb_base = channel->hsusb.base;
u32 val;
/* Initialize USB2 part */
writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE);
writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET);
writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
/* Initialize HSUSB part */
if (hsusb_base) {
val = readl(hsusb_base + HSUSB_UGCTRL2);
val = (val & ~HSUSB_UGCTRL2_USB0SEL) |
HSUSB_UGCTRL2_USB0SEL_OTG;
writel(val & HSUSB_UGCTRL2_MASK, hsusb_base + HSUSB_UGCTRL2);
/* Initialize otg part */
/* Initialize otg part */
if (channel->has_otg)
rcar_gen3_init_otg(channel);
}
return 0;
}
......@@ -237,7 +214,6 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
{
struct rcar_gen3_chan *channel = phy_get_drvdata(p);
void __iomem *usb2_base = channel->usb2.base;
void __iomem *hsusb_base = channel->hsusb.base;
u32 val;
val = readl(usb2_base + USB2_USBCTR);
......@@ -246,33 +222,6 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
val &= ~USB2_USBCTR_PLL_RST;
writel(val, usb2_base + USB2_USBCTR);
/*
* TODO: To reduce power consuming, this driver should set the SUSPM
* after the PHY detects ID pin as peripheral.
*/
if (hsusb_base) {
/* Power on HSUSB PHY */
val = readw(hsusb_base + HSUSB_LPSTS);
val |= HSUSB_LPSTS_SUSPM;
writew(val, hsusb_base + HSUSB_LPSTS);
}
return 0;
}
static int rcar_gen3_phy_usb2_power_off(struct phy *p)
{
struct rcar_gen3_chan *channel = phy_get_drvdata(p);
void __iomem *hsusb_base = channel->hsusb.base;
u32 val;
if (hsusb_base) {
/* Power off HSUSB PHY */
val = readw(hsusb_base + HSUSB_LPSTS);
val &= ~HSUSB_LPSTS_SUSPM;
writew(val, hsusb_base + HSUSB_LPSTS);
}
return 0;
}
......@@ -280,7 +229,6 @@ static struct phy_ops rcar_gen3_phy_usb2_ops = {
.init = rcar_gen3_phy_usb2_init,
.exit = rcar_gen3_phy_usb2_exit,
.power_on = rcar_gen3_phy_usb2_power_on,
.power_off = rcar_gen3_phy_usb2_power_off,
.owner = THIS_MODULE,
};
......@@ -313,6 +261,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
struct rcar_gen3_chan *channel;
struct phy_provider *provider;
struct resource *res;
int irq;
if (!dev->of_node) {
dev_err(dev, "This driver needs device tree\n");
......@@ -323,29 +272,19 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
if (!channel)
return -ENOMEM;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "usb2_host");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
channel->usb2.base = devm_ioremap_resource(dev, res);
if (IS_ERR(channel->usb2.base))
return PTR_ERR(channel->usb2.base);
/* "hsusb" memory resource is optional */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hsusb");
/* To avoid error message by devm_ioremap_resource() */
if (res) {
int irq;
channel->hsusb.base = devm_ioremap_resource(dev, res);
if (IS_ERR(channel->hsusb.base))
channel->hsusb.base = NULL;
/* call request_irq for OTG */
irq = platform_get_irq(pdev, 0);
if (irq >= 0)
irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
IRQF_SHARED, dev_name(dev),
channel);
/* call request_irq for OTG */
irq = platform_get_irq(pdev, 0);
if (irq >= 0) {
irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
IRQF_SHARED, dev_name(dev), channel);
if (irq < 0)
dev_err(dev, "No irq handler (%d)\n", irq);
channel->has_otg = true;
}
/* devm_phy_create() will call pm_runtime_enable(dev); */
......
/*
* Rockchip DP PHY driver
*
* Copyright (C) 2016 FuZhou Rockchip Co., Ltd.
* Author: Yakir Yang <ykk@@rock-chips.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*/
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#define GRF_SOC_CON12 0x0274
#define GRF_EDP_REF_CLK_SEL_INTER_HIWORD_MASK BIT(20)
#define GRF_EDP_REF_CLK_SEL_INTER BIT(4)
#define GRF_EDP_PHY_SIDDQ_HIWORD_MASK BIT(21)
#define GRF_EDP_PHY_SIDDQ_ON 0
#define GRF_EDP_PHY_SIDDQ_OFF BIT(5)
struct rockchip_dp_phy {
struct device *dev;
struct regmap *grf;
struct clk *phy_24m;
};
static int rockchip_set_phy_state(struct phy *phy, bool enable)
{
struct rockchip_dp_phy *dp = phy_get_drvdata(phy);
int ret;
if (enable) {
ret = regmap_write(dp->grf, GRF_SOC_CON12,
GRF_EDP_PHY_SIDDQ_HIWORD_MASK |
GRF_EDP_PHY_SIDDQ_ON);
if (ret < 0) {
dev_err(dp->dev, "Can't enable PHY power %d\n", ret);
return ret;
}
ret = clk_prepare_enable(dp->phy_24m);
} else {
clk_disable_unprepare(dp->phy_24m);
ret = regmap_write(dp->grf, GRF_SOC_CON12,
GRF_EDP_PHY_SIDDQ_HIWORD_MASK |
GRF_EDP_PHY_SIDDQ_OFF);
}
return ret;
}
static int rockchip_dp_phy_power_on(struct phy *phy)
{
return rockchip_set_phy_state(phy, true);
}
static int rockchip_dp_phy_power_off(struct phy *phy)
{
return rockchip_set_phy_state(phy, false);
}
static const struct phy_ops rockchip_dp_phy_ops = {
.power_on = rockchip_dp_phy_power_on,
.power_off = rockchip_dp_phy_power_off,
.owner = THIS_MODULE,
};
static int rockchip_dp_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct phy_provider *phy_provider;
struct rockchip_dp_phy *dp;
struct phy *phy;
int ret;
if (!np)
return -ENODEV;
dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
if (IS_ERR(dp))
return -ENOMEM;
dp->dev = dev;
dp->phy_24m = devm_clk_get(dev, "24m");
if (IS_ERR(dp->phy_24m)) {
dev_err(dev, "cannot get clock 24m\n");
return PTR_ERR(dp->phy_24m);
}
ret = clk_set_rate(dp->phy_24m, 24000000);
if (ret < 0) {
dev_err(dp->dev, "cannot set clock phy_24m %d\n", ret);
return ret;
}
dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
if (IS_ERR(dp->grf)) {
dev_err(dev, "rk3288-dp needs rockchip,grf property\n");
return PTR_ERR(dp->grf);
}
ret = regmap_write(dp->grf, GRF_SOC_CON12, GRF_EDP_REF_CLK_SEL_INTER |
GRF_EDP_REF_CLK_SEL_INTER_HIWORD_MASK);
if (ret != 0) {
dev_err(dp->dev, "Could not config GRF edp ref clk: %d\n", ret);
return ret;
}
phy = devm_phy_create(dev, np, &rockchip_dp_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create phy\n");
return PTR_ERR(phy);
}
phy_set_drvdata(phy, dp);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id rockchip_dp_phy_dt_ids[] = {
{ .compatible = "rockchip,rk3288-dp-phy" },
{}
};
MODULE_DEVICE_TABLE(of, rockchip_dp_phy_dt_ids);
static struct platform_driver rockchip_dp_phy_driver = {
.probe = rockchip_dp_phy_probe,
.driver = {
.name = "rockchip-dp-phy",
.of_match_table = rockchip_dp_phy_dt_ids,
},
};
module_platform_driver(rockchip_dp_phy_driver);
MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
MODULE_DESCRIPTION("Rockchip DP PHY driver");
MODULE_LICENSE("GPL v2");
/*
* Rockchip emmc PHY driver
*
* Copyright (C) 2016 Shawn Lin <shawn.lin@rock-chips.com>
* Copyright (C) 2016 ROCKCHIP, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/delay.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
/*
* The higher 16-bit of this register is used for write protection
* only if BIT(x + 16) set to 1 the BIT(x) can be written.
*/
#define HIWORD_UPDATE(val, mask, shift) \
((val) << (shift) | (mask) << ((shift) + 16))
/* Register definition */
#define GRF_EMMCPHY_CON0 0x0
#define GRF_EMMCPHY_CON1 0x4
#define GRF_EMMCPHY_CON2 0x8
#define GRF_EMMCPHY_CON3 0xc
#define GRF_EMMCPHY_CON4 0x10
#define GRF_EMMCPHY_CON5 0x14
#define GRF_EMMCPHY_CON6 0x18
#define GRF_EMMCPHY_STATUS 0x20
#define PHYCTRL_PDB_MASK 0x1
#define PHYCTRL_PDB_SHIFT 0x0
#define PHYCTRL_PDB_PWR_ON 0x1
#define PHYCTRL_PDB_PWR_OFF 0x0
#define PHYCTRL_ENDLL_MASK 0x1
#define PHYCTRL_ENDLL_SHIFT 0x1
#define PHYCTRL_ENDLL_ENABLE 0x1
#define PHYCTRL_ENDLL_DISABLE 0x0
#define PHYCTRL_CALDONE_MASK 0x1
#define PHYCTRL_CALDONE_SHIFT 0x6
#define PHYCTRL_CALDONE_DONE 0x1
#define PHYCTRL_CALDONE_GOING 0x0
#define PHYCTRL_DLLRDY_MASK 0x1
#define PHYCTRL_DLLRDY_SHIFT 0x5
#define PHYCTRL_DLLRDY_DONE 0x1
#define PHYCTRL_DLLRDY_GOING 0x0
struct rockchip_emmc_phy {
unsigned int reg_offset;
struct regmap *reg_base;
};
static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy,
bool on_off)
{
unsigned int caldone;
unsigned int dllrdy;
/*
* Keep phyctrl_pdb and phyctrl_endll low to allow
* initialization of CALIO state M/C DFFs
*/
regmap_write(rk_phy->reg_base,
rk_phy->reg_offset + GRF_EMMCPHY_CON6,
HIWORD_UPDATE(PHYCTRL_PDB_PWR_OFF,
PHYCTRL_PDB_MASK,
PHYCTRL_PDB_SHIFT));
regmap_write(rk_phy->reg_base,
rk_phy->reg_offset + GRF_EMMCPHY_CON6,
HIWORD_UPDATE(PHYCTRL_ENDLL_DISABLE,
PHYCTRL_ENDLL_MASK,
PHYCTRL_ENDLL_SHIFT));
/* Already finish power_off above */
if (on_off == PHYCTRL_PDB_PWR_OFF)
return 0;
/*
* According to the user manual, calpad calibration
* cycle takes more than 2us without the minimal recommended
* value, so we may need a little margin here
*/
udelay(3);
regmap_write(rk_phy->reg_base,
rk_phy->reg_offset + GRF_EMMCPHY_CON6,
HIWORD_UPDATE(PHYCTRL_PDB_PWR_ON,
PHYCTRL_PDB_MASK,
PHYCTRL_PDB_SHIFT));
/*
* According to the user manual, it asks driver to
* wait 5us for calpad busy trimming
*/
udelay(5);
regmap_read(rk_phy->reg_base,
rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
&caldone);
caldone = (caldone >> PHYCTRL_CALDONE_SHIFT) & PHYCTRL_CALDONE_MASK;
if (caldone != PHYCTRL_CALDONE_DONE) {
pr_err("rockchip_emmc_phy_power: caldone timeout.\n");
return -ETIMEDOUT;
}
regmap_write(rk_phy->reg_base,
rk_phy->reg_offset + GRF_EMMCPHY_CON6,
HIWORD_UPDATE(PHYCTRL_ENDLL_ENABLE,
PHYCTRL_ENDLL_MASK,
PHYCTRL_ENDLL_SHIFT));
/*
* After enable analog DLL circuits, we need extra 10.2us
* for dll to be ready for work.
*/
udelay(11);
regmap_read(rk_phy->reg_base,
rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
&dllrdy);
dllrdy = (dllrdy >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK;
if (dllrdy != PHYCTRL_DLLRDY_DONE) {
pr_err("rockchip_emmc_phy_power: dllrdy timeout.\n");
return -ETIMEDOUT;
}
return 0;
}
static int rockchip_emmc_phy_power_off(struct phy *phy)
{
struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
int ret = 0;
/* Power down emmc phy analog blocks */
ret = rockchip_emmc_phy_power(rk_phy, PHYCTRL_PDB_PWR_OFF);
if (ret)
return ret;
return 0;
}
static int rockchip_emmc_phy_power_on(struct phy *phy)
{
struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
int ret = 0;
/* Power up emmc phy analog blocks */
ret = rockchip_emmc_phy_power(rk_phy, PHYCTRL_PDB_PWR_ON);
if (ret)
return ret;
return 0;
}
static const struct phy_ops ops = {
.power_on = rockchip_emmc_phy_power_on,
.power_off = rockchip_emmc_phy_power_off,
.owner = THIS_MODULE,
};
static int rockchip_emmc_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rockchip_emmc_phy *rk_phy;
struct phy *generic_phy;
struct phy_provider *phy_provider;
struct regmap *grf;
unsigned int reg_offset;
grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
if (IS_ERR(grf)) {
dev_err(dev, "Missing rockchip,grf property\n");
return PTR_ERR(grf);
}
rk_phy = devm_kzalloc(dev, sizeof(*rk_phy), GFP_KERNEL);
if (!rk_phy)
return -ENOMEM;
if (of_property_read_u32(dev->of_node, "reg", &reg_offset)) {
dev_err(dev, "missing reg property in node %s\n",
dev->of_node->name);
return -EINVAL;
}
rk_phy->reg_offset = reg_offset;
rk_phy->reg_base = grf;
generic_phy = devm_phy_create(dev, dev->of_node, &ops);
if (IS_ERR(generic_phy)) {
dev_err(dev, "failed to create PHY\n");
return PTR_ERR(generic_phy);
}
phy_set_drvdata(generic_phy, rk_phy);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id rockchip_emmc_phy_dt_ids[] = {
{ .compatible = "rockchip,rk3399-emmc-phy" },
{}
};
MODULE_DEVICE_TABLE(of, rockchip_emmc_phy_dt_ids);
static struct platform_driver rockchip_emmc_driver = {
.probe = rockchip_emmc_phy_probe,
.driver = {
.name = "rockchip-emmc-phy",
.of_match_table = rockchip_emmc_phy_dt_ids,
},
};
module_platform_driver(rockchip_emmc_driver);
MODULE_AUTHOR("Shawn Lin <shawn.lin@rock-chips.com>");
MODULE_DESCRIPTION("Rockchip EMMC PHY driver");
MODULE_LICENSE("GPL v2");
......@@ -30,21 +30,23 @@
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
/*
* The higher 16-bit of this register is used for write protection
* only if BIT(13 + 16) set to 1 the BIT(13) can be written.
*/
#define SIDDQ_WRITE_ENA BIT(29)
#define SIDDQ_ON BIT(13)
#define SIDDQ_OFF (0 << 13)
static int enable_usb_uart;
#define HIWORD_UPDATE(val, mask) \
((val) | (mask) << 16)
#define UOC_CON0_SIDDQ BIT(13)
struct rockchip_usb_phys {
int reg;
const char *pll_name;
};
struct rockchip_usb_phy_base;
struct rockchip_usb_phy_pdata {
struct rockchip_usb_phys *phys;
int (*init_usb_uart)(struct regmap *grf);
int usb_uart_phy;
};
struct rockchip_usb_phy_base {
......@@ -61,13 +63,15 @@ struct rockchip_usb_phy {
struct clk *clk480m;
struct clk_hw clk480m_hw;
struct phy *phy;
bool uart_enabled;
};
static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy,
bool siddq)
{
return regmap_write(phy->base->reg_base, phy->reg_offset,
SIDDQ_WRITE_ENA | (siddq ? SIDDQ_ON : SIDDQ_OFF));
u32 val = HIWORD_UPDATE(siddq ? UOC_CON0_SIDDQ : 0, UOC_CON0_SIDDQ);
return regmap_write(phy->base->reg_base, phy->reg_offset, val);
}
static unsigned long rockchip_usb_phy480m_recalc_rate(struct clk_hw *hw,
......@@ -108,7 +112,7 @@ static int rockchip_usb_phy480m_is_enabled(struct clk_hw *hw)
if (ret < 0)
return ret;
return (val & SIDDQ_ON) ? 0 : 1;
return (val & UOC_CON0_SIDDQ) ? 0 : 1;
}
static const struct clk_ops rockchip_usb_phy480m_ops = {
......@@ -122,6 +126,9 @@ static int rockchip_usb_phy_power_off(struct phy *_phy)
{
struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
if (phy->uart_enabled)
return -EBUSY;
clk_disable_unprepare(phy->clk480m);
return 0;
......@@ -131,6 +138,9 @@ static int rockchip_usb_phy_power_on(struct phy *_phy)
{
struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
if (phy->uart_enabled)
return -EBUSY;
return clk_prepare_enable(phy->clk480m);
}
......@@ -144,8 +154,10 @@ static void rockchip_usb_phy_action(void *data)
{
struct rockchip_usb_phy *rk_phy = data;
of_clk_del_provider(rk_phy->np);
clk_unregister(rk_phy->clk480m);
if (!rk_phy->uart_enabled) {
of_clk_del_provider(rk_phy->np);
clk_unregister(rk_phy->clk480m);
}
if (rk_phy->clk)
clk_put(rk_phy->clk);
......@@ -194,30 +206,35 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
return -EINVAL;
}
if (rk_phy->clk) {
clk_name = __clk_get_name(rk_phy->clk);
init.flags = 0;
init.parent_names = &clk_name;
init.num_parents = 1;
if (enable_usb_uart && base->pdata->usb_uart_phy == i) {
dev_dbg(base->dev, "phy%d used as uart output\n", i);
rk_phy->uart_enabled = true;
} else {
init.flags = CLK_IS_ROOT;
init.parent_names = NULL;
init.num_parents = 0;
}
if (rk_phy->clk) {
clk_name = __clk_get_name(rk_phy->clk);
init.flags = 0;
init.parent_names = &clk_name;
init.num_parents = 1;
} else {
init.flags = CLK_IS_ROOT;
init.parent_names = NULL;
init.num_parents = 0;
}
init.ops = &rockchip_usb_phy480m_ops;
rk_phy->clk480m_hw.init = &init;
init.ops = &rockchip_usb_phy480m_ops;
rk_phy->clk480m_hw.init = &init;
rk_phy->clk480m = clk_register(base->dev, &rk_phy->clk480m_hw);
if (IS_ERR(rk_phy->clk480m)) {
err = PTR_ERR(rk_phy->clk480m);
goto err_clk;
}
rk_phy->clk480m = clk_register(base->dev, &rk_phy->clk480m_hw);
if (IS_ERR(rk_phy->clk480m)) {
err = PTR_ERR(rk_phy->clk480m);
goto err_clk;
}
err = of_clk_add_provider(child, of_clk_src_simple_get,
rk_phy->clk480m);
if (err < 0)
goto err_clk_prov;
err = of_clk_add_provider(child, of_clk_src_simple_get,
rk_phy->clk480m);
if (err < 0)
goto err_clk_prov;
}
err = devm_add_action(base->dev, rockchip_usb_phy_action, rk_phy);
if (err)
......@@ -230,13 +247,21 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
}
phy_set_drvdata(rk_phy->phy, rk_phy);
/* only power up usb phy when it use, so disable it when init*/
return rockchip_usb_phy_power(rk_phy, 1);
/*
* When acting as uart-pipe, just keep clock on otherwise
* only power up usb phy when it use, so disable it when init
*/
if (rk_phy->uart_enabled)
return clk_prepare_enable(rk_phy->clk);
else
return rockchip_usb_phy_power(rk_phy, 1);
err_devm_action:
of_clk_del_provider(child);
if (!rk_phy->uart_enabled)
of_clk_del_provider(child);
err_clk_prov:
clk_unregister(rk_phy->clk480m);
if (!rk_phy->uart_enabled)
clk_unregister(rk_phy->clk480m);
err_clk:
if (rk_phy->clk)
clk_put(rk_phy->clk);
......@@ -259,6 +284,86 @@ static const struct rockchip_usb_phy_pdata rk3188_pdata = {
},
};
#define RK3288_UOC0_CON0 0x320
#define RK3288_UOC0_CON0_COMMON_ON_N BIT(0)
#define RK3288_UOC0_CON0_DISABLE BIT(4)
#define RK3288_UOC0_CON2 0x328
#define RK3288_UOC0_CON2_SOFT_CON_SEL BIT(2)
#define RK3288_UOC0_CON3 0x32c
#define RK3288_UOC0_CON3_UTMI_SUSPENDN BIT(0)
#define RK3288_UOC0_CON3_UTMI_OPMODE_NODRIVING (1 << 1)
#define RK3288_UOC0_CON3_UTMI_OPMODE_MASK (3 << 1)
#define RK3288_UOC0_CON3_UTMI_XCVRSEELCT_FSTRANSC (1 << 3)
#define RK3288_UOC0_CON3_UTMI_XCVRSEELCT_MASK (3 << 3)
#define RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED BIT(5)
#define RK3288_UOC0_CON3_BYPASSDMEN BIT(6)
#define RK3288_UOC0_CON3_BYPASSSEL BIT(7)
/*
* Enable the bypass of uart2 data through the otg usb phy.
* Original description in the TRM.
* 1. Disable the OTG block by setting OTGDISABLE0 to 1’b1.
* 2. Disable the pull-up resistance on the D+ line by setting
* OPMODE0[1:0] to 2’b01.
* 3. To ensure that the XO, Bias, and PLL blocks are powered down in Suspend
* mode, set COMMONONN to 1’b1.
* 4. Place the USB PHY in Suspend mode by setting SUSPENDM0 to 1’b0.
* 5. Set BYPASSSEL0 to 1’b1.
* 6. To transmit data, controls BYPASSDMEN0, and BYPASSDMDATA0.
* To receive data, monitor FSVPLUS0.
*
* The actual code in the vendor kernel does some things differently.
*/
static int __init rk3288_init_usb_uart(struct regmap *grf)
{
u32 val;
int ret;
/*
* COMMON_ON and DISABLE settings are described in the TRM,
* but were not present in the original code.
* Also disable the analog phy components to save power.
*/
val = HIWORD_UPDATE(RK3288_UOC0_CON0_COMMON_ON_N
| RK3288_UOC0_CON0_DISABLE
| UOC_CON0_SIDDQ,
RK3288_UOC0_CON0_COMMON_ON_N
| RK3288_UOC0_CON0_DISABLE
| UOC_CON0_SIDDQ);
ret = regmap_write(grf, RK3288_UOC0_CON0, val);
if (ret)
return ret;
val = HIWORD_UPDATE(RK3288_UOC0_CON2_SOFT_CON_SEL,
RK3288_UOC0_CON2_SOFT_CON_SEL);
ret = regmap_write(grf, RK3288_UOC0_CON2, val);
if (ret)
return ret;
val = HIWORD_UPDATE(RK3288_UOC0_CON3_UTMI_OPMODE_NODRIVING
| RK3288_UOC0_CON3_UTMI_XCVRSEELCT_FSTRANSC
| RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED,
RK3288_UOC0_CON3_UTMI_SUSPENDN
| RK3288_UOC0_CON3_UTMI_OPMODE_MASK
| RK3288_UOC0_CON3_UTMI_XCVRSEELCT_MASK
| RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED);
ret = regmap_write(grf, RK3288_UOC0_CON3, val);
if (ret)
return ret;
val = HIWORD_UPDATE(RK3288_UOC0_CON3_BYPASSSEL
| RK3288_UOC0_CON3_BYPASSDMEN,
RK3288_UOC0_CON3_BYPASSSEL
| RK3288_UOC0_CON3_BYPASSDMEN);
ret = regmap_write(grf, RK3288_UOC0_CON3, val);
if (ret)
return ret;
return 0;
}
static const struct rockchip_usb_phy_pdata rk3288_pdata = {
.phys = (struct rockchip_usb_phys[]){
{ .reg = 0x320, .pll_name = "sclk_otgphy0_480m" },
......@@ -266,6 +371,8 @@ static const struct rockchip_usb_phy_pdata rk3288_pdata = {
{ .reg = 0x348, .pll_name = "sclk_otgphy2_480m" },
{ /* sentinel */ }
},
.init_usb_uart = rk3288_init_usb_uart,
.usb_uart_phy = 0,
};
static int rockchip_usb_phy_probe(struct platform_device *pdev)
......@@ -328,6 +435,60 @@ static struct platform_driver rockchip_usb_driver = {
module_platform_driver(rockchip_usb_driver);
#ifndef MODULE
static int __init rockchip_init_usb_uart(void)
{
const struct of_device_id *match;
const struct rockchip_usb_phy_pdata *data;
struct device_node *np;
struct regmap *grf;
int ret;
if (!enable_usb_uart)
return 0;
np = of_find_matching_node_and_match(NULL, rockchip_usb_phy_dt_ids,
&match);
if (!np) {
pr_err("%s: failed to find usbphy node\n", __func__);
return -ENOTSUPP;
}
pr_debug("%s: using settings for %s\n", __func__, match->compatible);
data = match->data;
if (!data->init_usb_uart) {
pr_err("%s: usb-uart not available on %s\n",
__func__, match->compatible);
return -ENOTSUPP;
}
grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
if (IS_ERR(grf)) {
pr_err("%s: Missing rockchip,grf property, %lu\n",
__func__, PTR_ERR(grf));
return PTR_ERR(grf);
}
ret = data->init_usb_uart(grf);
if (ret) {
pr_err("%s: could not init usb_uart, %d\n", __func__, ret);
enable_usb_uart = 0;
return ret;
}
return 0;
}
early_initcall(rockchip_init_usb_uart);
static int __init rockchip_usb_uart(char *buf)
{
enable_usb_uart = true;
return 0;
}
early_param("rockchip.usb_uart", rockchip_usb_uart);
#endif
MODULE_AUTHOR("Yunzhi Li <lyz@rock-chips.com>");
MODULE_DESCRIPTION("Rockchip USB 2.0 PHY driver");
MODULE_LICENSE("GPL v2");
......@@ -391,7 +391,7 @@ static void __twl4030_phy_power(struct twl4030_usb *twl, int on)
WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
}
static int twl4030_usb_runtime_suspend(struct device *dev)
static int __maybe_unused twl4030_usb_runtime_suspend(struct device *dev)
{
struct twl4030_usb *twl = dev_get_drvdata(dev);
......@@ -405,7 +405,7 @@ static int twl4030_usb_runtime_suspend(struct device *dev)
return 0;
}
static int twl4030_usb_runtime_resume(struct device *dev)
static int __maybe_unused twl4030_usb_runtime_resume(struct device *dev)
{
struct twl4030_usb *twl = dev_get_drvdata(dev);
int res;
......
......@@ -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/
......
......@@ -476,6 +476,8 @@ static ssize_t cxacru_sysfs_store_adsl_config(struct device *dev,
return -EINVAL;
if (index < 0 || index > 0x7f)
return -EINVAL;
if (tmp < 0 || tmp > len - pos)
return -EINVAL;
pos += tmp;
/* skip trailing newline */
......
......@@ -28,6 +28,11 @@ struct ci_hdrc_imx_platform_flag {
bool runtime_pm;
};
static const struct ci_hdrc_imx_platform_flag imx23_usb_data = {
.flags = CI_HDRC_TURN_VBUS_EARLY_ON |
CI_HDRC_DISABLE_STREAMING,
};
static const struct ci_hdrc_imx_platform_flag imx27_usb_data = {
CI_HDRC_DISABLE_STREAMING,
};
......@@ -66,6 +71,7 @@ static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = {
};
static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
{ .compatible = "fsl,imx23-usb", .data = &imx23_usb_data},
{ .compatible = "fsl,imx28-usb", .data = &imx28_usb_data},
{ .compatible = "fsl,imx27-usb", .data = &imx27_usb_data},
{ .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data},
......@@ -244,7 +250,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
struct ci_hdrc_platform_data pdata = {
.name = dev_name(&pdev->dev),
.capoffset = DEF_CAPOFFSET,
.flags = CI_HDRC_SET_NON_ZERO_TTHA,
};
int ret;
const struct of_device_id *of_id;
......@@ -302,9 +307,9 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
&pdata);
if (IS_ERR(data->ci_pdev)) {
ret = PTR_ERR(data->ci_pdev);
dev_err(&pdev->dev,
"Can't register ci_hdrc platform device, err=%d\n",
ret);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"ci_hdrc_add_device failed, err=%d\n", ret);
goto err_clk;
}
......
......@@ -721,6 +721,9 @@ static int ci_get_platdata(struct device *dev,
return ret;
}
if (of_find_property(dev->of_node, "non-zero-ttctrl-ttha", NULL))
platdata->flags |= CI_HDRC_SET_NON_ZERO_TTHA;
ext_id = ERR_PTR(-ENODEV);
ext_vbus = ERR_PTR(-ENODEV);
if (of_property_read_bool(dev->of_node, "extcon")) {
......
......@@ -175,7 +175,6 @@ static int ci_requests_show(struct seq_file *s, void *data)
{
struct ci_hdrc *ci = s->private;
unsigned long flags;
struct list_head *ptr = NULL;
struct ci_hw_req *req = NULL;
struct td_node *node, *tmpnode;
unsigned i, j, qsize = sizeof(struct ci_hw_td)/sizeof(u32);
......@@ -187,9 +186,7 @@ static int ci_requests_show(struct seq_file *s, void *data)
spin_lock_irqsave(&ci->lock, flags);
for (i = 0; i < ci->hw_ep_max; i++)
list_for_each(ptr, &ci->ci_hw_ep[i].qh.queue) {
req = list_entry(ptr, struct ci_hw_req, queue);
list_for_each_entry(req, &ci->ci_hw_ep[i].qh.queue, queue) {
list_for_each_entry_safe(node, tmpnode, &req->tds, td) {
seq_printf(s, "EP=%02i: TD=%08X %s\n",
i % (ci->hw_ep_max / 2),
......
......@@ -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);
......
......@@ -819,7 +819,6 @@ static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
ci->ep0out : ci->ep0in;
if (!list_empty(&hwep->qh.queue)) {
_ep_nuke(hwep);
retval = -EOVERFLOW;
dev_warn(hwep->ci->dev, "endpoint ctrl %X nuked\n",
_usb_addr(hwep));
}
......@@ -1068,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;
......
......@@ -713,9 +713,20 @@ static int acm_tty_write(struct tty_struct *tty,
}
if (acm->susp_count) {
if (acm->putbuffer) {
/* now to preserve order */
usb_anchor_urb(acm->putbuffer->urb, &acm->delayed);
acm->putbuffer = NULL;
}
usb_anchor_urb(wb->urb, &acm->delayed);
spin_unlock_irqrestore(&acm->write_lock, flags);
return count;
} else {
if (acm->putbuffer) {
/* at this point there is no good way to handle errors */
acm_start_wb(acm, acm->putbuffer);
acm->putbuffer = NULL;
}
}
stat = acm_start_wb(acm, wb);
......@@ -726,6 +737,60 @@ static int acm_tty_write(struct tty_struct *tty,
return count;
}
static void acm_tty_flush_chars(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
struct acm_wb *cur = acm->putbuffer;
int err;
unsigned long flags;
acm->putbuffer = NULL;
err = usb_autopm_get_interface_async(acm->control);
spin_lock_irqsave(&acm->write_lock, flags);
if (err < 0) {
cur->use = 0;
goto out;
}
if (acm->susp_count)
usb_anchor_urb(cur->urb, &acm->delayed);
else
acm_start_wb(acm, cur);
out:
spin_unlock_irqrestore(&acm->write_lock, flags);
return;
}
static int acm_tty_put_char(struct tty_struct *tty, unsigned char ch)
{
struct acm *acm = tty->driver_data;
struct acm_wb *cur;
int wbn;
unsigned long flags;
overflow:
cur = acm->putbuffer;
if (!cur) {
spin_lock_irqsave(&acm->write_lock, flags);
wbn = acm_wb_alloc(acm);
if (wbn >= 0) {
cur = &acm->wb[wbn];
acm->putbuffer = cur;
}
spin_unlock_irqrestore(&acm->write_lock, flags);
if (!cur)
return 0;
}
if (cur->len == acm->writesize) {
acm_tty_flush_chars(tty);
goto overflow;
}
cur->buf[cur->len++] = ch;
return 1;
}
static int acm_tty_write_room(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
......@@ -1905,6 +1970,8 @@ static const struct tty_operations acm_ops = {
.cleanup = acm_tty_cleanup,
.hangup = acm_tty_hangup,
.write = acm_tty_write,
.put_char = acm_tty_put_char,
.flush_chars = acm_tty_flush_chars,
.write_room = acm_tty_write_room,
.ioctl = acm_tty_ioctl,
.throttle = acm_tty_throttle,
......
......@@ -94,6 +94,7 @@ struct acm {
unsigned long read_urbs_free;
struct urb *read_urbs[ACM_NR];
struct acm_rb read_buffers[ACM_NR];
struct acm_wb *putbuffer; /* for acm_tty_put_char() */
int rx_buflimit;
int rx_endpoint;
spinlock_t read_lock;
......
......@@ -27,6 +27,7 @@
#include <linux/uaccess.h>
#include <linux/kref.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/usb.h>
#include <linux/usb/tmc.h>
......@@ -87,6 +88,23 @@ struct usbtmc_device_data {
u8 bTag_last_write; /* needed for abort */
u8 bTag_last_read; /* needed for abort */
/* data for interrupt in endpoint handling */
u8 bNotify1;
u8 bNotify2;
u16 ifnum;
u8 iin_bTag;
u8 *iin_buffer;
atomic_t iin_data_valid;
unsigned int iin_ep;
int iin_ep_present;
int iin_interval;
struct urb *iin_urb;
u16 iin_wMaxPacketSize;
atomic_t srq_asserted;
/* coalesced usb488_caps from usbtmc_dev_capabilities */
__u8 usb488_caps;
u8 rigol_quirk;
/* attributes from the USB TMC spec for this device */
......@@ -99,6 +117,8 @@ struct usbtmc_device_data {
struct usbtmc_dev_capabilities capabilities;
struct kref kref;
struct mutex io_mutex; /* only one i/o function running at a time */
wait_queue_head_t waitq;
struct fasync_struct *fasync;
};
#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
......@@ -373,6 +393,142 @@ static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
return rv;
}
static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
void __user *arg)
{
struct device *dev = &data->intf->dev;
u8 *buffer;
u8 tag;
__u8 stb;
int rv;
dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n",
data->iin_ep_present);
buffer = kmalloc(8, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
atomic_set(&data->iin_data_valid, 0);
/* must issue read_stb before using poll or select */
atomic_set(&data->srq_asserted, 0);
rv = usb_control_msg(data->usb_dev,
usb_rcvctrlpipe(data->usb_dev, 0),
USBTMC488_REQUEST_READ_STATUS_BYTE,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
data->iin_bTag,
data->ifnum,
buffer, 0x03, USBTMC_TIMEOUT);
if (rv < 0) {
dev_err(dev, "stb usb_control_msg returned %d\n", rv);
goto exit;
}
if (buffer[0] != USBTMC_STATUS_SUCCESS) {
dev_err(dev, "control status returned %x\n", buffer[0]);
rv = -EIO;
goto exit;
}
if (data->iin_ep_present) {
rv = wait_event_interruptible_timeout(
data->waitq,
atomic_read(&data->iin_data_valid) != 0,
USBTMC_TIMEOUT);
if (rv < 0) {
dev_dbg(dev, "wait interrupted %d\n", rv);
goto exit;
}
if (rv == 0) {
dev_dbg(dev, "wait timed out\n");
rv = -ETIME;
goto exit;
}
tag = data->bNotify1 & 0x7f;
if (tag != data->iin_bTag) {
dev_err(dev, "expected bTag %x got %x\n",
data->iin_bTag, tag);
}
stb = data->bNotify2;
} else {
stb = buffer[2];
}
rv = copy_to_user(arg, &stb, sizeof(stb));
if (rv)
rv = -EFAULT;
exit:
/* bump interrupt bTag */
data->iin_bTag += 1;
if (data->iin_bTag > 127)
/* 1 is for SRQ see USBTMC-USB488 subclass spec section 4.3.1 */
data->iin_bTag = 2;
kfree(buffer);
return rv;
}
static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
void __user *arg, unsigned int cmd)
{
struct device *dev = &data->intf->dev;
__u8 val;
u8 *buffer;
u16 wValue;
int rv;
if (!(data->usb488_caps & USBTMC488_CAPABILITY_SIMPLE))
return -EINVAL;
buffer = kmalloc(8, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
if (cmd == USBTMC488_REQUEST_REN_CONTROL) {
rv = copy_from_user(&val, arg, sizeof(val));
if (rv) {
rv = -EFAULT;
goto exit;
}
wValue = val ? 1 : 0;
} else {
wValue = 0;
}
rv = usb_control_msg(data->usb_dev,
usb_rcvctrlpipe(data->usb_dev, 0),
cmd,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
wValue,
data->ifnum,
buffer, 0x01, USBTMC_TIMEOUT);
if (rv < 0) {
dev_err(dev, "simple usb_control_msg failed %d\n", rv);
goto exit;
} else if (rv != 1) {
dev_warn(dev, "simple usb_control_msg returned %d\n", rv);
rv = -EIO;
goto exit;
}
if (buffer[0] != USBTMC_STATUS_SUCCESS) {
dev_err(dev, "simple control status returned %x\n", buffer[0]);
rv = -EIO;
goto exit;
}
rv = 0;
exit:
kfree(buffer);
return rv;
}
/*
* Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-IN endpoint.
* @transfer_size: number of bytes to request from the device.
......@@ -895,6 +1051,7 @@ static int get_capabilities(struct usbtmc_device_data *data)
data->capabilities.device_capabilities = buffer[5];
data->capabilities.usb488_interface_capabilities = buffer[14];
data->capabilities.usb488_device_capabilities = buffer[15];
data->usb488_caps = (buffer[14] & 0x07) | ((buffer[15] & 0x0f) << 4);
rv = 0;
err_out:
......@@ -1069,6 +1226,33 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case USBTMC_IOCTL_ABORT_BULK_IN:
retval = usbtmc_ioctl_abort_bulk_in(data);
break;
case USBTMC488_IOCTL_GET_CAPS:
retval = copy_to_user((void __user *)arg,
&data->usb488_caps,
sizeof(data->usb488_caps));
if (retval)
retval = -EFAULT;
break;
case USBTMC488_IOCTL_READ_STB:
retval = usbtmc488_ioctl_read_stb(data, (void __user *)arg);
break;
case USBTMC488_IOCTL_REN_CONTROL:
retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
USBTMC488_REQUEST_REN_CONTROL);
break;
case USBTMC488_IOCTL_GOTO_LOCAL:
retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
USBTMC488_REQUEST_GOTO_LOCAL);
break;
case USBTMC488_IOCTL_LOCAL_LOCKOUT:
retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
USBTMC488_REQUEST_LOCAL_LOCKOUT);
break;
}
skip_io_on_zombie:
......@@ -1076,6 +1260,34 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return retval;
}
static int usbtmc_fasync(int fd, struct file *file, int on)
{
struct usbtmc_device_data *data = file->private_data;
return fasync_helper(fd, file, on, &data->fasync);
}
static unsigned int usbtmc_poll(struct file *file, poll_table *wait)
{
struct usbtmc_device_data *data = file->private_data;
unsigned int mask;
mutex_lock(&data->io_mutex);
if (data->zombie) {
mask = POLLHUP | POLLERR;
goto no_poll;
}
poll_wait(file, &data->waitq, wait);
mask = (atomic_read(&data->srq_asserted)) ? POLLIN | POLLRDNORM : 0;
no_poll:
mutex_unlock(&data->io_mutex);
return mask;
}
static const struct file_operations fops = {
.owner = THIS_MODULE,
.read = usbtmc_read,
......@@ -1083,6 +1295,8 @@ static const struct file_operations fops = {
.open = usbtmc_open,
.release = usbtmc_release,
.unlocked_ioctl = usbtmc_ioctl,
.fasync = usbtmc_fasync,
.poll = usbtmc_poll,
.llseek = default_llseek,
};
......@@ -1092,6 +1306,67 @@ static struct usb_class_driver usbtmc_class = {
.minor_base = USBTMC_MINOR_BASE,
};
static void usbtmc_interrupt(struct urb *urb)
{
struct usbtmc_device_data *data = urb->context;
struct device *dev = &data->intf->dev;
int status = urb->status;
int rv;
dev_dbg(&data->intf->dev, "int status: %d len %d\n",
status, urb->actual_length);
switch (status) {
case 0: /* SUCCESS */
/* check for valid STB notification */
if (data->iin_buffer[0] > 0x81) {
data->bNotify1 = data->iin_buffer[0];
data->bNotify2 = data->iin_buffer[1];
atomic_set(&data->iin_data_valid, 1);
wake_up_interruptible(&data->waitq);
goto exit;
}
/* check for SRQ notification */
if (data->iin_buffer[0] == 0x81) {
if (data->fasync)
kill_fasync(&data->fasync,
SIGIO, POLL_IN);
atomic_set(&data->srq_asserted, 1);
wake_up_interruptible(&data->waitq);
goto exit;
}
dev_warn(dev, "invalid notification: %x\n", data->iin_buffer[0]);
break;
case -EOVERFLOW:
dev_err(dev, "overflow with length %d, actual length is %d\n",
data->iin_wMaxPacketSize, urb->actual_length);
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
case -EILSEQ:
case -ETIME:
/* urb terminated, clean up */
dev_dbg(dev, "urb terminated, status: %d\n", status);
return;
default:
dev_err(dev, "unknown status received: %d\n", status);
}
exit:
rv = usb_submit_urb(urb, GFP_ATOMIC);
if (rv)
dev_err(dev, "usb_submit_urb failed: %d\n", rv);
}
static void usbtmc_free_int(struct usbtmc_device_data *data)
{
if (!data->iin_ep_present || !data->iin_urb)
return;
usb_kill_urb(data->iin_urb);
kfree(data->iin_buffer);
usb_free_urb(data->iin_urb);
kref_put(&data->kref, usbtmc_delete);
}
static int usbtmc_probe(struct usb_interface *intf,
const struct usb_device_id *id)
......@@ -1114,6 +1389,9 @@ static int usbtmc_probe(struct usb_interface *intf,
usb_set_intfdata(intf, data);
kref_init(&data->kref);
mutex_init(&data->io_mutex);
init_waitqueue_head(&data->waitq);
atomic_set(&data->iin_data_valid, 0);
atomic_set(&data->srq_asserted, 0);
data->zombie = 0;
/* Determine if it is a Rigol or not */
......@@ -1134,9 +1412,12 @@ static int usbtmc_probe(struct usb_interface *intf,
data->bTag = 1;
data->TermCharEnabled = 0;
data->TermChar = '\n';
/* 2 <= bTag <= 127 USBTMC-USB488 subclass specification 4.3.1 */
data->iin_bTag = 2;
/* USBTMC devices have only one setting, so use that */
iface_desc = data->intf->cur_altsetting;
data->ifnum = iface_desc->desc.bInterfaceNumber;
/* Find bulk in endpoint */
for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
......@@ -1161,6 +1442,20 @@ static int usbtmc_probe(struct usb_interface *intf,
break;
}
}
/* Find int endpoint */
for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
endpoint = &iface_desc->endpoint[n].desc;
if (usb_endpoint_is_int_in(endpoint)) {
data->iin_ep_present = 1;
data->iin_ep = endpoint->bEndpointAddress;
data->iin_wMaxPacketSize = usb_endpoint_maxp(endpoint);
data->iin_interval = endpoint->bInterval;
dev_dbg(&intf->dev, "Found Int in endpoint at %u\n",
data->iin_ep);
break;
}
}
retcode = get_capabilities(data);
if (retcode)
......@@ -1169,6 +1464,39 @@ static int usbtmc_probe(struct usb_interface *intf,
retcode = sysfs_create_group(&intf->dev.kobj,
&capability_attr_grp);
if (data->iin_ep_present) {
/* allocate int urb */
data->iin_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!data->iin_urb) {
dev_err(&intf->dev, "Failed to allocate int urb\n");
goto error_register;
}
/* will reference data in int urb */
kref_get(&data->kref);
/* allocate buffer for interrupt in */
data->iin_buffer = kmalloc(data->iin_wMaxPacketSize,
GFP_KERNEL);
if (!data->iin_buffer) {
dev_err(&intf->dev, "Failed to allocate int buf\n");
goto error_register;
}
/* fill interrupt urb */
usb_fill_int_urb(data->iin_urb, data->usb_dev,
usb_rcvintpipe(data->usb_dev, data->iin_ep),
data->iin_buffer, data->iin_wMaxPacketSize,
usbtmc_interrupt,
data, data->iin_interval);
retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL);
if (retcode) {
dev_err(&intf->dev, "Failed to submit iin_urb\n");
goto error_register;
}
}
retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp);
retcode = usb_register_dev(intf, &usbtmc_class);
......@@ -1185,6 +1513,7 @@ static int usbtmc_probe(struct usb_interface *intf,
error_register:
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
usbtmc_free_int(data);
kref_put(&data->kref, usbtmc_delete);
return retcode;
}
......@@ -1201,7 +1530,9 @@ static void usbtmc_disconnect(struct usb_interface *intf)
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
mutex_lock(&data->io_mutex);
data->zombie = 1;
wake_up_all(&data->waitq);
mutex_unlock(&data->io_mutex);
usbtmc_free_int(data);
kref_put(&data->kref, usbtmc_delete);
}
......
......@@ -51,6 +51,7 @@ static const char *const speed_names[] = {
[USB_SPEED_HIGH] = "high-speed",
[USB_SPEED_WIRELESS] = "wireless",
[USB_SPEED_SUPER] = "super-speed",
[USB_SPEED_SUPER_PLUS] = "super-speed-plus",
};
const char *usb_speed_string(enum usb_device_speed speed)
......
......@@ -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);
......
......@@ -5,7 +5,7 @@
usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o
usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o
usbcore-y += devio.o notify.o generic.o quirks.o devices.o
usbcore-y += port.o
usbcore-y += port.o of.o
usbcore-$(CONFIG_PCI) += hcd-pci.o
usbcore-$(CONFIG_ACPI) += usb-acpi.o
......
......@@ -62,8 +62,9 @@ int hcd_buffer_create(struct usb_hcd *hcd)
char name[16];
int i, size;
if (!hcd->self.controller->dma_mask &&
!(hcd->driver->flags & HCD_LOCAL_MEM))
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
(!hcd->self.controller->dma_mask &&
!(hcd->driver->flags & HCD_LOCAL_MEM)))
return 0;
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
......@@ -93,6 +94,9 @@ void hcd_buffer_destroy(struct usb_hcd *hcd)
{
int i;
if (!IS_ENABLED(CONFIG_HAS_DMA))
return;
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
struct dma_pool *pool = hcd->pool[i];
......@@ -119,8 +123,9 @@ void *hcd_buffer_alloc(
int i;
/* some USB hosts just use PIO */
if (!bus->controller->dma_mask &&
!(hcd->driver->flags & HCD_LOCAL_MEM)) {
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
(!bus->controller->dma_mask &&
!(hcd->driver->flags & HCD_LOCAL_MEM))) {
*dma = ~(dma_addr_t) 0;
return kmalloc(size, mem_flags);
}
......@@ -145,8 +150,9 @@ void hcd_buffer_free(
if (!addr)
return;
if (!bus->controller->dma_mask &&
!(hcd->driver->flags & HCD_LOCAL_MEM)) {
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
(!bus->controller->dma_mask &&
!(hcd->driver->flags & HCD_LOCAL_MEM))) {
kfree(addr);
return;
}
......
......@@ -43,6 +43,27 @@ static int find_next_descriptor(unsigned char *buffer, int size,
return buffer - buffer0;
}
static void usb_parse_ssp_isoc_endpoint_companion(struct device *ddev,
int cfgno, int inum, int asnum, struct usb_host_endpoint *ep,
unsigned char *buffer, int size)
{
struct usb_ssp_isoc_ep_comp_descriptor *desc;
/*
* The SuperSpeedPlus Isoc endpoint companion descriptor immediately
* follows the SuperSpeed Endpoint Companion descriptor
*/
desc = (struct usb_ssp_isoc_ep_comp_descriptor *) buffer;
if (desc->bDescriptorType != USB_DT_SSP_ISOC_ENDPOINT_COMP ||
size < USB_DT_SSP_ISOC_EP_COMP_SIZE) {
dev_warn(ddev, "Invalid SuperSpeedPlus isoc endpoint companion"
"for config %d interface %d altsetting %d ep %d.\n",
cfgno, inum, asnum, ep->desc.bEndpointAddress);
return;
}
memcpy(&ep->ssp_isoc_ep_comp, desc, USB_DT_SSP_ISOC_EP_COMP_SIZE);
}
static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
int inum, int asnum, struct usb_host_endpoint *ep,
unsigned char *buffer, int size)
......@@ -54,6 +75,9 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
* be the first thing immediately following the endpoint descriptor.
*/
desc = (struct usb_ss_ep_comp_descriptor *) buffer;
buffer += desc->bLength;
size -= desc->bLength;
if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP ||
size < USB_DT_SS_EP_COMP_SIZE) {
dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
......@@ -112,6 +136,7 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
cfgno, inum, asnum, ep->desc.bEndpointAddress);
ep->ss_ep_comp.bmAttributes = 16;
} else if (usb_endpoint_xfer_isoc(&ep->desc) &&
!USB_SS_SSP_ISOC_COMP(desc->bmAttributes) &&
USB_SS_MULT(desc->bmAttributes) > 3) {
dev_warn(ddev, "Isoc endpoint has Mult of %d in "
"config %d interface %d altsetting %d ep %d: "
......@@ -121,6 +146,12 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
ep->ss_ep_comp.bmAttributes = 2;
}
/* Parse a possible SuperSpeedPlus isoc ep companion descriptor */
if (usb_endpoint_xfer_isoc(&ep->desc) &&
USB_SS_SSP_ISOC_COMP(desc->bmAttributes))
usb_parse_ssp_isoc_endpoint_companion(ddev, cfgno, inum, asnum,
ep, buffer, size);
if (usb_endpoint_xfer_isoc(&ep->desc))
max_tx = (desc->bMaxBurst + 1) *
(USB_SS_MULT(desc->bmAttributes)) *
......@@ -191,6 +222,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
if (usb_endpoint_xfer_int(d)) {
i = 1;
switch (to_usb_device(ddev)->speed) {
case USB_SPEED_SUPER_PLUS:
case USB_SPEED_SUPER:
case USB_SPEED_HIGH:
/* Many device manufacturers are using full-speed
......@@ -274,7 +306,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
}
/* Parse a possible SuperSpeed endpoint companion descriptor */
if (to_usb_device(ddev)->speed == USB_SPEED_SUPER)
if (to_usb_device(ddev)->speed >= USB_SPEED_SUPER)
usb_parse_ss_endpoint_companion(ddev, cfgno,
inum, asnum, endpoint, buffer, size);
......@@ -862,6 +894,9 @@ int usb_get_bos_descriptor(struct usb_device *dev)
dev->bos->ss_id =
(struct usb_ss_container_id_descriptor *)buffer;
break;
case USB_PTM_CAP_TYPE:
dev->bos->ptm_cap =
(struct usb_ptm_cap_descriptor *)buffer;
default:
break;
}
......
......@@ -110,13 +110,6 @@ static const char format_endpt[] =
/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
"E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%d%cs\n";
/*
* Need access to the driver and USB bus lists.
* extern struct list_head usb_bus_list;
* However, these will come from functions that return ptrs to each of them.
*/
/*
* Wait for an connect/disconnect event to happen. We initialize
* the event counter with an odd number, and each event will increment
......@@ -221,7 +214,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
break;
case USB_ENDPOINT_XFER_INT:
type = "Int.";
if (speed == USB_SPEED_HIGH || speed == USB_SPEED_SUPER)
if (speed == USB_SPEED_HIGH || speed >= USB_SPEED_SUPER)
interval = 1 << (desc->bInterval - 1);
else
interval = desc->bInterval;
......@@ -230,7 +223,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
return start;
}
interval *= (speed == USB_SPEED_HIGH ||
speed == USB_SPEED_SUPER) ? 125 : 1000;
speed >= USB_SPEED_SUPER) ? 125 : 1000;
if (interval % 1000)
unit = 'u';
else {
......@@ -322,7 +315,7 @@ static char *usb_dump_config_descriptor(char *start, char *end,
if (start > end)
return start;
if (speed == USB_SPEED_SUPER)
if (speed >= USB_SPEED_SUPER)
mul = 8;
else
mul = 2;
......@@ -534,6 +527,8 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
speed = "480"; break;
case USB_SPEED_SUPER:
speed = "5000"; break;
case USB_SPEED_SUPER_PLUS:
speed = "10000"; break;
default:
speed = "??";
}
......@@ -553,7 +548,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
/* super/high speed reserves 80%, full/low reserves 90% */
if (usbdev->speed == USB_SPEED_HIGH ||
usbdev->speed == USB_SPEED_SUPER)
usbdev->speed >= USB_SPEED_SUPER)
max = 800;
else
max = FRAME_TIME_MAX_USECS_ALLOC;
......@@ -616,6 +611,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf,
struct usb_bus *bus;
ssize_t ret, total_written = 0;
loff_t skip_bytes = *ppos;
int id;
if (*ppos < 0)
return -EINVAL;
......@@ -624,9 +620,9 @@ static ssize_t usb_device_read(struct file *file, char __user *buf,
if (!access_ok(VERIFY_WRITE, buf, nbytes))
return -EFAULT;
mutex_lock(&usb_bus_list_lock);
mutex_lock(&usb_bus_idr_lock);
/* print devices for all busses */
list_for_each_entry(bus, &usb_bus_list, bus_list) {
idr_for_each_entry(&usb_bus_idr, bus, id) {
/* recurse through all children of the root hub */
if (!bus_to_hcd(bus)->rh_registered)
continue;
......@@ -635,12 +631,12 @@ static ssize_t usb_device_read(struct file *file, char __user *buf,
bus->root_hub, bus, 0, 0, 0);
usb_unlock_device(bus->root_hub);
if (ret < 0) {
mutex_unlock(&usb_bus_list_lock);
mutex_unlock(&usb_bus_idr_lock);
return ret;
}
total_written += ret;
}
mutex_unlock(&usb_bus_list_lock);
mutex_unlock(&usb_bus_idr_lock);
return total_written;
}
......
......@@ -50,6 +50,7 @@
#include <linux/user_namespace.h>
#include <linux/scatterlist.h>
#include <linux/uaccess.h>
#include <linux/dma-mapping.h>
#include <asm/byteorder.h>
#include <linux/moduleparam.h>
......@@ -69,6 +70,7 @@ struct usb_dev_state {
spinlock_t lock; /* protects the async urb lists */
struct list_head async_pending;
struct list_head async_completed;
struct list_head memory_list;
wait_queue_head_t wait; /* wake up if a request completed */
unsigned int discsignr;
struct pid *disc_pid;
......@@ -77,6 +79,19 @@ struct usb_dev_state {
unsigned long ifclaimed;
u32 secid;
u32 disabled_bulk_eps;
bool privileges_dropped;
unsigned long interface_allowed_mask;
};
struct usb_memory {
struct list_head memlist;
int vma_use_count;
int urb_use_count;
u32 size;
void *mem;
dma_addr_t dma_handle;
unsigned long vm_start;
struct usb_dev_state *ps;
};
struct async {
......@@ -89,6 +104,7 @@ struct async {
void __user *userbuffer;
void __user *userurb;
struct urb *urb;
struct usb_memory *usbm;
unsigned int mem_usage;
int status;
u32 secid;
......@@ -162,6 +178,111 @@ static int connected(struct usb_dev_state *ps)
ps->dev->state != USB_STATE_NOTATTACHED);
}
static void dec_usb_memory_use_count(struct usb_memory *usbm, int *count)
{
struct usb_dev_state *ps = usbm->ps;
unsigned long flags;
spin_lock_irqsave(&ps->lock, flags);
--*count;
if (usbm->urb_use_count == 0 && usbm->vma_use_count == 0) {
list_del(&usbm->memlist);
spin_unlock_irqrestore(&ps->lock, flags);
usb_free_coherent(ps->dev, usbm->size, usbm->mem,
usbm->dma_handle);
usbfs_decrease_memory_usage(
usbm->size + sizeof(struct usb_memory));
kfree(usbm);
} else {
spin_unlock_irqrestore(&ps->lock, flags);
}
}
static void usbdev_vm_open(struct vm_area_struct *vma)
{
struct usb_memory *usbm = vma->vm_private_data;
unsigned long flags;
spin_lock_irqsave(&usbm->ps->lock, flags);
++usbm->vma_use_count;
spin_unlock_irqrestore(&usbm->ps->lock, flags);
}
static void usbdev_vm_close(struct vm_area_struct *vma)
{
struct usb_memory *usbm = vma->vm_private_data;
dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
}
struct vm_operations_struct usbdev_vm_ops = {
.open = usbdev_vm_open,
.close = usbdev_vm_close
};
static int usbdev_mmap(struct file *file, struct vm_area_struct *vma)
{
struct usb_memory *usbm = NULL;
struct usb_dev_state *ps = file->private_data;
size_t size = vma->vm_end - vma->vm_start;
void *mem;
unsigned long flags;
dma_addr_t dma_handle;
int ret;
ret = usbfs_increase_memory_usage(size + sizeof(struct usb_memory));
if (ret)
goto error;
usbm = kzalloc(sizeof(struct usb_memory), GFP_KERNEL);
if (!usbm) {
ret = -ENOMEM;
goto error_decrease_mem;
}
mem = usb_alloc_coherent(ps->dev, size, GFP_USER, &dma_handle);
if (!mem) {
ret = -ENOMEM;
goto error_free_usbm;
}
memset(mem, 0, size);
usbm->mem = mem;
usbm->dma_handle = dma_handle;
usbm->size = size;
usbm->ps = ps;
usbm->vm_start = vma->vm_start;
usbm->vma_use_count = 1;
INIT_LIST_HEAD(&usbm->memlist);
if (remap_pfn_range(vma, vma->vm_start,
virt_to_phys(usbm->mem) >> PAGE_SHIFT,
size, vma->vm_page_prot) < 0) {
dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
return -EAGAIN;
}
vma->vm_flags |= VM_IO;
vma->vm_flags |= (VM_DONTEXPAND | VM_DONTDUMP);
vma->vm_ops = &usbdev_vm_ops;
vma->vm_private_data = usbm;
spin_lock_irqsave(&ps->lock, flags);
list_add_tail(&usbm->memlist, &ps->memory_list);
spin_unlock_irqrestore(&ps->lock, flags);
return 0;
error_free_usbm:
kfree(usbm);
error_decrease_mem:
usbfs_decrease_memory_usage(size + sizeof(struct usb_memory));
error:
return ret;
}
static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes,
loff_t *ppos)
{
......@@ -278,8 +399,13 @@ static void free_async(struct async *as)
if (sg_page(&as->urb->sg[i]))
kfree(sg_virt(&as->urb->sg[i]));
}
kfree(as->urb->sg);
kfree(as->urb->transfer_buffer);
if (as->usbm == NULL)
kfree(as->urb->transfer_buffer);
else
dec_usb_memory_use_count(as->usbm, &as->usbm->urb_use_count);
kfree(as->urb->setup_packet);
usb_free_urb(as->urb);
usbfs_decrease_memory_usage(as->mem_usage);
......@@ -624,6 +750,10 @@ static int claimintf(struct usb_dev_state *ps, unsigned int ifnum)
if (test_bit(ifnum, &ps->ifclaimed))
return 0;
if (ps->privileges_dropped &&
!test_bit(ifnum, &ps->interface_allowed_mask))
return -EACCES;
intf = usb_ifnum_to_if(dev, ifnum);
if (!intf)
err = -ENOENT;
......@@ -848,7 +978,7 @@ static struct usb_device *usbdev_lookup_by_devt(dev_t devt)
(void *) (unsigned long) devt, match_devt);
if (!dev)
return NULL;
return container_of(dev, struct usb_device, dev);
return to_usb_device(dev);
}
/*
......@@ -861,7 +991,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
int ret;
ret = -ENOMEM;
ps = kmalloc(sizeof(struct usb_dev_state), GFP_KERNEL);
ps = kzalloc(sizeof(struct usb_dev_state), GFP_KERNEL);
if (!ps)
goto out_free_ps;
......@@ -889,16 +1019,15 @@ static int usbdev_open(struct inode *inode, struct file *file)
ps->dev = dev;
ps->file = file;
ps->interface_allowed_mask = 0xFFFFFFFF; /* 32 bits */
spin_lock_init(&ps->lock);
INIT_LIST_HEAD(&ps->list);
INIT_LIST_HEAD(&ps->async_pending);
INIT_LIST_HEAD(&ps->async_completed);
INIT_LIST_HEAD(&ps->memory_list);
init_waitqueue_head(&ps->wait);
ps->discsignr = 0;
ps->disc_pid = get_pid(task_pid(current));
ps->cred = get_current_cred();
ps->disccontext = NULL;
ps->ifclaimed = 0;
security_task_getsecid(current, &ps->secid);
smp_wmb();
list_add_tail(&ps->list, &dev->filelist);
......@@ -945,6 +1074,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
free_async(as);
as = async_getcompleted(ps);
}
kfree(ps);
return 0;
}
......@@ -1198,6 +1328,28 @@ static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
static int proc_resetdevice(struct usb_dev_state *ps)
{
struct usb_host_config *actconfig = ps->dev->actconfig;
struct usb_interface *interface;
int i, number;
/* Don't allow a device reset if the process has dropped the
* privilege to do such things and any of the interfaces are
* currently claimed.
*/
if (ps->privileges_dropped && actconfig) {
for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
interface = actconfig->interface[i];
number = interface->cur_altsetting->desc.bInterfaceNumber;
if (usb_interface_claimed(interface) &&
!test_bit(number, &ps->ifclaimed)) {
dev_warn(&ps->dev->dev,
"usbfs: interface %d claimed by %s while '%s' resets device\n",
number, interface->dev.driver->name, current->comm);
return -EACCES;
}
}
}
return usb_reset_device(ps->dev);
}
......@@ -1266,6 +1418,31 @@ static int proc_setconfig(struct usb_dev_state *ps, void __user *arg)
return status;
}
static struct usb_memory *
find_memory_area(struct usb_dev_state *ps, const struct usbdevfs_urb *uurb)
{
struct usb_memory *usbm = NULL, *iter;
unsigned long flags;
unsigned long uurb_start = (unsigned long)uurb->buffer;
spin_lock_irqsave(&ps->lock, flags);
list_for_each_entry(iter, &ps->memory_list, memlist) {
if (uurb_start >= iter->vm_start &&
uurb_start < iter->vm_start + iter->size) {
if (uurb->buffer_length > iter->vm_start + iter->size -
uurb_start) {
usbm = ERR_PTR(-EINVAL);
} else {
usbm = iter;
usbm->urb_use_count++;
}
break;
}
}
spin_unlock_irqrestore(&ps->lock, flags);
return usbm;
}
static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb,
struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
void __user *arg)
......@@ -1378,11 +1555,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
number_of_packets = uurb->number_of_packets;
isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) *
number_of_packets;
isopkt = kmalloc(isofrmlen, GFP_KERNEL);
if (!isopkt)
return -ENOMEM;
if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {
ret = -EFAULT;
isopkt = memdup_user(iso_frame_desc, isofrmlen);
if (IS_ERR(isopkt)) {
ret = PTR_ERR(isopkt);
isopkt = NULL;
goto error;
}
for (totlen = u = 0; u < number_of_packets; u++) {
......@@ -1422,6 +1598,19 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
goto error;
}
as->usbm = find_memory_area(ps, uurb);
if (IS_ERR(as->usbm)) {
ret = PTR_ERR(as->usbm);
as->usbm = NULL;
goto error;
}
/* do not use SG buffers when memory mapped segments
* are in use
*/
if (as->usbm)
num_sgs = 0;
u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length +
num_sgs * sizeof(struct scatterlist);
ret = usbfs_increase_memory_usage(u);
......@@ -1459,29 +1648,35 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
totlen -= u;
}
} else if (uurb->buffer_length > 0) {
as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
GFP_KERNEL);
if (!as->urb->transfer_buffer) {
ret = -ENOMEM;
goto error;
}
if (as->usbm) {
unsigned long uurb_start = (unsigned long)uurb->buffer;
if (!is_in) {
if (copy_from_user(as->urb->transfer_buffer,
uurb->buffer,
uurb->buffer_length)) {
ret = -EFAULT;
as->urb->transfer_buffer = as->usbm->mem +
(uurb_start - as->usbm->vm_start);
} else {
as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
GFP_KERNEL);
if (!as->urb->transfer_buffer) {
ret = -ENOMEM;
goto error;
}
} else if (uurb->type == USBDEVFS_URB_TYPE_ISO) {
/*
* Isochronous input data may end up being
* discontiguous if some of the packets are short.
* Clear the buffer so that the gaps don't leak
* kernel data to userspace.
*/
memset(as->urb->transfer_buffer, 0,
uurb->buffer_length);
if (!is_in) {
if (copy_from_user(as->urb->transfer_buffer,
uurb->buffer,
uurb->buffer_length)) {
ret = -EFAULT;
goto error;
}
} else if (uurb->type == USBDEVFS_URB_TYPE_ISO) {
/*
* Isochronous input data may end up being
* discontiguous if some of the packets are
* short. Clear the buffer so that the gaps
* don't leak kernel data to userspace.
*/
memset(as->urb->transfer_buffer, 0,
uurb->buffer_length);
}
}
}
as->urb->dev = ps->dev;
......@@ -1528,10 +1723,14 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
isopkt = NULL;
as->ps = ps;
as->userurb = arg;
if (is_in && uurb->buffer_length > 0)
if (as->usbm) {
unsigned long uurb_start = (unsigned long)uurb->buffer;
as->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
as->urb->transfer_dma = as->usbm->dma_handle +
(uurb_start - as->usbm->vm_start);
} else if (is_in && uurb->buffer_length > 0)
as->userbuffer = uurb->buffer;
else
as->userbuffer = NULL;
as->signr = uurb->signr;
as->ifnum = ifnum;
as->pid = get_pid(task_pid(current));
......@@ -1587,6 +1786,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
return 0;
error:
if (as && as->usbm)
dec_usb_memory_use_count(as->usbm, &as->usbm->urb_use_count);
kfree(isopkt);
kfree(dr);
if (as)
......@@ -1903,7 +2104,7 @@ static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg)
ret = releaseintf(ps, ifnum);
if (ret < 0)
return ret;
destroy_async_on_interface (ps, ifnum);
destroy_async_on_interface(ps, ifnum);
return 0;
}
......@@ -1915,6 +2116,9 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
struct usb_interface *intf = NULL;
struct usb_driver *driver = NULL;
if (ps->privileges_dropped)
return -EACCES;
/* alloc buffer */
size = _IOC_SIZE(ctl->ioctl_code);
if (size > 0) {
......@@ -2040,7 +2244,8 @@ static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
__u32 caps;
caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
USBDEVFS_CAP_REAP_AFTER_DISCONNECT;
USBDEVFS_CAP_REAP_AFTER_DISCONNECT | USBDEVFS_CAP_MMAP |
USBDEVFS_CAP_DROP_PRIVILEGES;
if (!ps->dev->bus->no_stop_on_short)
caps |= USBDEVFS_CAP_BULK_CONTINUATION;
if (ps->dev->bus->sg_tablesize)
......@@ -2067,6 +2272,9 @@ static int proc_disconnect_claim(struct usb_dev_state *ps, void __user *arg)
if (intf->dev.driver) {
struct usb_driver *driver = to_usb_driver(intf->dev.driver);
if (ps->privileges_dropped)
return -EACCES;
if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER) &&
strncmp(dc.driver, intf->dev.driver->name,
sizeof(dc.driver)) != 0)
......@@ -2123,6 +2331,23 @@ static int proc_free_streams(struct usb_dev_state *ps, void __user *arg)
return r;
}
static int proc_drop_privileges(struct usb_dev_state *ps, void __user *arg)
{
u32 data;
if (copy_from_user(&data, arg, sizeof(data)))
return -EFAULT;
/* This is an one way operation. Once privileges are
* dropped, you cannot regain them. You may however reissue
* this ioctl to shrink the allowed interfaces mask.
*/
ps->interface_allowed_mask &= data;
ps->privileges_dropped = true;
return 0;
}
/*
* NOTE: All requests here that have interface numbers as parameters
* are assuming that somehow the configuration has been prevented from
......@@ -2311,6 +2536,9 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
case USBDEVFS_FREE_STREAMS:
ret = proc_free_streams(ps, p);
break;
case USBDEVFS_DROP_PRIVILEGES:
ret = proc_drop_privileges(ps, p);
break;
}
done:
......@@ -2366,6 +2594,7 @@ const struct file_operations usbdev_file_operations = {
#ifdef CONFIG_COMPAT
.compat_ioctl = usbdev_compat_ioctl,
#endif
.mmap = usbdev_mmap,
.open = usbdev_open,
.release = usbdev_release,
};
......
......@@ -19,6 +19,7 @@
#include <linux/errno.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/usb.h>
#include "usb.h"
......@@ -155,7 +156,6 @@ int usb_register_dev(struct usb_interface *intf,
int minor_base = class_driver->minor_base;
int minor;
char name[20];
char *temp;
#ifdef CONFIG_USB_DYNAMIC_MINORS
/*
......@@ -192,14 +192,9 @@ int usb_register_dev(struct usb_interface *intf,
/* create a usb class device for this usb interface */
snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
temp = strrchr(name, '/');
if (temp && (temp[1] != '\0'))
++temp;
else
temp = name;
intf->usb_dev = device_create(usb_class->class, &intf->dev,
MKDEV(USB_MAJOR, minor), class_driver,
"%s", temp);
"%s", kbasename(name));
if (IS_ERR(intf->usb_dev)) {
down_write(&minor_rwsem);
usb_minors[minor] = NULL;
......
......@@ -196,7 +196,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
* The xHCI driver has its own irq management
* make sure irq setup is not touched for xhci in generic hcd code
*/
if ((driver->flags & HCD_MASK) != HCD_USB3) {
if ((driver->flags & HCD_MASK) < HCD_USB3) {
if (!dev->irq) {
dev_err(&dev->dev,
"Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
......
......@@ -90,16 +90,15 @@ unsigned long usb_hcds_loaded;
EXPORT_SYMBOL_GPL(usb_hcds_loaded);
/* host controllers we manage */
LIST_HEAD (usb_bus_list);
EXPORT_SYMBOL_GPL (usb_bus_list);
DEFINE_IDR (usb_bus_idr);
EXPORT_SYMBOL_GPL (usb_bus_idr);
/* used when allocating bus numbers */
#define USB_MAXBUS 64
static DECLARE_BITMAP(busmap, USB_MAXBUS);
/* used when updating list of hcds */
DEFINE_MUTEX(usb_bus_list_lock); /* exported only for usbfs */
EXPORT_SYMBOL_GPL (usb_bus_list_lock);
DEFINE_MUTEX(usb_bus_idr_lock); /* exported only for usbfs */
EXPORT_SYMBOL_GPL (usb_bus_idr_lock);
/* used for controlling access to virtual root hubs */
static DEFINE_SPINLOCK(hcd_root_hub_lock);
......@@ -128,6 +127,27 @@ static inline int is_root_hub(struct usb_device *udev)
#define KERNEL_REL bin2bcd(((LINUX_VERSION_CODE >> 16) & 0x0ff))
#define KERNEL_VER bin2bcd(((LINUX_VERSION_CODE >> 8) & 0x0ff))
/* usb 3.1 root hub device descriptor */
static const u8 usb31_rh_dev_descriptor[18] = {
0x12, /* __u8 bLength; */
USB_DT_DEVICE, /* __u8 bDescriptorType; Device */
0x10, 0x03, /* __le16 bcdUSB; v3.1 */
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
0x00, /* __u8 bDeviceSubClass; */
0x03, /* __u8 bDeviceProtocol; USB 3 hub */
0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */
0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
0x03, 0x00, /* __le16 idProduct; device 0x0003 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
0x03, /* __u8 iManufacturer; */
0x02, /* __u8 iProduct; */
0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
/* usb 3.0 root hub device descriptor */
static const u8 usb3_rh_dev_descriptor[18] = {
0x12, /* __u8 bLength; */
......@@ -557,6 +577,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
case USB_DT_DEVICE << 8:
switch (hcd->speed) {
case HCD_USB31:
bufp = usb31_rh_dev_descriptor;
break;
case HCD_USB3:
bufp = usb3_rh_dev_descriptor;
break;
......@@ -645,9 +667,15 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
/* non-generic request */
switch (typeReq) {
case GetHubStatus:
case GetPortStatus:
len = 4;
break;
case GetPortStatus:
if (wValue == HUB_PORT_STATUS)
len = 4;
else
/* other port status types return 8 bytes */
len = 8;
break;
case GetHubDescriptor:
len = sizeof (struct usb_hub_descriptor);
break;
......@@ -967,8 +995,6 @@ static void usb_bus_init (struct usb_bus *bus)
bus->bandwidth_int_reqs = 0;
bus->bandwidth_isoc_reqs = 0;
mutex_init(&bus->usb_address0_mutex);
INIT_LIST_HEAD (&bus->bus_list);
}
/*-------------------------------------------------------------------------*/
......@@ -988,18 +1014,14 @@ static int usb_register_bus(struct usb_bus *bus)
int result = -E2BIG;
int busnum;
mutex_lock(&usb_bus_list_lock);
busnum = find_next_zero_bit(busmap, USB_MAXBUS, 1);
if (busnum >= USB_MAXBUS) {
printk (KERN_ERR "%s: too many buses\n", usbcore_name);
mutex_lock(&usb_bus_idr_lock);
busnum = idr_alloc(&usb_bus_idr, bus, 1, USB_MAXBUS, GFP_KERNEL);
if (busnum < 0) {
pr_err("%s: failed to get bus number\n", usbcore_name);
goto error_find_busnum;
}
set_bit(busnum, busmap);
bus->busnum = busnum;
/* Add it to the local list of buses */
list_add (&bus->bus_list, &usb_bus_list);
mutex_unlock(&usb_bus_list_lock);
mutex_unlock(&usb_bus_idr_lock);
usb_notify_add_bus(bus);
......@@ -1008,7 +1030,7 @@ static int usb_register_bus(struct usb_bus *bus)
return 0;
error_find_busnum:
mutex_unlock(&usb_bus_list_lock);
mutex_unlock(&usb_bus_idr_lock);
return result;
}
......@@ -1029,13 +1051,11 @@ static void usb_deregister_bus (struct usb_bus *bus)
* controller code, as well as having it call this when cleaning
* itself up
*/
mutex_lock(&usb_bus_list_lock);
list_del (&bus->bus_list);
mutex_unlock(&usb_bus_list_lock);
mutex_lock(&usb_bus_idr_lock);
idr_remove(&usb_bus_idr, bus->busnum);
mutex_unlock(&usb_bus_idr_lock);
usb_notify_remove_bus(bus);
clear_bit(bus->busnum, busmap);
}
/**
......@@ -1063,12 +1083,12 @@ static int register_root_hub(struct usb_hcd *hcd)
set_bit (devnum, usb_dev->bus->devmap.devicemap);
usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
mutex_lock(&usb_bus_list_lock);
mutex_lock(&usb_bus_idr_lock);
usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
if (retval != sizeof usb_dev->descriptor) {
mutex_unlock(&usb_bus_list_lock);
mutex_unlock(&usb_bus_idr_lock);
dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
dev_name(&usb_dev->dev), retval);
return (retval < 0) ? retval : -EMSGSIZE;
......@@ -1078,8 +1098,8 @@ static int register_root_hub(struct usb_hcd *hcd)
retval = usb_get_bos_descriptor(usb_dev);
if (!retval) {
usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev);
} else if (usb_dev->speed == USB_SPEED_SUPER) {
mutex_unlock(&usb_bus_list_lock);
} else if (usb_dev->speed >= USB_SPEED_SUPER) {
mutex_unlock(&usb_bus_idr_lock);
dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
dev_name(&usb_dev->dev), retval);
return retval;
......@@ -1099,7 +1119,7 @@ static int register_root_hub(struct usb_hcd *hcd)
if (HCD_DEAD(hcd))
usb_hc_died (hcd); /* This time clean up */
}
mutex_unlock(&usb_bus_list_lock);
mutex_unlock(&usb_bus_idr_lock);
return retval;
}
......@@ -1408,7 +1428,8 @@ static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle,
void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
if (urb->transfer_flags & URB_SETUP_MAP_SINGLE)
if (IS_ENABLED(CONFIG_HAS_DMA) &&
(urb->transfer_flags & URB_SETUP_MAP_SINGLE))
dma_unmap_single(hcd->self.controller,
urb->setup_dma,
sizeof(struct usb_ctrlrequest),
......@@ -1440,17 +1461,20 @@ void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
usb_hcd_unmap_urb_setup_for_dma(hcd, urb);
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
if (urb->transfer_flags & URB_DMA_MAP_SG)
if (IS_ENABLED(CONFIG_HAS_DMA) &&
(urb->transfer_flags & URB_DMA_MAP_SG))
dma_unmap_sg(hcd->self.controller,
urb->sg,
urb->num_sgs,
dir);
else if (urb->transfer_flags & URB_DMA_MAP_PAGE)
else if (IS_ENABLED(CONFIG_HAS_DMA) &&
(urb->transfer_flags & URB_DMA_MAP_PAGE))
dma_unmap_page(hcd->self.controller,
urb->transfer_dma,
urb->transfer_buffer_length,
dir);
else if (urb->transfer_flags & URB_DMA_MAP_SINGLE)
else if (IS_ENABLED(CONFIG_HAS_DMA) &&
(urb->transfer_flags & URB_DMA_MAP_SINGLE))
dma_unmap_single(hcd->self.controller,
urb->transfer_dma,
urb->transfer_buffer_length,
......@@ -1492,7 +1516,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
if (usb_endpoint_xfer_control(&urb->ep->desc)) {
if (hcd->self.uses_pio_for_control)
return ret;
if (hcd->self.uses_dma) {
if (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
urb->setup_dma = dma_map_single(
hcd->self.controller,
urb->setup_packet,
......@@ -1518,7 +1542,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
if (urb->transfer_buffer_length != 0
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
if (hcd->self.uses_dma) {
if (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
if (urb->num_sgs) {
int n;
......@@ -2112,7 +2136,7 @@ int usb_alloc_streams(struct usb_interface *interface,
hcd = bus_to_hcd(dev->bus);
if (!hcd->driver->alloc_streams || !hcd->driver->free_streams)
return -EINVAL;
if (dev->speed != USB_SPEED_SUPER)
if (dev->speed < USB_SPEED_SUPER)
return -EINVAL;
if (dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
......@@ -2160,7 +2184,7 @@ int usb_free_streams(struct usb_interface *interface,
dev = interface_to_usbdev(interface);
hcd = bus_to_hcd(dev->bus);
if (dev->speed != USB_SPEED_SUPER)
if (dev->speed < USB_SPEED_SUPER)
return -EINVAL;
/* Double-free is not allowed */
......@@ -2208,7 +2232,7 @@ int usb_hcd_get_frame_number (struct usb_device *udev)
int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
{
struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
struct usb_hcd *hcd = bus_to_hcd(rhdev->bus);
int status;
int old_state = hcd->state;
......@@ -2257,7 +2281,7 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
{
struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
struct usb_hcd *hcd = bus_to_hcd(rhdev->bus);
int status;
int old_state = hcd->state;
......@@ -2371,7 +2395,7 @@ int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num)
* boards with root hubs hooked up to internal devices (instead of
* just the OTG port) may need more attention to resetting...
*/
hcd = container_of (bus, struct usb_hcd, self);
hcd = bus_to_hcd(bus);
if (port_num && hcd->driver->start_port_reset)
status = hcd->driver->start_port_reset(hcd, port_num);
......@@ -2778,9 +2802,11 @@ int usb_add_hcd(struct usb_hcd *hcd,
rhdev->speed = USB_SPEED_WIRELESS;
break;
case HCD_USB3:
case HCD_USB31:
rhdev->speed = USB_SPEED_SUPER;
break;
case HCD_USB31:
rhdev->speed = USB_SPEED_SUPER_PLUS;
break;
default:
retval = -EINVAL;
goto err_set_rh_speed;
......@@ -2863,9 +2889,9 @@ int usb_add_hcd(struct usb_hcd *hcd,
#ifdef CONFIG_PM
cancel_work_sync(&hcd->wakeup_work);
#endif
mutex_lock(&usb_bus_list_lock);
mutex_lock(&usb_bus_idr_lock);
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
mutex_unlock(&usb_bus_list_lock);
mutex_unlock(&usb_bus_idr_lock);
err_register_root_hub:
hcd->rh_pollable = 0;
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
......@@ -2932,9 +2958,9 @@ void usb_remove_hcd(struct usb_hcd *hcd)
cancel_work_sync(&hcd->wakeup_work);
#endif
mutex_lock(&usb_bus_list_lock);
mutex_lock(&usb_bus_idr_lock);
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
mutex_unlock(&usb_bus_list_lock);
mutex_unlock(&usb_bus_idr_lock);
/*
* tasklet_kill() isn't needed here because:
......
......@@ -49,7 +49,7 @@ static void hub_event(struct work_struct *work);
DEFINE_MUTEX(usb_port_peer_mutex);
/* cycle leds on hubs that aren't blinking for attention */
static bool blinkenlights = 0;
static bool blinkenlights;
module_param(blinkenlights, bool, S_IRUGO);
MODULE_PARM_DESC(blinkenlights, "true to cycle leds on hubs");
......@@ -78,7 +78,7 @@ MODULE_PARM_DESC(initial_descriptor_timeout,
* otherwise the new scheme is used. If that fails and "use_both_schemes"
* is set, then the driver will make another attempt, using the other scheme.
*/
static bool old_scheme_first = 0;
static bool old_scheme_first;
module_param(old_scheme_first, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(old_scheme_first,
"start with the old device initialization scheme");
......@@ -298,7 +298,7 @@ static void usb_set_lpm_parameters(struct usb_device *udev)
unsigned int hub_u1_del;
unsigned int hub_u2_del;
if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER)
if (!udev->lpm_capable || udev->speed < USB_SPEED_SUPER)
return;
hub = usb_hub_to_struct_hub(udev->parent);
......@@ -537,29 +537,34 @@ static int get_hub_status(struct usb_device *hdev,
/*
* USB 2.0 spec Section 11.24.2.7
* USB 3.1 takes into use the wValue and wLength fields, spec Section 10.16.2.6
*/
static int get_port_status(struct usb_device *hdev, int port1,
struct usb_port_status *data)
void *data, u16 value, u16 length)
{
int i, status = -ETIMEDOUT;
for (i = 0; i < USB_STS_RETRIES &&
(status == -ETIMEDOUT || status == -EPIPE); i++) {
status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port1,
data, sizeof(*data), USB_STS_TIMEOUT);
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, value,
port1, data, length, USB_STS_TIMEOUT);
}
return status;
}
static int hub_port_status(struct usb_hub *hub, int port1,
u16 *status, u16 *change)
static int hub_ext_port_status(struct usb_hub *hub, int port1, int type,
u16 *status, u16 *change, u32 *ext_status)
{
int ret;
int len = 4;
if (type != HUB_PORT_STATUS)
len = 8;
mutex_lock(&hub->status_mutex);
ret = get_port_status(hub->hdev, port1, &hub->status->port);
if (ret < 4) {
ret = get_port_status(hub->hdev, port1, &hub->status->port, type, len);
if (ret < len) {
if (ret != -ENODEV)
dev_err(hub->intfdev,
"%s failed (err = %d)\n", __func__, ret);
......@@ -568,13 +573,22 @@ static int hub_port_status(struct usb_hub *hub, int port1,
} else {
*status = le16_to_cpu(hub->status->port.wPortStatus);
*change = le16_to_cpu(hub->status->port.wPortChange);
if (type != HUB_PORT_STATUS && ext_status)
*ext_status = le32_to_cpu(
hub->status->port.dwExtPortStatus);
ret = 0;
}
mutex_unlock(&hub->status_mutex);
return ret;
}
static int hub_port_status(struct usb_hub *hub, int port1,
u16 *status, u16 *change)
{
return hub_ext_port_status(hub, port1, HUB_PORT_STATUS,
status, change, NULL);
}
static void kick_hub_wq(struct usb_hub *hub)
{
struct usb_interface *intf;
......@@ -2131,7 +2145,7 @@ static void hub_disconnect_children(struct usb_device *udev)
* Something got disconnected. Get rid of it and all of its children.
*
* If *pdev is a normal device then the parent hub must already be locked.
* If *pdev is a root hub then the caller must hold the usb_bus_list_lock,
* If *pdev is a root hub then the caller must hold the usb_bus_idr_lock,
* which protects the set of root hubs as well as the list of buses.
*
* Only hub drivers (including virtual root hub drivers for host
......@@ -2429,7 +2443,7 @@ static void set_usb_port_removable(struct usb_device *udev)
* enumerated. The device descriptor is available, but not descriptors
* for any device configuration. The caller must have locked either
* the parent hub (if udev is a normal device) or else the
* usb_bus_list_lock (if udev is a root hub). The parent's pointer to
* usb_bus_idr_lock (if udev is a root hub). The parent's pointer to
* udev has already been installed, but udev is not yet visible through
* sysfs or other filesystem code.
*
......@@ -2612,6 +2626,32 @@ int usb_authorize_device(struct usb_device *usb_dev)
return result;
}
/*
* Return 1 if port speed is SuperSpeedPlus, 0 otherwise
* check it from the link protocol field of the current speed ID attribute.
* current speed ID is got from ext port status request. Sublink speed attribute
* table is returned with the hub BOS SSP device capability descriptor
*/
static int port_speed_is_ssp(struct usb_device *hdev, int speed_id)
{
int ssa_count;
u32 ss_attr;
int i;
struct usb_ssp_cap_descriptor *ssp_cap = hdev->bos->ssp_cap;
if (!ssp_cap)
return 0;
ssa_count = le32_to_cpu(ssp_cap->bmAttributes) &
USB_SSP_SUBLINK_SPEED_ATTRIBS;
for (i = 0; i <= ssa_count; i++) {
ss_attr = le32_to_cpu(ssp_cap->bmSublinkSpeedAttr[i]);
if (speed_id == (ss_attr & USB_SSP_SUBLINK_SPEED_SSID))
return !!(ss_attr & USB_SSP_SUBLINK_SPEED_LP);
}
return 0;
}
/* Returns 1 if @hub is a WUSB root hub, 0 otherwise */
static unsigned hub_is_wusb(struct usb_hub *hub)
......@@ -2619,7 +2659,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
struct usb_hcd *hcd;
if (hub->hdev->parent != NULL) /* not a root hub? */
return 0;
hcd = container_of(hub->hdev->bus, struct usb_hcd, self);
hcd = bus_to_hcd(hub->hdev->bus);
return hcd->wireless;
}
......@@ -2645,7 +2685,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
*/
static bool use_new_scheme(struct usb_device *udev, int retry)
{
if (udev->speed == USB_SPEED_SUPER)
if (udev->speed >= USB_SPEED_SUPER)
return false;
return USE_NEW_SCHEME(retry);
......@@ -2676,6 +2716,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
int delay_time, ret;
u16 portstatus;
u16 portchange;
u32 ext_portstatus = 0;
for (delay_time = 0;
delay_time < HUB_RESET_TIMEOUT;
......@@ -2684,7 +2725,14 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
msleep(delay);
/* read and decode port status */
ret = hub_port_status(hub, port1, &portstatus, &portchange);
if (hub_is_superspeedplus(hub->hdev))
ret = hub_ext_port_status(hub, port1,
HUB_EXT_PORT_STATUS,
&portstatus, &portchange,
&ext_portstatus);
else
ret = hub_port_status(hub, port1, &portstatus,
&portchange);
if (ret < 0)
return ret;
......@@ -2727,6 +2775,10 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
if (hub_is_wusb(hub))
udev->speed = USB_SPEED_WIRELESS;
else if (hub_is_superspeedplus(hub->hdev) &&
port_speed_is_ssp(hub->hdev, ext_portstatus &
USB_EXT_PORT_STAT_RX_SPEED_ID))
udev->speed = USB_SPEED_SUPER_PLUS;
else if (hub_is_superspeed(hub->hdev))
udev->speed = USB_SPEED_SUPER;
else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
......@@ -3989,7 +4041,7 @@ int usb_disable_lpm(struct usb_device *udev)
struct usb_hcd *hcd;
if (!udev || !udev->parent ||
udev->speed != USB_SPEED_SUPER ||
udev->speed < USB_SPEED_SUPER ||
!udev->lpm_capable ||
udev->state < USB_STATE_DEFAULT)
return 0;
......@@ -4048,7 +4100,7 @@ void usb_enable_lpm(struct usb_device *udev)
struct usb_port *port_dev;
if (!udev || !udev->parent ||
udev->speed != USB_SPEED_SUPER ||
udev->speed < USB_SPEED_SUPER ||
!udev->lpm_capable ||
udev->state < USB_STATE_DEFAULT)
return;
......@@ -4292,7 +4344,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
{
struct usb_device *hdev = hub->hdev;
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
int i, j, retval;
int retries, operations, retval, i;
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
const char *speed;
......@@ -4323,7 +4375,9 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
retval = -ENODEV;
if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
/* Don't allow speed changes at reset, except usb 3.0 to faster */
if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed &&
!(oldspeed == USB_SPEED_SUPER && udev->speed > oldspeed)) {
dev_dbg(&udev->dev, "device reset changed speed!\n");
goto fail;
}
......@@ -4335,6 +4389,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
* reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
*/
switch (udev->speed) {
case USB_SPEED_SUPER_PLUS:
case USB_SPEED_SUPER:
case USB_SPEED_WIRELESS: /* fixed at 512 */
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
......@@ -4361,7 +4416,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
else
speed = usb_speed_string(udev->speed);
if (udev->speed != USB_SPEED_SUPER)
if (udev->speed < USB_SPEED_SUPER)
dev_info(&udev->dev,
"%s %s USB device number %d using %s\n",
(udev->config) ? "reset" : "new", speed,
......@@ -4394,7 +4449,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
* first 8 bytes of the device descriptor to get the ep0 maxpacket
* value.
*/
for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) {
bool did_new_scheme = false;
if (use_new_scheme(udev, retry_counter)) {
......@@ -4421,7 +4476,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
* 255 is for WUSB devices, we actually need to use
* 512 (WUSB1.0[4.8.1]).
*/
for (j = 0; j < 3; ++j) {
for (operations = 0; operations < 3; ++operations) {
buf->bMaxPacketSize0 = 0;
r = usb_control_msg(udev, usb_rcvaddr0pipe(),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
......@@ -4441,7 +4496,13 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
r = -EPROTO;
break;
}
if (r == 0)
/*
* Some devices time out if they are powered on
* when already connected. They need a second
* reset. But only on the first attempt,
* lest we get into a time out/reset loop
*/
if (r == 0 || (r == -ETIMEDOUT && retries == 0))
break;
}
udev->descriptor.bMaxPacketSize0 =
......@@ -4473,7 +4534,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
* authorization will assign the final address.
*/
if (udev->wusb == 0) {
for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
for (operations = 0; operations < SET_ADDRESS_TRIES; ++operations) {
retval = hub_set_address(udev, devnum);
if (retval >= 0)
break;
......@@ -4485,11 +4546,12 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
devnum, retval);
goto fail;
}
if (udev->speed == USB_SPEED_SUPER) {
if (udev->speed >= USB_SPEED_SUPER) {
devnum = udev->devnum;
dev_info(&udev->dev,
"%s SuperSpeed USB device number %d using %s\n",
"%s SuperSpeed%s USB device number %d using %s\n",
(udev->config) ? "reset" : "new",
(udev->speed == USB_SPEED_SUPER_PLUS) ? "Plus" : "",
devnum, udev->bus->controller->driver->name);
}
......@@ -4528,7 +4590,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
* got from those devices show they aren't superspeed devices. Warm
* reset the port attached by the devices can fix them.
*/
if ((udev->speed == USB_SPEED_SUPER) &&
if ((udev->speed >= USB_SPEED_SUPER) &&
(le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
dev_err(&udev->dev, "got a wrong device descriptor, "
"warm reset device\n");
......@@ -4539,7 +4601,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
}
if (udev->descriptor.bMaxPacketSize0 == 0xff ||
udev->speed == USB_SPEED_SUPER)
udev->speed >= USB_SPEED_SUPER)
i = 512;
else
i = udev->descriptor.bMaxPacketSize0;
......@@ -4749,7 +4811,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
udev->level = hdev->level + 1;
udev->wusb = hub_is_wusb(hub);
/* Only USB 3.0 devices are connected to SuperSpeed hubs. */
/* Devices connected to SuperSpeed hubs are USB 3.0 or later */
if (hub_is_superspeed(hub->hdev))
udev->speed = USB_SPEED_SUPER;
else
......
......@@ -140,6 +140,13 @@ static inline int hub_is_superspeed(struct usb_device *hdev)
return hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS;
}
static inline int hub_is_superspeedplus(struct usb_device *hdev)
{
return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS &&
le16_to_cpu(hdev->descriptor.bcdUSB) >= 0x0310 &&
hdev->bos->ssp_cap);
}
static inline unsigned hub_power_on_good_delay(struct usb_hub *hub)
{
unsigned delay = hub->descriptor->bPwrOn2PwrGood * 2;
......
/*
* of.c The helpers for hcd device tree support
*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
* Author: Peter Chen <peter.chen@freescale.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 of
* the License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/of.h>
/**
* usb_of_get_child_node - Find the device node match port number
* @parent: the parent device node
* @portnum: the port number which device is connecting
*
* Find the node from device tree according to its port number.
*
* Return: On success, a pointer to the device node, %NULL on failure.
*/
struct device_node *usb_of_get_child_node(struct device_node *parent,
int portnum)
{
struct device_node *node;
u32 port;
for_each_child_of_node(parent, node) {
if (!of_property_read_u32(node, "reg", &port)) {
if (port == portnum)
return node;
}
}
return NULL;
}
EXPORT_SYMBOL_GPL(usb_of_get_child_node);
......@@ -23,10 +23,12 @@ static ssize_t field##_show(struct device *dev, \
{ \
struct usb_device *udev; \
struct usb_host_config *actconfig; \
ssize_t rc = 0; \
ssize_t rc; \
\
udev = to_usb_device(dev); \
usb_lock_device(udev); \
rc = usb_lock_device_interruptible(udev); \
if (rc < 0) \
return -EINTR; \
actconfig = udev->actconfig; \
if (actconfig) \
rc = sprintf(buf, format_string, \
......@@ -47,10 +49,12 @@ static ssize_t bMaxPower_show(struct device *dev,
{
struct usb_device *udev;
struct usb_host_config *actconfig;
ssize_t rc = 0;
ssize_t rc;
udev = to_usb_device(dev);
usb_lock_device(udev);
rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
actconfig = udev->actconfig;
if (actconfig)
rc = sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig));
......@@ -64,10 +68,12 @@ static ssize_t configuration_show(struct device *dev,
{
struct usb_device *udev;
struct usb_host_config *actconfig;
ssize_t rc = 0;
ssize_t rc;
udev = to_usb_device(dev);
usb_lock_device(udev);
rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
actconfig = udev->actconfig;
if (actconfig && actconfig->string)
rc = sprintf(buf, "%s\n", actconfig->string);
......@@ -84,11 +90,13 @@ static ssize_t bConfigurationValue_store(struct device *dev,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
int config, value;
int config, value, rc;
if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255)
return -EINVAL;
usb_lock_device(udev);
rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
value = usb_set_configuration(udev, config);
usb_unlock_device(udev);
return (value < 0) ? value : count;
......@@ -105,7 +113,9 @@ static ssize_t name##_show(struct device *dev, \
int retval; \
\
udev = to_usb_device(dev); \
usb_lock_device(udev); \
retval = usb_lock_device_interruptible(udev); \
if (retval < 0) \
return -EINTR; \
retval = sprintf(buf, "%s\n", udev->name); \
usb_unlock_device(udev); \
return retval; \
......@@ -141,6 +151,9 @@ static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
case USB_SPEED_SUPER:
speed = "5000";
break;
case USB_SPEED_SUPER_PLUS:
speed = "10000";
break;
default:
speed = "unknown";
}
......@@ -224,11 +237,13 @@ static ssize_t avoid_reset_quirk_store(struct device *dev,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
int val;
int val, rc;
if (sscanf(buf, "%d", &val) != 1 || val < 0 || val > 1)
return -EINVAL;
usb_lock_device(udev);
rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
if (val)
udev->quirks |= USB_QUIRK_RESET;
else
......@@ -294,7 +309,7 @@ static ssize_t persist_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
int value;
int value, rc;
/* Hubs are always enabled for USB_PERSIST */
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
......@@ -303,7 +318,9 @@ static ssize_t persist_store(struct device *dev, struct device_attribute *attr,
if (sscanf(buf, "%d", &value) != 1)
return -EINVAL;
usb_lock_device(udev);
rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
udev->persist_enabled = !!value;
usb_unlock_device(udev);
return count;
......@@ -420,13 +437,16 @@ static ssize_t level_store(struct device *dev, struct device_attribute *attr,
int len = count;
char *cp;
int rc = count;
int rv;
warn_level();
cp = memchr(buf, '\n', count);
if (cp)
len = cp - buf;
usb_lock_device(udev);
rv = usb_lock_device_interruptible(udev);
if (rv < 0)
return -EINTR;
if (len == sizeof on_string - 1 &&
strncmp(buf, on_string, len) == 0)
......@@ -466,7 +486,9 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev,
bool value;
int ret;
usb_lock_device(udev);
ret = usb_lock_device_interruptible(udev);
if (ret < 0)
return -EINTR;
ret = strtobool(buf, &value);
......@@ -536,8 +558,11 @@ static ssize_t usb3_hardware_lpm_u1_show(struct device *dev,
{
struct usb_device *udev = to_usb_device(dev);
const char *p;
int rc;
usb_lock_device(udev);
rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
if (udev->usb3_lpm_u1_enabled)
p = "enabled";
......@@ -555,8 +580,11 @@ static ssize_t usb3_hardware_lpm_u2_show(struct device *dev,
{
struct usb_device *udev = to_usb_device(dev);
const char *p;
int rc;
usb_lock_device(udev);
rc = usb_lock_device_interruptible(udev);
if (rc < 0)
return -EINTR;
if (udev->usb3_lpm_u2_enabled)
p = "enabled";
......@@ -822,7 +850,6 @@ read_descriptors(struct file *filp, struct kobject *kobj,
* Following that are the raw descriptor entries for all the
* configurations (config plus subsidiary descriptors).
*/
usb_lock_device(udev);
for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations &&
nleft > 0; ++cfgno) {
if (cfgno < 0) {
......@@ -843,7 +870,6 @@ read_descriptors(struct file *filp, struct kobject *kobj,
off -= srclen;
}
}
usb_unlock_device(udev);
return count - nleft;
}
......@@ -969,7 +995,9 @@ static ssize_t supports_autosuspend_show(struct device *dev,
{
int s;
device_lock(dev);
s = device_lock_interruptible(dev);
if (s < 0)
return -EINTR;
/* Devices will be autosuspended even when an interface isn't claimed */
s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend);
device_unlock(dev);
......
......@@ -401,7 +401,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
/* SuperSpeed isoc endpoints have up to 16 bursts of up to
* 3 packets each
*/
if (dev->speed == USB_SPEED_SUPER) {
if (dev->speed >= USB_SPEED_SUPER) {
int burst = 1 + ep->ss_ep_comp.bMaxBurst;
int mult = USB_SS_MULT(ep->ss_ep_comp.bmAttributes);
max *= burst;
......@@ -499,6 +499,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
}
/* too big? */
switch (dev->speed) {
case USB_SPEED_SUPER_PLUS:
case USB_SPEED_SUPER: /* units are 125us */
/* Handle up to 2^(16-1) microframes */
if (urb->interval > (1 << 15))
......
......@@ -36,6 +36,7 @@
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <linux/usb/of.h>
#include <asm/io.h>
#include <linux/scatterlist.h>
......@@ -241,7 +242,7 @@ static int __each_dev(struct device *dev, void *data)
if (!is_usb_device(dev))
return 0;
return arg->fn(container_of(dev, struct usb_device, dev), arg->data);
return arg->fn(to_usb_device(dev), arg->data);
}
/**
......@@ -397,7 +398,7 @@ struct device_type usb_device_type = {
/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
static unsigned usb_bus_is_wusb(struct usb_bus *bus)
{
struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self);
struct usb_hcd *hcd = bus_to_hcd(bus);
return hcd->wireless;
}
......@@ -470,6 +471,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
dev->route = 0;
dev->dev.parent = bus->controller;
dev->dev.of_node = bus->controller->of_node;
dev_set_name(&dev->dev, "usb%d", bus->busnum);
root_hub = 1;
} else {
......@@ -494,6 +496,14 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
dev->dev.parent = &parent->dev;
dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
if (!parent->parent) {
/* device under root hub's port */
port1 = usb_hcd_find_raw_port_number(usb_hcd,
port1);
}
dev->dev.of_node = usb_of_get_child_node(parent->dev.of_node,
port1);
/* hub driver sets up TT records */
}
......@@ -1115,6 +1125,7 @@ static void __exit usb_exit(void)
bus_unregister(&usb_bus_type);
usb_acpi_unregister();
usb_debugfs_cleanup();
idr_destroy(&usb_bus_idr);
}
subsys_initcall(usb_init);
......
......@@ -45,7 +45,7 @@ static inline unsigned usb_get_max_power(struct usb_device *udev,
struct usb_host_config *c)
{
/* SuperSpeed power is in 8 mA units; others are in 2 mA units */
unsigned mul = (udev->speed == USB_SPEED_SUPER ? 8 : 2);
unsigned mul = (udev->speed >= USB_SPEED_SUPER ? 8 : 2);
return c->desc.bMaxPower * mul;
}
......
......@@ -2,6 +2,7 @@ config USB_DWC2
tristate "DesignWare USB2 DRD Core Support"
depends on HAS_DMA
depends on USB || USB_GADGET
depends on HAS_IOMEM
help
Say Y here if your system has a Dual Role Hi-Speed USB
controller based on the DesignWare HSOTG IP Core.
......
此差异已折叠。
......@@ -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;
}
此差异已折叠。
......@@ -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 @@ static void dwc2_complete_non_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
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,8 +1331,8 @@ 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,
&hsotg->periodic_sched_assigned);
list_move_tail(&qh->qh_list_entry,
&hsotg->periodic_sched_assigned);
/*
* If channel has been halted during giveback of urb
* then prevent any new scheduling.
......
此差异已折叠。
此差异已折叠。
......@@ -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 = &params_bcm2835 },
{ .compatible = "hisilicon,hi6220-usb", .data = &params_hi6220 },
{ .compatible = "rockchip,rk3066-usb", .data = &params_rk3066 },
{ .compatible = "lantiq,arx100-usb", .data = &params_ltq },
{ .compatible = "lantiq,xrx200-usb", .data = &params_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);
......
此差异已折叠。
此差异已折叠。
......@@ -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);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册