提交 19e36ad2 编写于 作者: L Linus Torvalds

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

Pull USB updates from Greg KH:
 "Here's the big pull request for USB and PHY drivers for 4.7-rc1

  Full details in the shortlog, but it's the normal major gadget driver
  updates, phy updates, new usbip code, as well as a bit of lots of
  other stuff.

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

* tag 'usb-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (164 commits)
  USB: serial: ti_usb_3410_5052: add MOXA UPORT 11x0 support
  USB: serial: fix minor-number allocation
  USB: serial: quatech2: fix use-after-free in probe error path
  USB: serial: mxuport: fix use-after-free in probe error path
  USB: serial: keyspan: fix debug and error messages
  USB: serial: keyspan: fix URB unlink
  USB: serial: keyspan: fix use-after-free in probe error path
  USB: serial: io_edgeport: fix memory leaks in probe error path
  USB: serial: io_edgeport: fix memory leaks in attach error path
  usb: Remove unnecessary space before operator ','.
  usb: Remove unnecessary space before open square bracket.
  USB: FHCI: avoid redundant condition
  usb: host: xhci-rcar: Avoid long wait in xhci_reset()
  usb/host/fotg210: remove dead code in create_sysfs_files
  usb: wusbcore: Do not initialise statics to 0.
  usb: wusbcore: Remove space before ',' and '(' .
  USB: serial: cp210x: clean up CRTSCTS flag code
  USB: serial: cp210x: get rid of magic numbers in CRTSCTS flag code
  USB: serial: cp210x: fix hardware flow-control disable
  USB: serial: option: add even more ZTE device ids
  ...
What: /sys/devices/platform/usbip-vudc.%d/dev_desc
Date: April 2016
KernelVersion: 4.6
Contact: Krzysztof Opasiak <k.opasiak@samsung.com>
Description:
This file allows to read device descriptor of
gadget driver which is currently bound to this
controller. It is possible to read this file
only if gadget driver is bound, otherwise error
is returned.
What: /sys/devices/platform/usbip-vudc.%d/usbip_status
Date: April 2016
KernelVersion: 4.6
Contact: Krzysztof Opasiak <k.opasiak@samsung.com>
Description:
Current status of the device.
Allowed values:
1 - Device is available and can be exported
2 - Device is currently exported
3 - Fatal error occurred during communication
with peer
What: /sys/devices/platform/usbip-vudc.%d/usbip_sockfd
Date: April 2016
KernelVersion: 4.6
Contact: Krzysztof Opasiak <k.opasiak@samsung.com>
Description:
This file allows to export usb device to
connection peer. It is done by writing to this
file socket fd (as a string for example "8")
associated with a connection to remote peer who
would like to use this device. It is possible to
close the connection by writing -1 instead of
socked fd.
Driver for Broadcom Northstar USB 2.0 PHY
Required properties:
- compatible: brcm,ns-usb2-phy
- reg: iomem address range of DMU (Device Management Unit)
- reg-names: "dmu", the only needed & supported reg right now
- clocks: USB PHY reference clock
- clock-names: "phy-ref-clk", the only needed & supported clock right now
To initialize USB 2.0 PHY driver needs to setup PLL correctly. To do this it
requires passing phandle to the USB PHY reference clock.
Example:
usb2-phy {
compatible = "brcm,ns-usb2-phy";
reg = <0x1800c000 0x1000>;
reg-names = "dmu";
#phy-cells = <0>;
clocks = <&genpll BCM_NSP_GENPLL_USB_PHY_REF_CLK>;
clock-names = "phy-ref-clk";
};
* Broadcom SATA3 PHY for STB * Broadcom SATA3 PHY
Required properties: Required properties:
- compatible: should be one or more of - compatible: should be one or more of
"brcm,bcm7425-sata-phy" "brcm,bcm7425-sata-phy"
"brcm,bcm7445-sata-phy" "brcm,bcm7445-sata-phy"
"brcm,iproc-ns2-sata-phy"
"brcm,phy-sata3" "brcm,phy-sata3"
- address-cells: should be 1 - address-cells: should be 1
- size-cells: should be 0 - size-cells: should be 0
- reg: register range for the PHY PCB interface - reg: register ranges for the PHY PCB interface
- reg-names: should be "phy" - reg-names: should be "phy" and "phy-ctrl"
The "phy-ctrl" registers are only required for
"brcm,iproc-ns2-sata-phy".
Sub-nodes: Sub-nodes:
Each port's PHY should be represented as a sub-node. Each port's PHY should be represented as a sub-node.
...@@ -16,12 +19,12 @@ Sub-nodes: ...@@ -16,12 +19,12 @@ Sub-nodes:
Sub-nodes required properties: Sub-nodes required properties:
- reg: the PHY number - reg: the PHY number
- phy-cells: generic PHY binding; must be 0 - phy-cells: generic PHY binding; must be 0
Optional:
- brcm,enable-ssc: use spread spectrum clocking (SSC) on this port
Sub-nodes optional properties:
- brcm,enable-ssc: use spread spectrum clocking (SSC) on this port
This property is not applicable for "brcm,iproc-ns2-sata-phy".
Example: Example:
sata-phy@f0458100 { sata-phy@f0458100 {
compatible = "brcm,bcm7445-sata-phy", "brcm,phy-sata3"; compatible = "brcm,bcm7445-sata-phy", "brcm,phy-sata3";
reg = <0xf0458100 0x1e00>, <0xf045804c 0x10>; reg = <0xf0458100 0x1e00>, <0xf045804c 0x10>;
......
...@@ -4,7 +4,9 @@ mt65xx USB3.0 PHY binding ...@@ -4,7 +4,9 @@ mt65xx USB3.0 PHY binding
This binding describes a usb3.0 phy for mt65xx platforms of Medaitek SoC. This binding describes a usb3.0 phy for mt65xx platforms of Medaitek SoC.
Required properties (controller (parent) node): Required properties (controller (parent) node):
- compatible : should be "mediatek,mt8173-u3phy" - compatible : should be one of
"mediatek,mt2701-u3phy"
"mediatek,mt8173-u3phy"
- reg : offset and length of register for phy, exclude port's - reg : offset and length of register for phy, exclude port's
register. register.
- clocks : a list of phandle + clock-specifier pairs, one for each - clocks : a list of phandle + clock-specifier pairs, one for each
......
...@@ -7,6 +7,12 @@ Required properties: ...@@ -7,6 +7,12 @@ Required properties:
- compatible: "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC. - compatible: "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC.
"renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC. "renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC.
"renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC. "renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC.
"renesas,rcar-gen2-usb-phy" for a generic R-Car Gen2 compatible device.
When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first
followed by the generic version.
- reg: offset and length of the register block. - reg: offset and length of the register block.
- #address-cells: number of address cells for the USB channel subnodes, must - #address-cells: number of address cells for the USB channel subnodes, must
be <1>. be <1>.
...@@ -34,7 +40,7 @@ the USB channel; see the selector meanings below: ...@@ -34,7 +40,7 @@ the USB channel; see the selector meanings below:
Example (Lager board): Example (Lager board):
usb-phy@e6590100 { usb-phy@e6590100 {
compatible = "renesas,usb-phy-r8a7790"; compatible = "renesas,usb-phy-r8a7790", "renesas,rcar-gen2-usb-phy";
reg = <0 0xe6590100 0 0x100>; reg = <0 0xe6590100 0 0x100>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
......
...@@ -6,6 +6,12 @@ This file provides information on what the device node for the R-Car generation ...@@ -6,6 +6,12 @@ This file provides information on what the device node for the R-Car generation
Required properties: Required properties:
- compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795 - compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795
SoC. SoC.
"renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device.
When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first
followed by the generic version.
- reg: offset and length of the partial USB 2.0 Host register block. - reg: offset and length of the partial USB 2.0 Host register block.
- clocks: clock phandle and specifier pair(s). - clocks: clock phandle and specifier pair(s).
- #phy-cells: see phy-bindings.txt in the same directory, must be <0>. - #phy-cells: see phy-bindings.txt in the same directory, must be <0>.
...@@ -15,18 +21,20 @@ To use a USB channel where USB 2.0 Host and HSUSB (USB 2.0 Peripheral) are ...@@ -15,18 +21,20 @@ To use a USB channel where USB 2.0 Host and HSUSB (USB 2.0 Peripheral) are
combined, the device tree node should set interrupt properties to use the combined, the device tree node should set interrupt properties to use the
channel as USB OTG: channel as USB OTG:
- interrupts: interrupt specifier for the PHY. - interrupts: interrupt specifier for the PHY.
- vbus-supply: Phandle to a regulator that provides power to the VBUS. This
regulator will be managed during the PHY power on/off sequence.
Example (R-Car H3): Example (R-Car H3):
usb-phy@ee080200 { usb-phy@ee080200 {
compatible = "renesas,usb2-phy-r8a7795"; compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy";
reg = <0 0xee080200 0 0x700>; reg = <0 0xee080200 0 0x700>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp7_clks R8A7795_CLK_EHCI0>; clocks = <&mstp7_clks R8A7795_CLK_EHCI0>;
}; };
usb-phy@ee0a0200 { usb-phy@ee0a0200 {
compatible = "renesas,usb2-phy-r8a7795"; compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy";
reg = <0 0xee0a0200 0 0x700>; reg = <0 0xee0a0200 0 0x700>;
clocks = <&mstp7_clks R8A7795_CLK_EHCI0>; clocks = <&mstp7_clks R8A7795_CLK_EHCI0>;
}; };
...@@ -2,9 +2,20 @@ Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY ...@@ -2,9 +2,20 @@ Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY
------------------------------------------------- -------------------------------------------------
Required properties: Required properties:
- compatible : should be "samsung,s5pv210-mipi-video-phy"; - compatible : should be one of the listed compatibles:
- "samsung,s5pv210-mipi-video-phy"
- "samsung,exynos5420-mipi-video-phy"
- "samsung,exynos5433-mipi-video-phy"
- #phy-cells : from the generic phy bindings, must be 1; - #phy-cells : from the generic phy bindings, must be 1;
- syscon - phandle to the PMU system controller;
In case of s5pv210 and exynos5420 compatible PHYs:
- syscon - phandle to the PMU system controller
In case of exynos5433 compatible PHY:
- samsung,pmu-syscon - phandle to the PMU system controller
- samsung,disp-sysreg - phandle to the DISP system registers controller
- samsung,cam0-sysreg - phandle to the CAM0 system registers controller
- samsung,cam1-sysreg - phandle to the CAM1 system registers controller
For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in
the PHY specifier identifies the PHY and its meaning is as follows: the PHY specifier identifies the PHY and its meaning is as follows:
...@@ -12,6 +23,9 @@ the PHY specifier identifies the PHY and its meaning is as follows: ...@@ -12,6 +23,9 @@ the PHY specifier identifies the PHY and its meaning is as follows:
1 - MIPI DSIM 0, 1 - MIPI DSIM 0,
2 - MIPI CSIS 1, 2 - MIPI CSIS 1,
3 - MIPI DSIM 1. 3 - MIPI DSIM 1.
"samsung,exynos5420-mipi-video-phy" and "samsung,exynos5433-mipi-video-phy"
supports additional fifth PHY:
4 - MIPI CSIS 2.
Samsung EXYNOS SoC series Display Port PHY Samsung EXYNOS SoC series Display Port PHY
------------------------------------------------- -------------------------------------------------
......
...@@ -14,7 +14,6 @@ Optional properties: ...@@ -14,7 +14,6 @@ Optional properties:
the second element is expected to be a handle to the USB3/SS PHY the second element is expected to be a handle to the USB3/SS PHY
- phys: from the *Generic PHY* bindings - phys: from the *Generic PHY* bindings
- phy-names: from the *Generic PHY* bindings - phy-names: from the *Generic PHY* bindings
- tx-fifo-resize: determines if the FIFO *has* to be reallocated.
- snps,usb3_lpm_capable: determines if platform is USB3 LPM capable - snps,usb3_lpm_capable: determines if platform is USB3 LPM capable
- snps,disable_scramble_quirk: true when SW should disable data scrambling. - snps,disable_scramble_quirk: true when SW should disable data scrambling.
Only really useful for FPGA builds. Only really useful for FPGA builds.
...@@ -38,6 +37,8 @@ Optional properties: ...@@ -38,6 +37,8 @@ Optional properties:
- snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy. - snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy.
- snps,dis_enblslpm_quirk: when set clears the enblslpm in GUSB2PHYCFG, - snps,dis_enblslpm_quirk: when set clears the enblslpm in GUSB2PHYCFG,
disabling the suspend signal to the PHY. disabling the suspend signal to the PHY.
- snps,dis_rxdet_inp3_quirk: when set core will disable receiver detection
in PHY P3 power state.
- snps,is-utmi-l1-suspend: true when DWC3 asserts output signal - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
utmi_l1_suspend_n, false when asserts utmi_sleep_n utmi_l1_suspend_n, false when asserts utmi_sleep_n
- snps,hird-threshold: HIRD threshold - snps,hird-threshold: HIRD threshold
...@@ -47,6 +48,8 @@ Optional properties: ...@@ -47,6 +48,8 @@ Optional properties:
register for post-silicon frame length adjustment when the register for post-silicon frame length adjustment when the
fladj_30mhz_sdbnd signal is invalid or incorrect. fladj_30mhz_sdbnd signal is invalid or incorrect.
- <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to be reallocated.
This is usually a subnode to DWC3 glue to which it is connected. This is usually a subnode to DWC3 glue to which it is connected.
dwc3@4a030000 { dwc3@4a030000 {
...@@ -54,5 +57,4 @@ dwc3@4a030000 { ...@@ -54,5 +57,4 @@ dwc3@4a030000 {
reg = <0x4a030000 0xcfff>; reg = <0x4a030000 0xcfff>;
interrupts = <0 92 4> interrupts = <0 92 4>
usb-phy = <&usb2_phy>, <&usb3,phy>; usb-phy = <&usb2_phy>, <&usb3,phy>;
tx-fifo-resize;
}; };
...@@ -59,7 +59,6 @@ Example device nodes: ...@@ -59,7 +59,6 @@ Example device nodes:
interrupts = <0 205 0x4>; interrupts = <0 205 0x4>;
phys = <&hs_phy>, <&ss_phy>; phys = <&hs_phy>, <&ss_phy>;
phy-names = "usb2-phy", "usb3-phy"; phy-names = "usb2-phy", "usb3-phy";
tx-fifo-resize;
dr_mode = "host"; dr_mode = "host";
}; };
}; };
......
...@@ -3,14 +3,17 @@ ...@@ -3,14 +3,17 @@
To show how to demo OTG HNP and SRP functions via sys input files To show how to demo OTG HNP and SRP functions via sys input files
with 2 Freescale i.MX6Q sabre SD boards. with 2 Freescale i.MX6Q sabre SD boards.
1.1 How to enable OTG FSM in menuconfig 1.1 How to enable OTG FSM
--------------------------------------- ---------------------------------------
Select CONFIG_USB_OTG_FSM, rebuild kernel Image and modules. 1.1.1 Select CONFIG_USB_OTG_FSM in menuconfig, rebuild kernel
If you want to check some internal variables for otg fsm, Image and modules. If you want to check some internal
mount debugfs, there are 2 files which can show otg fsm variables for otg fsm, mount debugfs, there are 2 files
variables and some controller registers value: which can show otg fsm variables and some controller registers value:
cat /sys/kernel/debug/ci_hdrc.0/otg cat /sys/kernel/debug/ci_hdrc.0/otg
cat /sys/kernel/debug/ci_hdrc.0/registers cat /sys/kernel/debug/ci_hdrc.0/registers
1.1.2 Add below entries in your dts file for your controller node
otg-rev = <0x0200>;
adp-disable;
1.2 Test operations 1.2 Test operations
------------------- -------------------
......
...@@ -15,6 +15,15 @@ config GENERIC_PHY ...@@ -15,6 +15,15 @@ config GENERIC_PHY
phy users can obtain reference to the PHY. All the users of this phy users can obtain reference to the PHY. All the users of this
framework should select this config. framework should select this config.
config PHY_BCM_NS_USB2
tristate "Broadcom Northstar USB 2.0 PHY Driver"
depends on ARCH_BCM_IPROC || COMPILE_TEST
depends on HAS_IOMEM && OF
select GENERIC_PHY
help
Enable this to support Broadcom USB 2.0 PHY connected to the USB
controller on Northstar family.
config PHY_BERLIN_USB config PHY_BERLIN_USB
tristate "Marvell Berlin USB PHY Driver" tristate "Marvell Berlin USB PHY Driver"
depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF
...@@ -113,14 +122,15 @@ config PHY_MIPHY365X ...@@ -113,14 +122,15 @@ config PHY_MIPHY365X
config PHY_RCAR_GEN2 config PHY_RCAR_GEN2
tristate "Renesas R-Car generation 2 USB PHY driver" tristate "Renesas R-Car generation 2 USB PHY driver"
depends on ARCH_SHMOBILE depends on ARCH_RENESAS
depends on GENERIC_PHY depends on GENERIC_PHY
help help
Support for USB PHY found on Renesas R-Car generation 2 SoCs. Support for USB PHY found on Renesas R-Car generation 2 SoCs.
config PHY_RCAR_GEN3_USB2 config PHY_RCAR_GEN3_USB2
tristate "Renesas R-Car generation 3 USB 2.0 PHY driver" tristate "Renesas R-Car generation 3 USB 2.0 PHY driver"
depends on OF && ARCH_SHMOBILE depends on ARCH_RENESAS
depends on EXTCON
select GENERIC_PHY select GENERIC_PHY
help help
Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs. Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs.
...@@ -218,9 +228,8 @@ config PHY_MT65XX_USB3 ...@@ -218,9 +228,8 @@ config PHY_MT65XX_USB3
depends on ARCH_MEDIATEK && OF depends on ARCH_MEDIATEK && OF
select GENERIC_PHY select GENERIC_PHY
help help
Say 'Y' here to add support for Mediatek USB3.0 PHY driver Say 'Y' here to add support for Mediatek USB3.0 PHY driver,
for mt65xx SoCs. it supports two usb2.0 ports and it supports multiple usb2.0 and usb3.0 ports.
one usb3.0 port.
config PHY_HI6220_USB config PHY_HI6220_USB
tristate "hi6220 USB PHY support" tristate "hi6220 USB PHY support"
...@@ -250,7 +259,8 @@ config PHY_SUN9I_USB ...@@ -250,7 +259,8 @@ config PHY_SUN9I_USB
tristate "Allwinner sun9i SoC USB PHY driver" tristate "Allwinner sun9i SoC USB PHY driver"
depends on ARCH_SUNXI && HAS_IOMEM && OF depends on ARCH_SUNXI && HAS_IOMEM && OF
depends on RESET_CONTROLLER depends on RESET_CONTROLLER
depends on USB_COMMON depends on USB_SUPPORT
select USB_COMMON
select GENERIC_PHY select GENERIC_PHY
help help
Enable this to support the transceiver that is part of Allwinner Enable this to support the transceiver that is part of Allwinner
...@@ -403,14 +413,15 @@ config PHY_TUSB1210 ...@@ -403,14 +413,15 @@ config PHY_TUSB1210
help help
Support for TI TUSB1210 USB ULPI PHY. Support for TI TUSB1210 USB ULPI PHY.
config PHY_BRCMSTB_SATA config PHY_BRCM_SATA
tristate "Broadcom STB SATA PHY driver" tristate "Broadcom SATA PHY driver"
depends on ARCH_BRCMSTB || BMIPS_GENERIC depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || COMPILE_TEST
depends on OF depends on OF
select GENERIC_PHY select GENERIC_PHY
default ARCH_BCM_IPROC
help help
Enable this to support the SATA3 PHY on 28nm or 40nm Broadcom STB SoCs. Enable this to support the Broadcom SATA PHY.
Likely useful only with CONFIG_SATA_BRCMSTB enabled. If unsure, say N.
config PHY_CYGNUS_PCIE config PHY_CYGNUS_PCIE
tristate "Broadcom Cygnus PCIe PHY driver" tristate "Broadcom Cygnus PCIe PHY driver"
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
# #
obj-$(CONFIG_GENERIC_PHY) += phy-core.o obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o
obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o
obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o
obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o
...@@ -49,7 +50,7 @@ obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o ...@@ -49,7 +50,7 @@ obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o
obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
......
/*
* Broadcom Northstar USB 2.0 PHY Driver
*
* Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.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 as
* published by the Free Software Foundation.
*
*/
#include <linux/bcma/bcma.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
struct bcm_ns_usb2 {
struct device *dev;
struct clk *ref_clk;
struct phy *phy;
void __iomem *dmu;
};
static int bcm_ns_usb2_phy_init(struct phy *phy)
{
struct bcm_ns_usb2 *usb2 = phy_get_drvdata(phy);
struct device *dev = usb2->dev;
void __iomem *dmu = usb2->dmu;
u32 ref_clk_rate, usb2ctl, usb_pll_ndiv, usb_pll_pdiv;
int err = 0;
err = clk_prepare_enable(usb2->ref_clk);
if (err < 0) {
dev_err(dev, "Failed to prepare ref clock: %d\n", err);
goto err_out;
}
ref_clk_rate = clk_get_rate(usb2->ref_clk);
if (!ref_clk_rate) {
dev_err(dev, "Failed to get ref clock rate\n");
err = -EINVAL;
goto err_clk_off;
}
usb2ctl = readl(dmu + BCMA_DMU_CRU_USB2_CONTROL);
if (usb2ctl & BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK) {
usb_pll_pdiv = usb2ctl;
usb_pll_pdiv &= BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK;
usb_pll_pdiv >>= BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_SHIFT;
} else {
usb_pll_pdiv = 1 << 3;
}
/* Calculate ndiv based on a solid 1920 MHz that is for USB2 PHY */
usb_pll_ndiv = (1920000000 * usb_pll_pdiv) / ref_clk_rate;
/* Unlock DMU PLL settings with some magic value */
writel(0x0000ea68, dmu + BCMA_DMU_CRU_CLKSET_KEY);
/* Write USB 2.0 PLL control setting */
usb2ctl &= ~BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_MASK;
usb2ctl |= usb_pll_ndiv << BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_SHIFT;
writel(usb2ctl, dmu + BCMA_DMU_CRU_USB2_CONTROL);
/* Lock DMU PLL settings */
writel(0x00000000, dmu + BCMA_DMU_CRU_CLKSET_KEY);
err_clk_off:
clk_disable_unprepare(usb2->ref_clk);
err_out:
return err;
}
static const struct phy_ops ops = {
.init = bcm_ns_usb2_phy_init,
.owner = THIS_MODULE,
};
static int bcm_ns_usb2_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct bcm_ns_usb2 *usb2;
struct resource *res;
struct phy_provider *phy_provider;
usb2 = devm_kzalloc(&pdev->dev, sizeof(*usb2), GFP_KERNEL);
if (!usb2)
return -ENOMEM;
usb2->dev = dev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmu");
usb2->dmu = devm_ioremap_resource(dev, res);
if (IS_ERR(usb2->dmu)) {
dev_err(dev, "Failed to map DMU regs\n");
return PTR_ERR(usb2->dmu);
}
usb2->ref_clk = devm_clk_get(dev, "phy-ref-clk");
if (IS_ERR(usb2->ref_clk)) {
dev_err(dev, "Clock not defined\n");
return PTR_ERR(usb2->ref_clk);
}
usb2->phy = devm_phy_create(dev, NULL, &ops);
if (IS_ERR(dev))
return PTR_ERR(dev);
phy_set_drvdata(usb2->phy, usb2);
platform_set_drvdata(pdev, usb2);
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 bcm_ns_usb2_id_table[] = {
{ .compatible = "brcm,ns-usb2-phy", },
{},
};
MODULE_DEVICE_TABLE(of, bcm_ns_usb2_id_table);
static struct platform_driver bcm_ns_usb2_driver = {
.probe = bcm_ns_usb2_probe,
.driver = {
.name = "bcm_ns_usb2",
.of_match_table = bcm_ns_usb2_id_table,
},
};
module_platform_driver(bcm_ns_usb2_driver);
MODULE_LICENSE("GPL v2");
/* /*
* Broadcom SATA3 AHCI Controller PHY Driver * Broadcom SATA3 AHCI Controller PHY Driver
* *
* Copyright © 2009-2015 Broadcom Corporation * Copyright (C) 2016 Broadcom
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -24,22 +25,26 @@ ...@@ -24,22 +25,26 @@
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#define SATA_MDIO_BANK_OFFSET 0x23c #define SATA_PCB_BANK_OFFSET 0x23c
#define SATA_MDIO_REG_OFFSET(ofs) ((ofs) * 4) #define SATA_PCB_REG_OFFSET(ofs) ((ofs) * 4)
#define MAX_PORTS 2 #define MAX_PORTS 2
/* Register offset between PHYs in PCB space */ /* Register offset between PHYs in PCB space */
#define SATA_MDIO_REG_28NM_SPACE_SIZE 0x1000 #define SATA_PCB_REG_28NM_SPACE_SIZE 0x1000
/* The older SATA PHY registers duplicated per port registers within the map, /* The older SATA PHY registers duplicated per port registers within the map,
* rather than having a separate map per port. * rather than having a separate map per port.
*/ */
#define SATA_MDIO_REG_40NM_SPACE_SIZE 0x10 #define SATA_PCB_REG_40NM_SPACE_SIZE 0x10
/* Register offset between PHYs in PHY control space */
#define SATA_PHY_CTRL_REG_28NM_SPACE_SIZE 0x8
enum brcm_sata_phy_version { enum brcm_sata_phy_version {
BRCM_SATA_PHY_28NM, BRCM_SATA_PHY_STB_28NM,
BRCM_SATA_PHY_40NM, BRCM_SATA_PHY_STB_40NM,
BRCM_SATA_PHY_IPROC_NS2,
}; };
struct brcm_sata_port { struct brcm_sata_port {
...@@ -52,15 +57,48 @@ struct brcm_sata_port { ...@@ -52,15 +57,48 @@ struct brcm_sata_port {
struct brcm_sata_phy { struct brcm_sata_phy {
struct device *dev; struct device *dev;
void __iomem *phy_base; void __iomem *phy_base;
void __iomem *ctrl_base;
enum brcm_sata_phy_version version; enum brcm_sata_phy_version version;
struct brcm_sata_port phys[MAX_PORTS]; struct brcm_sata_port phys[MAX_PORTS];
}; };
enum sata_mdio_phy_regs { enum sata_phy_regs {
PLL_REG_BANK_0 = 0x50, BLOCK0_REG_BANK = 0x000,
BLOCK0_XGXSSTATUS = 0x81,
BLOCK0_XGXSSTATUS_PLL_LOCK = BIT(12),
BLOCK0_SPARE = 0x8d,
BLOCK0_SPARE_OOB_CLK_SEL_MASK = 0x3,
BLOCK0_SPARE_OOB_CLK_SEL_REFBY2 = 0x1,
PLL_REG_BANK_0 = 0x050,
PLL_REG_BANK_0_PLLCONTROL_0 = 0x81, PLL_REG_BANK_0_PLLCONTROL_0 = 0x81,
PLL1_REG_BANK = 0x060,
PLL1_ACTRL2 = 0x82,
PLL1_ACTRL3 = 0x83,
PLL1_ACTRL4 = 0x84,
OOB_REG_BANK = 0x150,
OOB_CTRL1 = 0x80,
OOB_CTRL1_BURST_MAX_MASK = 0xf,
OOB_CTRL1_BURST_MAX_SHIFT = 12,
OOB_CTRL1_BURST_MIN_MASK = 0xf,
OOB_CTRL1_BURST_MIN_SHIFT = 8,
OOB_CTRL1_WAKE_IDLE_MAX_MASK = 0xf,
OOB_CTRL1_WAKE_IDLE_MAX_SHIFT = 4,
OOB_CTRL1_WAKE_IDLE_MIN_MASK = 0xf,
OOB_CTRL1_WAKE_IDLE_MIN_SHIFT = 0,
OOB_CTRL2 = 0x81,
OOB_CTRL2_SEL_ENA_SHIFT = 15,
OOB_CTRL2_SEL_ENA_RC_SHIFT = 14,
OOB_CTRL2_RESET_IDLE_MAX_MASK = 0x3f,
OOB_CTRL2_RESET_IDLE_MAX_SHIFT = 8,
OOB_CTRL2_BURST_CNT_MASK = 0x3,
OOB_CTRL2_BURST_CNT_SHIFT = 6,
OOB_CTRL2_RESET_IDLE_MIN_MASK = 0x3f,
OOB_CTRL2_RESET_IDLE_MIN_SHIFT = 0,
TXPMD_REG_BANK = 0x1a0, TXPMD_REG_BANK = 0x1a0,
TXPMD_CONTROL1 = 0x81, TXPMD_CONTROL1 = 0x81,
TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT(0), TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT(0),
...@@ -72,69 +110,183 @@ enum sata_mdio_phy_regs { ...@@ -72,69 +110,183 @@ enum sata_mdio_phy_regs {
TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff, TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff,
}; };
static inline void __iomem *brcm_sata_phy_base(struct brcm_sata_port *port) enum sata_phy_ctrl_regs {
PHY_CTRL_1 = 0x0,
PHY_CTRL_1_RESET = BIT(0),
};
static inline void __iomem *brcm_sata_pcb_base(struct brcm_sata_port *port)
{ {
struct brcm_sata_phy *priv = port->phy_priv; struct brcm_sata_phy *priv = port->phy_priv;
u32 offset = 0; u32 size = 0;
switch (priv->version) {
case BRCM_SATA_PHY_STB_28NM:
case BRCM_SATA_PHY_IPROC_NS2:
size = SATA_PCB_REG_28NM_SPACE_SIZE;
break;
case BRCM_SATA_PHY_STB_40NM:
size = SATA_PCB_REG_40NM_SPACE_SIZE;
break;
default:
dev_err(priv->dev, "invalid phy version\n");
break;
};
if (priv->version == BRCM_SATA_PHY_28NM) return priv->phy_base + (port->portnum * size);
offset = SATA_MDIO_REG_28NM_SPACE_SIZE; }
else if (priv->version == BRCM_SATA_PHY_40NM)
offset = SATA_MDIO_REG_40NM_SPACE_SIZE; static inline void __iomem *brcm_sata_ctrl_base(struct brcm_sata_port *port)
else {
struct brcm_sata_phy *priv = port->phy_priv;
u32 size = 0;
switch (priv->version) {
case BRCM_SATA_PHY_IPROC_NS2:
size = SATA_PHY_CTRL_REG_28NM_SPACE_SIZE;
break;
default:
dev_err(priv->dev, "invalid phy version\n"); dev_err(priv->dev, "invalid phy version\n");
break;
};
return priv->phy_base + (port->portnum * offset); return priv->ctrl_base + (port->portnum * size);
} }
static void brcm_sata_mdio_wr(void __iomem *addr, u32 bank, u32 ofs, static void brcm_sata_phy_wr(void __iomem *pcb_base, u32 bank,
u32 msk, u32 value) u32 ofs, u32 msk, u32 value)
{ {
u32 tmp; u32 tmp;
writel(bank, addr + SATA_MDIO_BANK_OFFSET); writel(bank, pcb_base + SATA_PCB_BANK_OFFSET);
tmp = readl(addr + SATA_MDIO_REG_OFFSET(ofs)); tmp = readl(pcb_base + SATA_PCB_REG_OFFSET(ofs));
tmp = (tmp & msk) | value; tmp = (tmp & msk) | value;
writel(tmp, addr + SATA_MDIO_REG_OFFSET(ofs)); writel(tmp, pcb_base + SATA_PCB_REG_OFFSET(ofs));
}
static u32 brcm_sata_phy_rd(void __iomem *pcb_base, u32 bank, u32 ofs)
{
writel(bank, pcb_base + SATA_PCB_BANK_OFFSET);
return readl(pcb_base + SATA_PCB_REG_OFFSET(ofs));
} }
/* These defaults were characterized by H/W group */ /* These defaults were characterized by H/W group */
#define FMIN_VAL_DEFAULT 0x3df #define STB_FMIN_VAL_DEFAULT 0x3df
#define FMAX_VAL_DEFAULT 0x3df #define STB_FMAX_VAL_DEFAULT 0x3df
#define FMAX_VAL_SSC 0x83 #define STB_FMAX_VAL_SSC 0x83
static void brcm_sata_cfg_ssc(struct brcm_sata_port *port) static int brcm_stb_sata_init(struct brcm_sata_port *port)
{ {
void __iomem *base = brcm_sata_phy_base(port); void __iomem *base = brcm_sata_pcb_base(port);
struct brcm_sata_phy *priv = port->phy_priv; struct brcm_sata_phy *priv = port->phy_priv;
u32 tmp; u32 tmp;
/* override the TX spread spectrum setting */ /* override the TX spread spectrum setting */
tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC; tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC;
brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp); brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp);
/* set fixed min freq */ /* set fixed min freq */
brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2, brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2,
~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK, ~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK,
FMIN_VAL_DEFAULT); STB_FMIN_VAL_DEFAULT);
/* set fixed max freq depending on SSC config */ /* set fixed max freq depending on SSC config */
if (port->ssc_en) { if (port->ssc_en) {
dev_info(priv->dev, "enabling SSC on port %d\n", port->portnum); dev_info(priv->dev, "enabling SSC on port%d\n", port->portnum);
tmp = FMAX_VAL_SSC; tmp = STB_FMAX_VAL_SSC;
} else { } else {
tmp = FMAX_VAL_DEFAULT; tmp = STB_FMAX_VAL_DEFAULT;
} }
brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3, brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3,
~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp); ~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp);
return 0;
}
/* NS2 SATA PLL1 defaults were characterized by H/W group */
#define NS2_PLL1_ACTRL2_MAGIC 0x1df8
#define NS2_PLL1_ACTRL3_MAGIC 0x2b00
#define NS2_PLL1_ACTRL4_MAGIC 0x8824
static int brcm_ns2_sata_init(struct brcm_sata_port *port)
{
int try;
unsigned int val;
void __iomem *base = brcm_sata_pcb_base(port);
void __iomem *ctrl_base = brcm_sata_ctrl_base(port);
struct device *dev = port->phy_priv->dev;
/* Configure OOB control */
val = 0x0;
val |= (0xc << OOB_CTRL1_BURST_MAX_SHIFT);
val |= (0x4 << OOB_CTRL1_BURST_MIN_SHIFT);
val |= (0x9 << OOB_CTRL1_WAKE_IDLE_MAX_SHIFT);
val |= (0x3 << OOB_CTRL1_WAKE_IDLE_MIN_SHIFT);
brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL1, 0x0, val);
val = 0x0;
val |= (0x1b << OOB_CTRL2_RESET_IDLE_MAX_SHIFT);
val |= (0x2 << OOB_CTRL2_BURST_CNT_SHIFT);
val |= (0x9 << OOB_CTRL2_RESET_IDLE_MIN_SHIFT);
brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL2, 0x0, val);
/* Configure PHY PLL register bank 1 */
val = NS2_PLL1_ACTRL2_MAGIC;
brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL2, 0x0, val);
val = NS2_PLL1_ACTRL3_MAGIC;
brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL3, 0x0, val);
val = NS2_PLL1_ACTRL4_MAGIC;
brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL4, 0x0, val);
/* Configure PHY BLOCK0 register bank */
/* Set oob_clk_sel to refclk/2 */
brcm_sata_phy_wr(base, BLOCK0_REG_BANK, BLOCK0_SPARE,
~BLOCK0_SPARE_OOB_CLK_SEL_MASK,
BLOCK0_SPARE_OOB_CLK_SEL_REFBY2);
/* Strobe PHY reset using PHY control register */
writel(PHY_CTRL_1_RESET, ctrl_base + PHY_CTRL_1);
mdelay(1);
writel(0x0, ctrl_base + PHY_CTRL_1);
mdelay(1);
/* Wait for PHY PLL lock by polling pll_lock bit */
try = 50;
while (try) {
val = brcm_sata_phy_rd(base, BLOCK0_REG_BANK,
BLOCK0_XGXSSTATUS);
if (val & BLOCK0_XGXSSTATUS_PLL_LOCK)
break;
msleep(20);
try--;
}
if (!try) {
/* PLL did not lock; give up */
dev_err(dev, "port%d PLL did not lock\n", port->portnum);
return -ETIMEDOUT;
}
dev_dbg(dev, "port%d initialized\n", port->portnum);
return 0;
} }
static int brcm_sata_phy_init(struct phy *phy) static int brcm_sata_phy_init(struct phy *phy)
{ {
int rc;
struct brcm_sata_port *port = phy_get_drvdata(phy); struct brcm_sata_port *port = phy_get_drvdata(phy);
brcm_sata_cfg_ssc(port); switch (port->phy_priv->version) {
case BRCM_SATA_PHY_STB_28NM:
case BRCM_SATA_PHY_STB_40NM:
rc = brcm_stb_sata_init(port);
break;
case BRCM_SATA_PHY_IPROC_NS2:
rc = brcm_ns2_sata_init(port);
break;
default:
rc = -ENODEV;
};
return 0; return 0;
} }
...@@ -146,9 +298,11 @@ static const struct phy_ops phy_ops = { ...@@ -146,9 +298,11 @@ static const struct phy_ops phy_ops = {
static const struct of_device_id brcm_sata_phy_of_match[] = { static const struct of_device_id brcm_sata_phy_of_match[] = {
{ .compatible = "brcm,bcm7445-sata-phy", { .compatible = "brcm,bcm7445-sata-phy",
.data = (void *)BRCM_SATA_PHY_28NM }, .data = (void *)BRCM_SATA_PHY_STB_28NM },
{ .compatible = "brcm,bcm7425-sata-phy", { .compatible = "brcm,bcm7425-sata-phy",
.data = (void *)BRCM_SATA_PHY_40NM }, .data = (void *)BRCM_SATA_PHY_STB_40NM },
{ .compatible = "brcm,iproc-ns2-sata-phy",
.data = (void *)BRCM_SATA_PHY_IPROC_NS2 },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match); MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match);
...@@ -181,7 +335,15 @@ static int brcm_sata_phy_probe(struct platform_device *pdev) ...@@ -181,7 +335,15 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
if (of_id) if (of_id)
priv->version = (enum brcm_sata_phy_version)of_id->data; priv->version = (enum brcm_sata_phy_version)of_id->data;
else else
priv->version = BRCM_SATA_PHY_28NM; priv->version = BRCM_SATA_PHY_STB_28NM;
if (priv->version == BRCM_SATA_PHY_IPROC_NS2) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"phy-ctrl");
priv->ctrl_base = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->ctrl_base))
return PTR_ERR(priv->ctrl_base);
}
for_each_available_child_of_node(dn, child) { for_each_available_child_of_node(dn, child) {
unsigned int id; unsigned int id;
...@@ -238,13 +400,13 @@ static struct platform_driver brcm_sata_phy_driver = { ...@@ -238,13 +400,13 @@ static struct platform_driver brcm_sata_phy_driver = {
.probe = brcm_sata_phy_probe, .probe = brcm_sata_phy_probe,
.driver = { .driver = {
.of_match_table = brcm_sata_phy_of_match, .of_match_table = brcm_sata_phy_of_match,
.name = "brcmstb-sata-phy", .name = "brcm-sata-phy",
} }
}; };
module_platform_driver(brcm_sata_phy_driver); module_platform_driver(brcm_sata_phy_driver);
MODULE_DESCRIPTION("Broadcom STB SATA PHY driver"); MODULE_DESCRIPTION("Broadcom SATA PHY driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marc Carino"); MODULE_AUTHOR("Marc Carino");
MODULE_AUTHOR("Brian Norris"); MODULE_AUTHOR("Brian Norris");
MODULE_ALIAS("platform:phy-brcmstb-sata"); MODULE_ALIAS("platform:phy-brcm-sata");
/* /*
* Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver * Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver
* *
* Copyright (C) 2013 Samsung Electronics Co., Ltd. * Copyright (C) 2013,2016 Samsung Electronics Co., Ltd.
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com> * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -13,96 +13,276 @@ ...@@ -13,96 +13,276 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mfd/syscon/exynos4-pmu.h> #include <linux/mfd/syscon/exynos4-pmu.h>
#include <linux/mfd/syscon/exynos5-pmu.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
/* MIPI_PHYn_CONTROL reg. offset (for base address from ioremap): n = 0..1 */
#define EXYNOS_MIPI_PHY_CONTROL(n) ((n) * 4)
enum exynos_mipi_phy_id { enum exynos_mipi_phy_id {
EXYNOS_MIPI_PHY_ID_NONE = -1,
EXYNOS_MIPI_PHY_ID_CSIS0, EXYNOS_MIPI_PHY_ID_CSIS0,
EXYNOS_MIPI_PHY_ID_DSIM0, EXYNOS_MIPI_PHY_ID_DSIM0,
EXYNOS_MIPI_PHY_ID_CSIS1, EXYNOS_MIPI_PHY_ID_CSIS1,
EXYNOS_MIPI_PHY_ID_DSIM1, EXYNOS_MIPI_PHY_ID_DSIM1,
EXYNOS_MIPI_PHY_ID_CSIS2,
EXYNOS_MIPI_PHYS_NUM EXYNOS_MIPI_PHYS_NUM
}; };
#define is_mipi_dsim_phy_id(id) \ enum exynos_mipi_phy_regmap_id {
((id) == EXYNOS_MIPI_PHY_ID_DSIM0 || (id) == EXYNOS_MIPI_PHY_ID_DSIM1) EXYNOS_MIPI_REGMAP_PMU,
EXYNOS_MIPI_REGMAP_DISP,
EXYNOS_MIPI_REGMAP_CAM0,
EXYNOS_MIPI_REGMAP_CAM1,
EXYNOS_MIPI_REGMAPS_NUM
};
struct mipi_phy_device_desc {
int num_phys;
int num_regmaps;
const char *regmap_names[EXYNOS_MIPI_REGMAPS_NUM];
struct exynos_mipi_phy_desc {
enum exynos_mipi_phy_id coupled_phy_id;
u32 enable_val;
unsigned int enable_reg;
enum exynos_mipi_phy_regmap_id enable_map;
u32 resetn_val;
unsigned int resetn_reg;
enum exynos_mipi_phy_regmap_id resetn_map;
} phys[EXYNOS_MIPI_PHYS_NUM];
};
static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
.num_regmaps = 1,
.regmap_names = {"syscon"},
.num_phys = 4,
.phys = {
{
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, {
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, {
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, {
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
.resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
},
},
};
static const struct mipi_phy_device_desc exynos5420_mipi_phy = {
.num_regmaps = 1,
.regmap_names = {"syscon"},
.num_phys = 5,
.phys = {
{
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, {
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_M_RESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, {
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, {
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_M_RESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
}, {
/* EXYNOS_MIPI_PHY_ID_CSIS2 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5420_MIPI_PHY2_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
.resetn_reg = EXYNOS5420_MIPI_PHY2_CONTROL,
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
},
},
};
#define EXYNOS5433_SYSREG_DISP_MIPI_PHY 0x100C
#define EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON 0x1014
#define EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON 0x1020
static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
.num_regmaps = 4,
.regmap_names = {
"samsung,pmu-syscon",
"samsung,disp-sysreg",
"samsung,cam0-sysreg",
"samsung,cam1-sysreg"
},
.num_phys = 5,
.phys = {
{
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(0),
.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
.resetn_map = EXYNOS_MIPI_REGMAP_CAM0,
}, {
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(0),
.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
.resetn_map = EXYNOS_MIPI_REGMAP_DISP,
}, {
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(1),
.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
.resetn_map = EXYNOS_MIPI_REGMAP_CAM0,
}, {
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(1),
.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
.resetn_map = EXYNOS_MIPI_REGMAP_DISP,
}, {
/* EXYNOS_MIPI_PHY_ID_CSIS2 */
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
.enable_val = EXYNOS5_PHY_ENABLE,
.enable_reg = EXYNOS5433_MIPI_PHY2_CONTROL,
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
.resetn_val = BIT(0),
.resetn_reg = EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON,
.resetn_map = EXYNOS_MIPI_REGMAP_CAM1,
},
},
};
struct exynos_mipi_video_phy { struct exynos_mipi_video_phy {
struct regmap *regmaps[EXYNOS_MIPI_REGMAPS_NUM];
int num_phys;
struct video_phy_desc { struct video_phy_desc {
struct phy *phy; struct phy *phy;
unsigned int index; unsigned int index;
const struct exynos_mipi_phy_desc *data;
} phys[EXYNOS_MIPI_PHYS_NUM]; } phys[EXYNOS_MIPI_PHYS_NUM];
spinlock_t slock; spinlock_t slock;
void __iomem *regs;
struct regmap *regmap;
}; };
static int __set_phy_state(struct exynos_mipi_video_phy *state, static inline int __is_running(const struct exynos_mipi_phy_desc *data,
enum exynos_mipi_phy_id id, unsigned int on) struct exynos_mipi_video_phy *state)
{ {
const unsigned int offset = EXYNOS4_MIPI_PHY_CONTROL(id / 2); u32 val;
void __iomem *addr;
u32 val, reset;
if (is_mipi_dsim_phy_id(id)) regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val);
reset = EXYNOS4_MIPI_PHY_MRESETN; return val & data->resetn_val;
else }
reset = EXYNOS4_MIPI_PHY_SRESETN;
static int __set_phy_state(const struct exynos_mipi_phy_desc *data,
struct exynos_mipi_video_phy *state, unsigned int on)
{
u32 val;
spin_lock(&state->slock); spin_lock(&state->slock);
if (!IS_ERR(state->regmap)) { /* disable in PMU sysreg */
regmap_read(state->regmap, offset, &val); if (!on && data->coupled_phy_id >= 0 &&
if (on) !__is_running(state->phys[data->coupled_phy_id].data, state)) {
val |= reset; regmap_read(state->regmaps[data->enable_map], data->enable_reg,
else &val);
val &= ~reset; val &= ~data->enable_val;
regmap_write(state->regmap, offset, val); regmap_write(state->regmaps[data->enable_map], data->enable_reg,
if (on) val);
val |= EXYNOS4_MIPI_PHY_ENABLE; }
else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
val &= ~EXYNOS4_MIPI_PHY_ENABLE; /* PHY reset */
regmap_write(state->regmap, offset, val); regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val);
} else { val = on ? (val | data->resetn_val) : (val & ~data->resetn_val);
addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2); regmap_write(state->regmaps[data->resetn_map], data->resetn_reg, val);
val = readl(addr); /* enable in PMU sysreg */
if (on) if (on) {
val |= reset; regmap_read(state->regmaps[data->enable_map], data->enable_reg,
else &val);
val &= ~reset; val |= data->enable_val;
writel(val, addr); regmap_write(state->regmaps[data->enable_map], data->enable_reg,
/* Clear ENABLE bit only if MRESETN, SRESETN bits are not set */ val);
if (on)
val |= EXYNOS4_MIPI_PHY_ENABLE;
else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
val &= ~EXYNOS4_MIPI_PHY_ENABLE;
writel(val, addr);
} }
spin_unlock(&state->slock); spin_unlock(&state->slock);
return 0; return 0;
} }
#define to_mipi_video_phy(desc) \ #define to_mipi_video_phy(desc) \
container_of((desc), struct exynos_mipi_video_phy, phys[(desc)->index]); container_of((desc), struct exynos_mipi_video_phy, phys[(desc)->index])
static int exynos_mipi_video_phy_power_on(struct phy *phy) static int exynos_mipi_video_phy_power_on(struct phy *phy)
{ {
struct video_phy_desc *phy_desc = phy_get_drvdata(phy); struct video_phy_desc *phy_desc = phy_get_drvdata(phy);
struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc); struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc);
return __set_phy_state(state, phy_desc->index, 1); return __set_phy_state(phy_desc->data, state, 1);
} }
static int exynos_mipi_video_phy_power_off(struct phy *phy) static int exynos_mipi_video_phy_power_off(struct phy *phy)
...@@ -110,7 +290,7 @@ static int exynos_mipi_video_phy_power_off(struct phy *phy) ...@@ -110,7 +290,7 @@ static int exynos_mipi_video_phy_power_off(struct phy *phy)
struct video_phy_desc *phy_desc = phy_get_drvdata(phy); struct video_phy_desc *phy_desc = phy_get_drvdata(phy);
struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc); struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc);
return __set_phy_state(state, phy_desc->index, 0); return __set_phy_state(phy_desc->data, state, 0);
} }
static struct phy *exynos_mipi_video_phy_xlate(struct device *dev, static struct phy *exynos_mipi_video_phy_xlate(struct device *dev,
...@@ -118,7 +298,7 @@ static struct phy *exynos_mipi_video_phy_xlate(struct device *dev, ...@@ -118,7 +298,7 @@ static struct phy *exynos_mipi_video_phy_xlate(struct device *dev,
{ {
struct exynos_mipi_video_phy *state = dev_get_drvdata(dev); struct exynos_mipi_video_phy *state = dev_get_drvdata(dev);
if (WARN_ON(args->args[0] >= EXYNOS_MIPI_PHYS_NUM)) if (WARN_ON(args->args[0] >= state->num_phys))
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
return state->phys[args->args[0]].phy; return state->phys[args->args[0]].phy;
...@@ -132,32 +312,33 @@ static const struct phy_ops exynos_mipi_video_phy_ops = { ...@@ -132,32 +312,33 @@ static const struct phy_ops exynos_mipi_video_phy_ops = {
static int exynos_mipi_video_phy_probe(struct platform_device *pdev) static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
{ {
const struct mipi_phy_device_desc *phy_dev;
struct exynos_mipi_video_phy *state; struct exynos_mipi_video_phy *state;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct phy_provider *phy_provider; struct phy_provider *phy_provider;
unsigned int i; unsigned int i;
phy_dev = of_device_get_match_data(dev);
if (!phy_dev)
return -ENODEV;
state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
if (!state) if (!state)
return -ENOMEM; return -ENOMEM;
state->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); for (i = 0; i < phy_dev->num_regmaps; i++) {
if (IS_ERR(state->regmap)) { state->regmaps[i] = syscon_regmap_lookup_by_phandle(np,
struct resource *res; phy_dev->regmap_names[i]);
if (IS_ERR(state->regmaps[i]))
dev_info(dev, "regmap lookup failed: %ld\n", return PTR_ERR(state->regmaps[i]);
PTR_ERR(state->regmap));
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
state->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(state->regs))
return PTR_ERR(state->regs);
} }
state->num_phys = phy_dev->num_phys;
spin_lock_init(&state->slock);
dev_set_drvdata(dev, state); dev_set_drvdata(dev, state);
spin_lock_init(&state->slock);
for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) { for (i = 0; i < state->num_phys; i++) {
struct phy *phy = devm_phy_create(dev, NULL, struct phy *phy = devm_phy_create(dev, NULL,
&exynos_mipi_video_phy_ops); &exynos_mipi_video_phy_ops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
...@@ -167,6 +348,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) ...@@ -167,6 +348,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
state->phys[i].phy = phy; state->phys[i].phy = phy;
state->phys[i].index = i; state->phys[i].index = i;
state->phys[i].data = &phy_dev->phys[i];
phy_set_drvdata(phy, &state->phys[i]); phy_set_drvdata(phy, &state->phys[i]);
} }
...@@ -177,8 +359,17 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) ...@@ -177,8 +359,17 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
} }
static const struct of_device_id exynos_mipi_video_phy_of_match[] = { static const struct of_device_id exynos_mipi_video_phy_of_match[] = {
{ .compatible = "samsung,s5pv210-mipi-video-phy" }, {
{ }, .compatible = "samsung,s5pv210-mipi-video-phy",
.data = &s5pv210_mipi_phy,
}, {
.compatible = "samsung,exynos5420-mipi-video-phy",
.data = &exynos5420_mipi_phy,
}, {
.compatible = "samsung,exynos5433-mipi-video-phy",
.data = &exynos5433_mipi_phy,
},
{ /* sentinel */ },
}; };
MODULE_DEVICE_TABLE(of, exynos_mipi_video_phy_of_match); MODULE_DEVICE_TABLE(of, exynos_mipi_video_phy_of_match);
......
...@@ -134,6 +134,11 @@ ...@@ -134,6 +134,11 @@
#define U3P_SR_COEF_DIVISOR 1000 #define U3P_SR_COEF_DIVISOR 1000
#define U3P_FM_DET_CYCLE_CNT 1024 #define U3P_FM_DET_CYCLE_CNT 1024
struct mt65xx_phy_pdata {
/* avoid RX sensitivity level degradation only for mt8173 */
bool avoid_rx_sen_degradation;
};
struct mt65xx_phy_instance { struct mt65xx_phy_instance {
struct phy *phy; struct phy *phy;
void __iomem *port_base; void __iomem *port_base;
...@@ -145,6 +150,7 @@ struct mt65xx_u3phy { ...@@ -145,6 +150,7 @@ struct mt65xx_u3phy {
struct device *dev; struct device *dev;
void __iomem *sif_base; /* include sif2, but exclude port's */ void __iomem *sif_base; /* include sif2, but exclude port's */
struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */ struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */
const struct mt65xx_phy_pdata *pdata;
struct mt65xx_phy_instance **phys; struct mt65xx_phy_instance **phys;
int nphys; int nphys;
}; };
...@@ -241,22 +247,26 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy, ...@@ -241,22 +247,26 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy,
tmp = readl(port_base + U3P_U2PHYACR4); tmp = readl(port_base + U3P_U2PHYACR4);
tmp &= ~P2C_U2_GPIO_CTR_MSK; tmp &= ~P2C_U2_GPIO_CTR_MSK;
writel(tmp, port_base + U3P_U2PHYACR4); writel(tmp, port_base + U3P_U2PHYACR4);
}
tmp = readl(port_base + U3P_USBPHYACR2); if (u3phy->pdata->avoid_rx_sen_degradation) {
tmp |= PA2_RG_SIF_U2PLL_FORCE_EN; if (!index) {
writel(tmp, port_base + U3P_USBPHYACR2); tmp = readl(port_base + U3P_USBPHYACR2);
tmp |= PA2_RG_SIF_U2PLL_FORCE_EN;
tmp = readl(port_base + U3D_U2PHYDCR0); writel(tmp, port_base + U3P_USBPHYACR2);
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
writel(tmp, port_base + U3D_U2PHYDCR0); tmp = readl(port_base + U3D_U2PHYDCR0);
} else { tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
tmp = readl(port_base + U3D_U2PHYDCR0); writel(tmp, port_base + U3D_U2PHYDCR0);
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON; } else {
writel(tmp, port_base + U3D_U2PHYDCR0); tmp = readl(port_base + U3D_U2PHYDCR0);
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
tmp = readl(port_base + U3P_U2PHYDTM0); writel(tmp, port_base + U3D_U2PHYDCR0);
tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
writel(tmp, port_base + U3P_U2PHYDTM0); tmp = readl(port_base + U3P_U2PHYDTM0);
tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
writel(tmp, port_base + U3P_U2PHYDTM0);
}
} }
tmp = readl(port_base + U3P_USBPHYACR6); tmp = readl(port_base + U3P_USBPHYACR6);
...@@ -318,7 +328,7 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy, ...@@ -318,7 +328,7 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD; tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD;
writel(tmp, u3phy->sif_base + U3P_XTALCTL3); writel(tmp, u3phy->sif_base + U3P_XTALCTL3);
/* [mt8173]switch 100uA current to SSUSB */ /* switch 100uA current to SSUSB */
tmp = readl(port_base + U3P_USBPHYACR5); tmp = readl(port_base + U3P_USBPHYACR5);
tmp |= PA5_RG_U2_HS_100U_U3_EN; tmp |= PA5_RG_U2_HS_100U_U3_EN;
writel(tmp, port_base + U3P_USBPHYACR5); writel(tmp, port_base + U3P_USBPHYACR5);
...@@ -335,7 +345,7 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy, ...@@ -335,7 +345,7 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(4); tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(4);
writel(tmp, port_base + U3P_USBPHYACR5); writel(tmp, port_base + U3P_USBPHYACR5);
if (index) { if (u3phy->pdata->avoid_rx_sen_degradation && index) {
tmp = readl(port_base + U3D_U2PHYDCR0); tmp = readl(port_base + U3D_U2PHYDCR0);
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON; tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
writel(tmp, port_base + U3D_U2PHYDCR0); writel(tmp, port_base + U3D_U2PHYDCR0);
...@@ -386,7 +396,9 @@ static void phy_instance_power_off(struct mt65xx_u3phy *u3phy, ...@@ -386,7 +396,9 @@ static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
tmp = readl(port_base + U3P_U3_PHYA_REG0); tmp = readl(port_base + U3P_U3_PHYA_REG0);
tmp &= ~P3A_RG_U3_VUSB10_ON; tmp &= ~P3A_RG_U3_VUSB10_ON;
writel(tmp, port_base + U3P_U3_PHYA_REG0); writel(tmp, port_base + U3P_U3_PHYA_REG0);
} else { }
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
tmp = readl(port_base + U3D_U2PHYDCR0); tmp = readl(port_base + U3D_U2PHYDCR0);
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON; tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
writel(tmp, port_base + U3D_U2PHYDCR0); writel(tmp, port_base + U3D_U2PHYDCR0);
...@@ -402,7 +414,7 @@ static void phy_instance_exit(struct mt65xx_u3phy *u3phy, ...@@ -402,7 +414,7 @@ static void phy_instance_exit(struct mt65xx_u3phy *u3phy,
u32 index = instance->index; u32 index = instance->index;
u32 tmp; u32 tmp;
if (index) { if (u3phy->pdata->avoid_rx_sen_degradation && index) {
tmp = readl(port_base + U3D_U2PHYDCR0); tmp = readl(port_base + U3D_U2PHYDCR0);
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON; tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
writel(tmp, port_base + U3D_U2PHYDCR0); writel(tmp, port_base + U3D_U2PHYDCR0);
...@@ -502,8 +514,24 @@ static struct phy_ops mt65xx_u3phy_ops = { ...@@ -502,8 +514,24 @@ static struct phy_ops mt65xx_u3phy_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static const struct mt65xx_phy_pdata mt2701_pdata = {
.avoid_rx_sen_degradation = false,
};
static const struct mt65xx_phy_pdata mt8173_pdata = {
.avoid_rx_sen_degradation = true,
};
static const struct of_device_id mt65xx_u3phy_id_table[] = {
{ .compatible = "mediatek,mt2701-u3phy", .data = &mt2701_pdata },
{ .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata },
{ },
};
MODULE_DEVICE_TABLE(of, mt65xx_u3phy_id_table);
static int mt65xx_u3phy_probe(struct platform_device *pdev) static int mt65xx_u3phy_probe(struct platform_device *pdev)
{ {
const struct of_device_id *match;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct device_node *child_np; struct device_node *child_np;
...@@ -513,10 +541,15 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev) ...@@ -513,10 +541,15 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
struct resource res; struct resource res;
int port, retval; int port, retval;
match = of_match_node(mt65xx_u3phy_id_table, pdev->dev.of_node);
if (!match)
return -EINVAL;
u3phy = devm_kzalloc(dev, sizeof(*u3phy), GFP_KERNEL); u3phy = devm_kzalloc(dev, sizeof(*u3phy), GFP_KERNEL);
if (!u3phy) if (!u3phy)
return -ENOMEM; return -ENOMEM;
u3phy->pdata = match->data;
u3phy->nphys = of_get_child_count(np); u3phy->nphys = of_get_child_count(np);
u3phy->phys = devm_kcalloc(dev, u3phy->nphys, u3phy->phys = devm_kcalloc(dev, u3phy->nphys,
sizeof(*u3phy->phys), GFP_KERNEL); sizeof(*u3phy->phys), GFP_KERNEL);
...@@ -587,12 +620,6 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev) ...@@ -587,12 +620,6 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
return retval; return retval;
} }
static const struct of_device_id mt65xx_u3phy_id_table[] = {
{ .compatible = "mediatek,mt8173-u3phy", },
{ },
};
MODULE_DEVICE_TABLE(of, mt65xx_u3phy_id_table);
static struct platform_driver mt65xx_u3phy_driver = { static struct platform_driver mt65xx_u3phy_driver = {
.probe = mt65xx_u3phy_probe, .probe = mt65xx_u3phy_probe,
.driver = { .driver = {
......
...@@ -195,6 +195,7 @@ static const struct of_device_id rcar_gen2_phy_match_table[] = { ...@@ -195,6 +195,7 @@ static const struct of_device_id rcar_gen2_phy_match_table[] = {
{ .compatible = "renesas,usb-phy-r8a7790" }, { .compatible = "renesas,usb-phy-r8a7790" },
{ .compatible = "renesas,usb-phy-r8a7791" }, { .compatible = "renesas,usb-phy-r8a7791" },
{ .compatible = "renesas,usb-phy-r8a7794" }, { .compatible = "renesas,usb-phy-r8a7794" },
{ .compatible = "renesas,rcar-gen2-usb-phy" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table); MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/extcon.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -19,6 +20,7 @@ ...@@ -19,6 +20,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
/******* USB2.0 Host registers (original offset is +0x200) *******/ /******* USB2.0 Host registers (original offset is +0x200) *******/
#define USB2_INT_ENABLE 0x000 #define USB2_INT_ENABLE 0x000
...@@ -74,20 +76,17 @@ ...@@ -74,20 +76,17 @@
#define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */
#define USB2_ADPCTRL_DRVVBUS BIT(4) #define USB2_ADPCTRL_DRVVBUS BIT(4)
struct rcar_gen3_data {
void __iomem *base;
struct clk *clk;
};
struct rcar_gen3_chan { struct rcar_gen3_chan {
struct rcar_gen3_data usb2; void __iomem *base;
struct extcon_dev *extcon;
struct phy *phy; struct phy *phy;
struct regulator *vbus;
bool has_otg; bool has_otg;
}; };
static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host)
{ {
void __iomem *usb2_base = ch->usb2.base; void __iomem *usb2_base = ch->base;
u32 val = readl(usb2_base + USB2_COMMCTRL); u32 val = readl(usb2_base + USB2_COMMCTRL);
dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, host); dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, host);
...@@ -100,7 +99,7 @@ static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) ...@@ -100,7 +99,7 @@ static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host)
static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm)
{ {
void __iomem *usb2_base = ch->usb2.base; void __iomem *usb2_base = ch->base;
u32 val = readl(usb2_base + USB2_LINECTRL1); u32 val = readl(usb2_base + USB2_LINECTRL1);
dev_vdbg(&ch->phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); dev_vdbg(&ch->phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm);
...@@ -114,7 +113,7 @@ static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) ...@@ -114,7 +113,7 @@ static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm)
static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus)
{ {
void __iomem *usb2_base = ch->usb2.base; void __iomem *usb2_base = ch->base;
u32 val = readl(usb2_base + USB2_ADPCTRL); u32 val = readl(usb2_base + USB2_ADPCTRL);
dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, vbus); dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, vbus);
...@@ -130,6 +129,9 @@ static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch) ...@@ -130,6 +129,9 @@ static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch)
rcar_gen3_set_linectrl(ch, 1, 1); rcar_gen3_set_linectrl(ch, 1, 1);
rcar_gen3_set_host_mode(ch, 1); rcar_gen3_set_host_mode(ch, 1);
rcar_gen3_enable_vbus_ctrl(ch, 1); rcar_gen3_enable_vbus_ctrl(ch, 1);
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true);
extcon_set_cable_state_(ch->extcon, EXTCON_USB, false);
} }
static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
...@@ -137,17 +139,20 @@ static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) ...@@ -137,17 +139,20 @@ static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
rcar_gen3_set_linectrl(ch, 0, 1); rcar_gen3_set_linectrl(ch, 0, 1);
rcar_gen3_set_host_mode(ch, 0); rcar_gen3_set_host_mode(ch, 0);
rcar_gen3_enable_vbus_ctrl(ch, 0); rcar_gen3_enable_vbus_ctrl(ch, 0);
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false);
extcon_set_cable_state_(ch->extcon, EXTCON_USB, true);
} }
static bool rcar_gen3_check_vbus(struct rcar_gen3_chan *ch) static bool rcar_gen3_check_vbus(struct rcar_gen3_chan *ch)
{ {
return !!(readl(ch->usb2.base + USB2_ADPCTRL) & return !!(readl(ch->base + USB2_ADPCTRL) &
USB2_ADPCTRL_OTGSESSVLD); USB2_ADPCTRL_OTGSESSVLD);
} }
static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
{ {
return !!(readl(ch->usb2.base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG);
} }
static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch)
...@@ -166,7 +171,7 @@ static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) ...@@ -166,7 +171,7 @@ static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch)
static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
{ {
void __iomem *usb2_base = ch->usb2.base; void __iomem *usb2_base = ch->base;
u32 val; u32 val;
val = readl(usb2_base + USB2_VBCTRL); val = readl(usb2_base + USB2_VBCTRL);
...@@ -187,7 +192,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) ...@@ -187,7 +192,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
static int rcar_gen3_phy_usb2_init(struct phy *p) static int rcar_gen3_phy_usb2_init(struct phy *p)
{ {
struct rcar_gen3_chan *channel = phy_get_drvdata(p); struct rcar_gen3_chan *channel = phy_get_drvdata(p);
void __iomem *usb2_base = channel->usb2.base; void __iomem *usb2_base = channel->base;
/* Initialize USB2 part */ /* Initialize USB2 part */
writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE); writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE);
...@@ -205,7 +210,7 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) ...@@ -205,7 +210,7 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
{ {
struct rcar_gen3_chan *channel = phy_get_drvdata(p); struct rcar_gen3_chan *channel = phy_get_drvdata(p);
writel(0, channel->usb2.base + USB2_INT_ENABLE); writel(0, channel->base + USB2_INT_ENABLE);
return 0; return 0;
} }
...@@ -213,8 +218,15 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) ...@@ -213,8 +218,15 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
static int rcar_gen3_phy_usb2_power_on(struct phy *p) static int rcar_gen3_phy_usb2_power_on(struct phy *p)
{ {
struct rcar_gen3_chan *channel = phy_get_drvdata(p); struct rcar_gen3_chan *channel = phy_get_drvdata(p);
void __iomem *usb2_base = channel->usb2.base; void __iomem *usb2_base = channel->base;
u32 val; u32 val;
int ret;
if (channel->vbus) {
ret = regulator_enable(channel->vbus);
if (ret)
return ret;
}
val = readl(usb2_base + USB2_USBCTR); val = readl(usb2_base + USB2_USBCTR);
val |= USB2_USBCTR_PLL_RST; val |= USB2_USBCTR_PLL_RST;
...@@ -225,17 +237,29 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) ...@@ -225,17 +237,29 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
return 0; return 0;
} }
static int rcar_gen3_phy_usb2_power_off(struct phy *p)
{
struct rcar_gen3_chan *channel = phy_get_drvdata(p);
int ret = 0;
if (channel->vbus)
ret = regulator_disable(channel->vbus);
return ret;
}
static struct phy_ops rcar_gen3_phy_usb2_ops = { static struct phy_ops rcar_gen3_phy_usb2_ops = {
.init = rcar_gen3_phy_usb2_init, .init = rcar_gen3_phy_usb2_init,
.exit = rcar_gen3_phy_usb2_exit, .exit = rcar_gen3_phy_usb2_exit,
.power_on = rcar_gen3_phy_usb2_power_on, .power_on = rcar_gen3_phy_usb2_power_on,
.power_off = rcar_gen3_phy_usb2_power_off,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
{ {
struct rcar_gen3_chan *ch = _ch; struct rcar_gen3_chan *ch = _ch;
void __iomem *usb2_base = ch->usb2.base; void __iomem *usb2_base = ch->base;
u32 status = readl(usb2_base + USB2_OBINTSTA); u32 status = readl(usb2_base + USB2_OBINTSTA);
irqreturn_t ret = IRQ_NONE; irqreturn_t ret = IRQ_NONE;
...@@ -251,10 +275,17 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) ...@@ -251,10 +275,17 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
{ .compatible = "renesas,usb2-phy-r8a7795" }, { .compatible = "renesas,usb2-phy-r8a7795" },
{ .compatible = "renesas,rcar-gen3-usb2-phy" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table); MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table);
static const unsigned int rcar_gen3_phy_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
EXTCON_NONE,
};
static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -273,18 +304,30 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) ...@@ -273,18 +304,30 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
channel->usb2.base = devm_ioremap_resource(dev, res); channel->base = devm_ioremap_resource(dev, res);
if (IS_ERR(channel->usb2.base)) if (IS_ERR(channel->base))
return PTR_ERR(channel->usb2.base); return PTR_ERR(channel->base);
/* call request_irq for OTG */ /* call request_irq for OTG */
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq >= 0) { if (irq >= 0) {
int ret;
irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq, irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
IRQF_SHARED, dev_name(dev), channel); IRQF_SHARED, dev_name(dev), channel);
if (irq < 0) if (irq < 0)
dev_err(dev, "No irq handler (%d)\n", irq); dev_err(dev, "No irq handler (%d)\n", irq);
channel->has_otg = true; channel->has_otg = true;
channel->extcon = devm_extcon_dev_allocate(dev,
rcar_gen3_phy_cable);
if (IS_ERR(channel->extcon))
return PTR_ERR(channel->extcon);
ret = devm_extcon_dev_register(dev, channel->extcon);
if (ret < 0) {
dev_err(dev, "Failed to register extcon\n");
return ret;
}
} }
/* devm_phy_create() will call pm_runtime_enable(dev); */ /* devm_phy_create() will call pm_runtime_enable(dev); */
...@@ -294,6 +337,13 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) ...@@ -294,6 +337,13 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
return PTR_ERR(channel->phy); return PTR_ERR(channel->phy);
} }
channel->vbus = devm_regulator_get_optional(dev, "vbus");
if (IS_ERR(channel->vbus)) {
if (PTR_ERR(channel->vbus) == -EPROBE_DEFER)
return PTR_ERR(channel->vbus);
channel->vbus = NULL;
}
phy_set_drvdata(channel->phy, channel); phy_set_drvdata(channel->phy, channel);
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
......
...@@ -216,7 +216,7 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base, ...@@ -216,7 +216,7 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
init.parent_names = &clk_name; init.parent_names = &clk_name;
init.num_parents = 1; init.num_parents = 1;
} else { } else {
init.flags = CLK_IS_ROOT; init.flags = 0;
init.parent_names = NULL; init.parent_names = NULL;
init.num_parents = 0; init.num_parents = 0;
} }
......
...@@ -31,8 +31,6 @@ if USB_SUPPORT ...@@ -31,8 +31,6 @@ if USB_SUPPORT
config USB_COMMON config USB_COMMON
tristate tristate
default y
depends on USB || USB_GADGET
config USB_ARCH_HAS_HCD config USB_ARCH_HAS_HCD
def_bool y def_bool y
...@@ -41,6 +39,7 @@ config USB_ARCH_HAS_HCD ...@@ -41,6 +39,7 @@ config USB_ARCH_HAS_HCD
config USB config USB
tristate "Support for Host-side USB" tristate "Support for Host-side USB"
depends on USB_ARCH_HAS_HCD depends on USB_ARCH_HAS_HCD
select USB_COMMON
select NLS # for UTF-8 strings select NLS # for UTF-8 strings
---help--- ---help---
Universal Serial Bus (USB) is a specification for a serial bus Universal Serial Bus (USB) is a specification for a serial bus
......
...@@ -173,10 +173,10 @@ struct uea_softc { ...@@ -173,10 +173,10 @@ struct uea_softc {
const struct firmware *dsp_firm; const struct firmware *dsp_firm;
struct urb *urb_int; struct urb *urb_int;
void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *); void (*dispatch_cmv)(struct uea_softc *, struct intr_pkt *);
void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *); void (*schedule_load_page)(struct uea_softc *, struct intr_pkt *);
int (*stat) (struct uea_softc *); int (*stat)(struct uea_softc *);
int (*send_cmvs) (struct uea_softc *); int (*send_cmvs)(struct uea_softc *);
/* keep in sync with eaglectl */ /* keep in sync with eaglectl */
struct uea_stats { struct uea_stats {
...@@ -2454,7 +2454,7 @@ UEA_ATTR(firmid, 0); ...@@ -2454,7 +2454,7 @@ UEA_ATTR(firmid, 0);
/* Retrieve the device End System Identifier (MAC) */ /* Retrieve the device End System Identifier (MAC) */
static int uea_getesi(struct uea_softc *sc, u_char * esi) static int uea_getesi(struct uea_softc *sc, u_char *esi)
{ {
unsigned char mac_str[2 * ETH_ALEN + 1]; unsigned char mac_str[2 * ETH_ALEN + 1];
int i; int i;
......
...@@ -292,10 +292,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) ...@@ -292,10 +292,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM) if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
data->supports_runtime_pm = true; data->supports_runtime_pm = true;
ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (ret)
goto err_clk;
ret = imx_usbmisc_init(data->usbmisc_data); ret = imx_usbmisc_init(data->usbmisc_data);
if (ret) { if (ret) {
dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret); dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret);
......
...@@ -61,8 +61,6 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol) ...@@ -61,8 +61,6 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
return 0; return 0;
} }
static int state_changed;
/* Called when leaving a state. Do state clean up jobs here */ /* Called when leaving a state. Do state clean up jobs here */
static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
{ {
...@@ -208,7 +206,6 @@ static void otg_start_hnp_polling(struct otg_fsm *fsm) ...@@ -208,7 +206,6 @@ static void otg_start_hnp_polling(struct otg_fsm *fsm)
/* Called when entering a state */ /* Called when entering a state */
static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
{ {
state_changed = 1;
if (fsm->otg->state == new_state) if (fsm->otg->state == new_state)
return 0; return 0;
VDBG("Set state: %s\n", usb_otg_state_string(new_state)); VDBG("Set state: %s\n", usb_otg_state_string(new_state));
...@@ -324,6 +321,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) ...@@ -324,6 +321,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
} }
fsm->otg->state = new_state; fsm->otg->state = new_state;
fsm->state_changed = 1;
return 0; return 0;
} }
...@@ -335,7 +333,7 @@ int otg_statemachine(struct otg_fsm *fsm) ...@@ -335,7 +333,7 @@ int otg_statemachine(struct otg_fsm *fsm)
mutex_lock(&fsm->lock); mutex_lock(&fsm->lock);
state = fsm->otg->state; state = fsm->otg->state;
state_changed = 0; fsm->state_changed = 0;
/* State machine state change judgement */ /* State machine state change judgement */
switch (state) { switch (state) {
...@@ -448,7 +446,7 @@ int otg_statemachine(struct otg_fsm *fsm) ...@@ -448,7 +446,7 @@ int otg_statemachine(struct otg_fsm *fsm)
} }
mutex_unlock(&fsm->lock); mutex_unlock(&fsm->lock);
VDBG("quit statemachine, changed = %d\n", state_changed); VDBG("quit statemachine, changed = %d\n", fsm->state_changed);
return state_changed; return fsm->state_changed;
} }
EXPORT_SYMBOL_GPL(otg_statemachine); EXPORT_SYMBOL_GPL(otg_statemachine);
...@@ -122,6 +122,9 @@ void *hcd_buffer_alloc( ...@@ -122,6 +122,9 @@ void *hcd_buffer_alloc(
struct usb_hcd *hcd = bus_to_hcd(bus); struct usb_hcd *hcd = bus_to_hcd(bus);
int i; int i;
if (size == 0)
return NULL;
/* some USB hosts just use PIO */ /* some USB hosts just use PIO */
if (!IS_ENABLED(CONFIG_HAS_DMA) || if (!IS_ENABLED(CONFIG_HAS_DMA) ||
(!bus->controller->dma_mask && (!bus->controller->dma_mask &&
......
...@@ -216,7 +216,7 @@ static void usbdev_vm_close(struct vm_area_struct *vma) ...@@ -216,7 +216,7 @@ static void usbdev_vm_close(struct vm_area_struct *vma)
dec_usb_memory_use_count(usbm, &usbm->vma_use_count); dec_usb_memory_use_count(usbm, &usbm->vma_use_count);
} }
struct vm_operations_struct usbdev_vm_ops = { static struct vm_operations_struct usbdev_vm_ops = {
.open = usbdev_vm_open, .open = usbdev_vm_open,
.close = usbdev_vm_close .close = usbdev_vm_close
}; };
...@@ -1316,10 +1316,11 @@ static int proc_getdriver(struct usb_dev_state *ps, void __user *arg) ...@@ -1316,10 +1316,11 @@ static int proc_getdriver(struct usb_dev_state *ps, void __user *arg)
static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg) static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)
{ {
struct usbdevfs_connectinfo ci = { struct usbdevfs_connectinfo ci;
.devnum = ps->dev->devnum,
.slow = ps->dev->speed == USB_SPEED_LOW memset(&ci, 0, sizeof(ci));
}; ci.devnum = ps->dev->devnum;
ci.slow = ps->dev->speed == USB_SPEED_LOW;
if (copy_to_user(arg, &ci, sizeof(ci))) if (copy_to_user(arg, &ci, sizeof(ci)))
return -EFAULT; return -EFAULT;
......
...@@ -284,7 +284,7 @@ static int usb_probe_interface(struct device *dev) ...@@ -284,7 +284,7 @@ static int usb_probe_interface(struct device *dev)
struct usb_device *udev = interface_to_usbdev(intf); struct usb_device *udev = interface_to_usbdev(intf);
const struct usb_device_id *id; const struct usb_device_id *id;
int error = -ENODEV; int error = -ENODEV;
int lpm_disable_error; int lpm_disable_error = -ENODEV;
dev_dbg(dev, "%s\n", __func__); dev_dbg(dev, "%s\n", __func__);
...@@ -336,12 +336,14 @@ static int usb_probe_interface(struct device *dev) ...@@ -336,12 +336,14 @@ static int usb_probe_interface(struct device *dev)
* setting during probe, that should also be fine. usb_set_interface() * setting during probe, that should also be fine. usb_set_interface()
* will attempt to disable LPM, and fail if it can't disable it. * will attempt to disable LPM, and fail if it can't disable it.
*/ */
lpm_disable_error = usb_unlocked_disable_lpm(udev); if (driver->disable_hub_initiated_lpm) {
if (lpm_disable_error && driver->disable_hub_initiated_lpm) { lpm_disable_error = usb_unlocked_disable_lpm(udev);
dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.", if (lpm_disable_error) {
__func__, driver->name); dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.",
error = lpm_disable_error; __func__, driver->name);
goto err; error = lpm_disable_error;
goto err;
}
} }
/* Carry out a deferred switch to altsetting 0 */ /* Carry out a deferred switch to altsetting 0 */
...@@ -391,7 +393,8 @@ static int usb_unbind_interface(struct device *dev) ...@@ -391,7 +393,8 @@ static int usb_unbind_interface(struct device *dev)
struct usb_interface *intf = to_usb_interface(dev); struct usb_interface *intf = to_usb_interface(dev);
struct usb_host_endpoint *ep, **eps = NULL; struct usb_host_endpoint *ep, **eps = NULL;
struct usb_device *udev; struct usb_device *udev;
int i, j, error, r, lpm_disable_error; int i, j, error, r;
int lpm_disable_error = -ENODEV;
intf->condition = USB_INTERFACE_UNBINDING; intf->condition = USB_INTERFACE_UNBINDING;
...@@ -399,12 +402,13 @@ static int usb_unbind_interface(struct device *dev) ...@@ -399,12 +402,13 @@ static int usb_unbind_interface(struct device *dev)
udev = interface_to_usbdev(intf); udev = interface_to_usbdev(intf);
error = usb_autoresume_device(udev); error = usb_autoresume_device(udev);
/* Hub-initiated LPM policy may change, so attempt to disable LPM until /* If hub-initiated LPM policy may change, attempt to disable LPM until
* the driver is unbound. If LPM isn't disabled, that's fine because it * the driver is unbound. If LPM isn't disabled, that's fine because it
* wouldn't be enabled unless all the bound interfaces supported * wouldn't be enabled unless all the bound interfaces supported
* hub-initiated LPM. * hub-initiated LPM.
*/ */
lpm_disable_error = usb_unlocked_disable_lpm(udev); if (driver->disable_hub_initiated_lpm)
lpm_disable_error = usb_unlocked_disable_lpm(udev);
/* /*
* Terminate all URBs for this interface unless the driver * Terminate all URBs for this interface unless the driver
...@@ -505,7 +509,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, ...@@ -505,7 +509,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
struct device *dev; struct device *dev;
struct usb_device *udev; struct usb_device *udev;
int retval = 0; int retval = 0;
int lpm_disable_error; int lpm_disable_error = -ENODEV;
if (!iface) if (!iface)
return -ENODEV; return -ENODEV;
...@@ -526,12 +530,14 @@ int usb_driver_claim_interface(struct usb_driver *driver, ...@@ -526,12 +530,14 @@ int usb_driver_claim_interface(struct usb_driver *driver,
iface->condition = USB_INTERFACE_BOUND; iface->condition = USB_INTERFACE_BOUND;
/* Disable LPM until this driver is bound. */ /* See the comment about disabling LPM in usb_probe_interface(). */
lpm_disable_error = usb_unlocked_disable_lpm(udev); if (driver->disable_hub_initiated_lpm) {
if (lpm_disable_error && driver->disable_hub_initiated_lpm) { lpm_disable_error = usb_unlocked_disable_lpm(udev);
dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.", if (lpm_disable_error) {
__func__, driver->name); dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.",
return -ENOMEM; __func__, driver->name);
return -ENOMEM;
}
} }
/* Claimed interfaces are initially inactive (suspended) and /* Claimed interfaces are initially inactive (suspended) and
......
...@@ -994,7 +994,7 @@ static void usb_bus_init (struct usb_bus *bus) ...@@ -994,7 +994,7 @@ static void usb_bus_init (struct usb_bus *bus)
bus->bandwidth_allocated = 0; bus->bandwidth_allocated = 0;
bus->bandwidth_int_reqs = 0; bus->bandwidth_int_reqs = 0;
bus->bandwidth_isoc_reqs = 0; bus->bandwidth_isoc_reqs = 0;
mutex_init(&bus->usb_address0_mutex); mutex_init(&bus->devnum_next_mutex);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1118,6 +1118,7 @@ static int register_root_hub(struct usb_hcd *hcd) ...@@ -1118,6 +1118,7 @@ static int register_root_hub(struct usb_hcd *hcd)
/* Did the HC die before the root hub was registered? */ /* Did the HC die before the root hub was registered? */
if (HCD_DEAD(hcd)) if (HCD_DEAD(hcd))
usb_hc_died (hcd); /* This time clean up */ usb_hc_died (hcd); /* This time clean up */
usb_dev->dev.of_node = parent_dev->of_node;
} }
mutex_unlock(&usb_bus_idr_lock); mutex_unlock(&usb_bus_idr_lock);
...@@ -2521,6 +2522,14 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, ...@@ -2521,6 +2522,14 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
return NULL; return NULL;
} }
if (primary_hcd == NULL) { if (primary_hcd == NULL) {
hcd->address0_mutex = kmalloc(sizeof(*hcd->address0_mutex),
GFP_KERNEL);
if (!hcd->address0_mutex) {
kfree(hcd);
dev_dbg(dev, "hcd address0 mutex alloc failed\n");
return NULL;
}
mutex_init(hcd->address0_mutex);
hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex), hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),
GFP_KERNEL); GFP_KERNEL);
if (!hcd->bandwidth_mutex) { if (!hcd->bandwidth_mutex) {
...@@ -2532,6 +2541,7 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, ...@@ -2532,6 +2541,7 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
dev_set_drvdata(dev, hcd); dev_set_drvdata(dev, hcd);
} else { } else {
mutex_lock(&usb_port_peer_mutex); mutex_lock(&usb_port_peer_mutex);
hcd->address0_mutex = primary_hcd->address0_mutex;
hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex; hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
hcd->primary_hcd = primary_hcd; hcd->primary_hcd = primary_hcd;
primary_hcd->primary_hcd = primary_hcd; primary_hcd->primary_hcd = primary_hcd;
...@@ -2598,8 +2608,10 @@ static void hcd_release(struct kref *kref) ...@@ -2598,8 +2608,10 @@ static void hcd_release(struct kref *kref)
struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
mutex_lock(&usb_port_peer_mutex); mutex_lock(&usb_port_peer_mutex);
if (usb_hcd_is_primary_hcd(hcd)) if (usb_hcd_is_primary_hcd(hcd)) {
kfree(hcd->address0_mutex);
kfree(hcd->bandwidth_mutex); kfree(hcd->bandwidth_mutex);
}
if (hcd->shared_hcd) { if (hcd->shared_hcd) {
struct usb_hcd *peer = hcd->shared_hcd; struct usb_hcd *peer = hcd->shared_hcd;
......
...@@ -104,6 +104,8 @@ static int usb_reset_and_verify_device(struct usb_device *udev); ...@@ -104,6 +104,8 @@ static int usb_reset_and_verify_device(struct usb_device *udev);
static inline char *portspeed(struct usb_hub *hub, int portstatus) static inline char *portspeed(struct usb_hub *hub, int portstatus)
{ {
if (hub_is_superspeedplus(hub->hdev))
return "10.0 Gb/s";
if (hub_is_superspeed(hub->hdev)) if (hub_is_superspeed(hub->hdev))
return "5.0 Gb/s"; return "5.0 Gb/s";
if (portstatus & USB_PORT_STAT_HIGH_SPEED) if (portstatus & USB_PORT_STAT_HIGH_SPEED)
...@@ -2080,7 +2082,7 @@ static void choose_devnum(struct usb_device *udev) ...@@ -2080,7 +2082,7 @@ static void choose_devnum(struct usb_device *udev)
struct usb_bus *bus = udev->bus; struct usb_bus *bus = udev->bus;
/* be safe when more hub events are proceed in parallel */ /* be safe when more hub events are proceed in parallel */
mutex_lock(&bus->usb_address0_mutex); mutex_lock(&bus->devnum_next_mutex);
if (udev->wusb) { if (udev->wusb) {
devnum = udev->portnum + 1; devnum = udev->portnum + 1;
BUG_ON(test_bit(devnum, bus->devmap.devicemap)); BUG_ON(test_bit(devnum, bus->devmap.devicemap));
...@@ -2098,7 +2100,7 @@ static void choose_devnum(struct usb_device *udev) ...@@ -2098,7 +2100,7 @@ static void choose_devnum(struct usb_device *udev)
set_bit(devnum, bus->devmap.devicemap); set_bit(devnum, bus->devmap.devicemap);
udev->devnum = devnum; udev->devnum = devnum;
} }
mutex_unlock(&bus->usb_address0_mutex); mutex_unlock(&bus->devnum_next_mutex);
} }
static void release_devnum(struct usb_device *udev) static void release_devnum(struct usb_device *udev)
...@@ -4364,7 +4366,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, ...@@ -4364,7 +4366,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
if (oldspeed == USB_SPEED_LOW) if (oldspeed == USB_SPEED_LOW)
delay = HUB_LONG_RESET_TIME; delay = HUB_LONG_RESET_TIME;
mutex_lock(&hdev->bus->usb_address0_mutex); mutex_lock(hcd->address0_mutex);
/* Reset the device; full speed may morph to high speed */ /* Reset the device; full speed may morph to high speed */
/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */ /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
...@@ -4650,7 +4652,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, ...@@ -4650,7 +4652,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
hub_port_disable(hub, port1, 0); hub_port_disable(hub, port1, 0);
update_devnum(udev, devnum); /* for disconnect processing */ update_devnum(udev, devnum); /* for disconnect processing */
} }
mutex_unlock(&hdev->bus->usb_address0_mutex); mutex_unlock(hcd->address0_mutex);
return retval; return retval;
} }
......
...@@ -302,9 +302,10 @@ static void sg_complete(struct urb *urb) ...@@ -302,9 +302,10 @@ static void sg_complete(struct urb *urb)
*/ */
spin_unlock(&io->lock); spin_unlock(&io->lock);
for (i = 0, found = 0; i < io->entries; i++) { for (i = 0, found = 0; i < io->entries; i++) {
if (!io->urbs[i] || !io->urbs[i]->dev) if (!io->urbs[i])
continue; continue;
if (found) { if (found) {
usb_block_urb(io->urbs[i]);
retval = usb_unlink_urb(io->urbs[i]); retval = usb_unlink_urb(io->urbs[i]);
if (retval != -EINPROGRESS && if (retval != -EINPROGRESS &&
retval != -ENODEV && retval != -ENODEV &&
...@@ -515,12 +516,10 @@ void usb_sg_wait(struct usb_sg_request *io) ...@@ -515,12 +516,10 @@ void usb_sg_wait(struct usb_sg_request *io)
int retval; int retval;
io->urbs[i]->dev = io->dev; io->urbs[i]->dev = io->dev;
retval = usb_submit_urb(io->urbs[i], GFP_ATOMIC);
/* after we submit, let completions or cancellations fire;
* we handshake using io->status.
*/
spin_unlock_irq(&io->lock); spin_unlock_irq(&io->lock);
retval = usb_submit_urb(io->urbs[i], GFP_NOIO);
switch (retval) { switch (retval) {
/* maybe we retrying will recover */ /* maybe we retrying will recover */
case -ENXIO: /* hc didn't queue this one */ case -ENXIO: /* hc didn't queue this one */
...@@ -578,31 +577,28 @@ EXPORT_SYMBOL_GPL(usb_sg_wait); ...@@ -578,31 +577,28 @@ EXPORT_SYMBOL_GPL(usb_sg_wait);
void usb_sg_cancel(struct usb_sg_request *io) void usb_sg_cancel(struct usb_sg_request *io)
{ {
unsigned long flags; unsigned long flags;
int i, retval;
spin_lock_irqsave(&io->lock, flags); spin_lock_irqsave(&io->lock, flags);
if (io->status) {
spin_unlock_irqrestore(&io->lock, flags);
return;
}
/* shut everything down */
io->status = -ECONNRESET;
spin_unlock_irqrestore(&io->lock, flags);
/* shut everything down, if it didn't already */ for (i = io->entries - 1; i >= 0; --i) {
if (!io->status) { usb_block_urb(io->urbs[i]);
int i;
io->status = -ECONNRESET;
spin_unlock(&io->lock);
for (i = 0; i < io->entries; i++) {
int retval;
if (!io->urbs[i]->dev) retval = usb_unlink_urb(io->urbs[i]);
continue; if (retval != -EINPROGRESS
retval = usb_unlink_urb(io->urbs[i]); && retval != -ENODEV
if (retval != -EINPROGRESS && retval != -EBUSY
&& retval != -ENODEV && retval != -EIDRM)
&& retval != -EBUSY dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
&& retval != -EIDRM) __func__, retval);
dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
__func__, retval);
}
spin_lock(&io->lock);
} }
spin_unlock_irqrestore(&io->lock, flags);
} }
EXPORT_SYMBOL_GPL(usb_sg_cancel); EXPORT_SYMBOL_GPL(usb_sg_cancel);
......
...@@ -466,7 +466,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, ...@@ -466,7 +466,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
dev->route = 0; dev->route = 0;
dev->dev.parent = bus->controller; dev->dev.parent = bus->controller;
dev->dev.of_node = bus->controller->of_node;
dev_set_name(&dev->dev, "usb%d", bus->busnum); dev_set_name(&dev->dev, "usb%d", bus->busnum);
root_hub = 1; root_hub = 1;
} else { } else {
......
...@@ -2425,6 +2425,9 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) ...@@ -2425,6 +2425,9 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw)
u32 gintsts; u32 gintsts;
u32 gintmsk; u32 gintmsk;
if (!dwc2_is_device_mode(hsotg))
return IRQ_NONE;
spin_lock(&hsotg->lock); spin_lock(&hsotg->lock);
irq_retry: irq_retry:
gintsts = dwc2_readl(hsotg->regs + GINTSTS); gintsts = dwc2_readl(hsotg->regs + GINTSTS);
...@@ -2631,7 +2634,10 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, ...@@ -2631,7 +2634,10 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
desc->wMaxPacketSize, desc->bInterval); desc->wMaxPacketSize, desc->bInterval);
/* not to be called for EP0 */ /* not to be called for EP0 */
WARN_ON(index == 0); if (index == 0) {
dev_err(hsotg->dev, "%s: called for EP 0\n", __func__);
return -EINVAL;
}
dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
if (dir_in != hs_ep->dir_in) { if (dir_in != hs_ep->dir_in) {
......
...@@ -4703,6 +4703,7 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, ...@@ -4703,6 +4703,7 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
spin_unlock_irqrestore(&hsotg->lock, flags); spin_unlock_irqrestore(&hsotg->lock, flags);
urb->hcpriv = NULL; urb->hcpriv = NULL;
kfree(qtd); kfree(qtd);
qtd = NULL;
fail1: fail1:
if (qh_allocated) { if (qh_allocated) {
struct dwc2_qtd *qtd2, *qtd2_tmp; struct dwc2_qtd *qtd2, *qtd2_tmp;
......
...@@ -552,6 +552,7 @@ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg, ...@@ -552,6 +552,7 @@ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
{ {
list_del(&qtd->qtd_list_entry); list_del(&qtd->qtd_list_entry);
kfree(qtd); kfree(qtd);
qtd = NULL;
} }
/* Descriptor DMA support functions */ /* Descriptor DMA support functions */
......
...@@ -1709,7 +1709,8 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) ...@@ -1709,7 +1709,8 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
dwc2_deschedule_periodic(hsotg, qh); dwc2_deschedule_periodic(hsotg, qh);
hsotg->periodic_qh_count--; hsotg->periodic_qh_count--;
if (!hsotg->periodic_qh_count) { if (!hsotg->periodic_qh_count &&
hsotg->core_params->dma_desc_enable <= 0) {
intr_mask = dwc2_readl(hsotg->regs + GINTMSK); intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
intr_mask &= ~GINTSTS_SOF; intr_mask &= ~GINTSTS_SOF;
dwc2_writel(intr_mask, hsotg->regs + GINTMSK); dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
......
...@@ -562,7 +562,7 @@ static int dwc2_driver_probe(struct platform_device *dev) ...@@ -562,7 +562,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
retval = dwc2_get_dr_mode(hsotg); retval = dwc2_get_dr_mode(hsotg);
if (retval) if (retval)
return retval; goto error;
/* /*
* Reset before dwc2_get_hwparams() then it could get power-on real * Reset before dwc2_get_hwparams() then it could get power-on real
......
...@@ -60,6 +60,20 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode) ...@@ -60,6 +60,20 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
dwc3_writel(dwc->regs, DWC3_GCTL, reg); dwc3_writel(dwc->regs, DWC3_GCTL, reg);
} }
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
{
struct dwc3 *dwc = dep->dwc;
u32 reg;
dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE,
DWC3_GDBGFIFOSPACE_NUM(dep->number) |
DWC3_GDBGFIFOSPACE_TYPE(type));
reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE);
return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg);
}
/** /**
* dwc3_core_soft_reset - Issues core soft reset and PHY reset * dwc3_core_soft_reset - Issues core soft reset and PHY reset
* @dwc: pointer to our context structure * @dwc: pointer to our context structure
...@@ -203,13 +217,10 @@ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, ...@@ -203,13 +217,10 @@ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
static void dwc3_free_event_buffers(struct dwc3 *dwc) static void dwc3_free_event_buffers(struct dwc3 *dwc)
{ {
struct dwc3_event_buffer *evt; struct dwc3_event_buffer *evt;
int i;
for (i = 0; i < dwc->num_event_buffers; i++) { evt = dwc->ev_buf;
evt = dwc->ev_buffs[i]; if (evt)
if (evt) dwc3_free_one_event_buffer(dwc, evt);
dwc3_free_one_event_buffer(dwc, evt);
}
} }
/** /**
...@@ -222,27 +233,14 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) ...@@ -222,27 +233,14 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
*/ */
static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
{ {
int num; struct dwc3_event_buffer *evt;
int i;
num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
dwc->num_event_buffers = num;
dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
GFP_KERNEL);
if (!dwc->ev_buffs)
return -ENOMEM;
for (i = 0; i < num; i++) {
struct dwc3_event_buffer *evt;
evt = dwc3_alloc_one_event_buffer(dwc, length); evt = dwc3_alloc_one_event_buffer(dwc, length);
if (IS_ERR(evt)) { if (IS_ERR(evt)) {
dev_err(dwc->dev, "can't allocate event buffer\n"); dev_err(dwc->dev, "can't allocate event buffer\n");
return PTR_ERR(evt); return PTR_ERR(evt);
}
dwc->ev_buffs[i] = evt;
} }
dwc->ev_buf = evt;
return 0; return 0;
} }
...@@ -256,25 +254,22 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) ...@@ -256,25 +254,22 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
static int dwc3_event_buffers_setup(struct dwc3 *dwc) static int dwc3_event_buffers_setup(struct dwc3 *dwc)
{ {
struct dwc3_event_buffer *evt; struct dwc3_event_buffer *evt;
int n;
for (n = 0; n < dwc->num_event_buffers; n++) { evt = dwc->ev_buf;
evt = dwc->ev_buffs[n]; dwc3_trace(trace_dwc3_core,
dwc3_trace(trace_dwc3_core, "Event buf %p dma %08llx length %d\n",
"Event buf %p dma %08llx length %d\n", evt->buf, (unsigned long long) evt->dma,
evt->buf, (unsigned long long) evt->dma, evt->length);
evt->length);
evt->lpos = 0;
evt->lpos = 0;
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0),
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), lower_32_bits(evt->dma));
lower_32_bits(evt->dma)); dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0),
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), upper_32_bits(evt->dma));
upper_32_bits(evt->dma)); dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_SIZE(evt->length));
DWC3_GEVNTSIZ_SIZE(evt->length)); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
}
return 0; return 0;
} }
...@@ -282,19 +277,16 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc) ...@@ -282,19 +277,16 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc)
static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
{ {
struct dwc3_event_buffer *evt; struct dwc3_event_buffer *evt;
int n;
for (n = 0; n < dwc->num_event_buffers; n++) { evt = dwc->ev_buf;
evt = dwc->ev_buffs[n];
evt->lpos = 0; evt->lpos = 0;
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0);
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0);
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK
| DWC3_GEVNTSIZ_SIZE(0)); | DWC3_GEVNTSIZ_SIZE(0));
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
}
} }
static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
...@@ -434,6 +426,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc) ...@@ -434,6 +426,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
if (dwc->u2ss_inp3_quirk) if (dwc->u2ss_inp3_quirk)
reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
if (dwc->dis_rxdet_inp3_quirk)
reg |= DWC3_GUSB3PIPECTL_DISRXDETINP3;
if (dwc->req_p1p2p3_quirk) if (dwc->req_p1p2p3_quirk)
reg |= DWC3_GUSB3PIPECTL_REQP1P2P3; reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
...@@ -882,9 +877,6 @@ static int dwc3_probe(struct platform_device *pdev) ...@@ -882,9 +877,6 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->usb3_lpm_capable = device_property_read_bool(dev, dwc->usb3_lpm_capable = device_property_read_bool(dev,
"snps,usb3_lpm_capable"); "snps,usb3_lpm_capable");
dwc->needs_fifo_resize = device_property_read_bool(dev,
"tx-fifo-resize");
dwc->disable_scramble_quirk = device_property_read_bool(dev, dwc->disable_scramble_quirk = device_property_read_bool(dev,
"snps,disable_scramble_quirk"); "snps,disable_scramble_quirk");
dwc->u2exit_lfps_quirk = device_property_read_bool(dev, dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
...@@ -907,6 +899,8 @@ static int dwc3_probe(struct platform_device *pdev) ...@@ -907,6 +899,8 @@ static int dwc3_probe(struct platform_device *pdev)
"snps,dis_u2_susphy_quirk"); "snps,dis_u2_susphy_quirk");
dwc->dis_enblslpm_quirk = device_property_read_bool(dev, dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
"snps,dis_enblslpm_quirk"); "snps,dis_enblslpm_quirk");
dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
"snps,dis_rxdet_inp3_quirk");
dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
"snps,tx_de_emphasis_quirk"); "snps,tx_de_emphasis_quirk");
...@@ -926,7 +920,6 @@ static int dwc3_probe(struct platform_device *pdev) ...@@ -926,7 +920,6 @@ static int dwc3_probe(struct platform_device *pdev)
if (pdata->hird_threshold) if (pdata->hird_threshold)
hird_threshold = pdata->hird_threshold; hird_threshold = pdata->hird_threshold;
dwc->needs_fifo_resize = pdata->tx_fifo_resize;
dwc->usb3_lpm_capable = pdata->usb3_lpm_capable; dwc->usb3_lpm_capable = pdata->usb3_lpm_capable;
dwc->dr_mode = pdata->dr_mode; dwc->dr_mode = pdata->dr_mode;
...@@ -941,6 +934,7 @@ static int dwc3_probe(struct platform_device *pdev) ...@@ -941,6 +934,7 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk; dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk; dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk; dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk;
dwc->dis_rxdet_inp3_quirk = pdata->dis_rxdet_inp3_quirk;
dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk; dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
if (pdata->tx_de_emphasis) if (pdata->tx_de_emphasis)
...@@ -1050,19 +1044,11 @@ static int dwc3_probe(struct platform_device *pdev) ...@@ -1050,19 +1044,11 @@ static int dwc3_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err5; goto err5;
ret = dwc3_debugfs_init(dwc); dwc3_debugfs_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize debugfs\n");
goto err6;
}
pm_runtime_allow(dev); pm_runtime_allow(dev);
return 0; return 0;
err6:
dwc3_core_exit_mode(dwc);
err5: err5:
dwc3_event_buffers_cleanup(dwc); dwc3_event_buffers_cleanup(dwc);
......
...@@ -152,6 +152,24 @@ ...@@ -152,6 +152,24 @@
/* Bit fields */ /* Bit fields */
/* Global Debug Queue/FIFO Space Available Register */
#define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f)
#define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0)
#define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff)
#define DWC3_TXFIFOQ 1
#define DWC3_RXFIFOQ 3
#define DWC3_TXREQQ 5
#define DWC3_RXREQQ 7
#define DWC3_RXINFOQ 9
#define DWC3_DESCFETCHQ 13
#define DWC3_EVENTQ 15
/* Global RX Threshold Configuration Register */
#define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19)
#define DWC3_GRXTHRCFG_RXPKTCNT(n) (((n) & 0xf) << 24)
#define DWC3_GRXTHRCFG_PKTCNTSEL (1 << 29)
/* Global Configuration Register */ /* Global Configuration Register */
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19) #define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
#define DWC3_GCTL_U2RSTECN (1 << 16) #define DWC3_GCTL_U2RSTECN (1 << 16)
...@@ -193,6 +211,7 @@ ...@@ -193,6 +211,7 @@
/* Global USB3 PIPE Control Register */ /* Global USB3 PIPE Control Register */
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
#define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29) #define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29)
#define DWC3_GUSB3PIPECTL_DISRXDETINP3 (1 << 28)
#define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24) #define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24)
#define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19) #define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19)
#define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7) #define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7)
...@@ -257,6 +276,9 @@ ...@@ -257,6 +276,9 @@
#define DWC3_DCFG_LOWSPEED (2 << 0) #define DWC3_DCFG_LOWSPEED (2 << 0)
#define DWC3_DCFG_FULLSPEED1 (3 << 0) #define DWC3_DCFG_FULLSPEED1 (3 << 0)
#define DWC3_DCFG_NUMP_SHIFT 17
#define DWC3_DCFG_NUMP(n) (((n) >> DWC3_DCFG_NUMP_SHIFT) & 0x1f)
#define DWC3_DCFG_NUMP_MASK (0x1f << DWC3_DCFG_NUMP_SHIFT)
#define DWC3_DCFG_LPM_CAP (1 << 22) #define DWC3_DCFG_LPM_CAP (1 << 22)
/* Device Control Register */ /* Device Control Register */
...@@ -438,18 +460,17 @@ struct dwc3_event_buffer { ...@@ -438,18 +460,17 @@ struct dwc3_event_buffer {
#define DWC3_EP_DIRECTION_TX true #define DWC3_EP_DIRECTION_TX true
#define DWC3_EP_DIRECTION_RX false #define DWC3_EP_DIRECTION_RX false
#define DWC3_TRB_NUM 32 #define DWC3_TRB_NUM 256
#define DWC3_TRB_MASK (DWC3_TRB_NUM - 1)
/** /**
* struct dwc3_ep - device side endpoint representation * struct dwc3_ep - device side endpoint representation
* @endpoint: usb endpoint * @endpoint: usb endpoint
* @request_list: list of requests for this endpoint * @pending_list: list of pending requests for this endpoint
* @req_queued: list of requests on this ep which have TRBs setup * @started_list: list of started requests on this endpoint
* @trb_pool: array of transaction buffers * @trb_pool: array of transaction buffers
* @trb_pool_dma: dma address of @trb_pool * @trb_pool_dma: dma address of @trb_pool
* @free_slot: next slot which is going to be used * @trb_enqueue: enqueue 'pointer' into TRB array
* @busy_slot: first slot which is owned by HW * @trb_dequeue: dequeue 'pointer' into TRB array
* @desc: usb_endpoint_descriptor pointer * @desc: usb_endpoint_descriptor pointer
* @dwc: pointer to DWC controller * @dwc: pointer to DWC controller
* @saved_state: ep state saved during hibernation * @saved_state: ep state saved during hibernation
...@@ -464,13 +485,11 @@ struct dwc3_event_buffer { ...@@ -464,13 +485,11 @@ struct dwc3_event_buffer {
*/ */
struct dwc3_ep { struct dwc3_ep {
struct usb_ep endpoint; struct usb_ep endpoint;
struct list_head request_list; struct list_head pending_list;
struct list_head req_queued; struct list_head started_list;
struct dwc3_trb *trb_pool; struct dwc3_trb *trb_pool;
dma_addr_t trb_pool_dma; dma_addr_t trb_pool_dma;
u32 free_slot;
u32 busy_slot;
const struct usb_ss_ep_comp_descriptor *comp_desc; const struct usb_ss_ep_comp_descriptor *comp_desc;
struct dwc3 *dwc; struct dwc3 *dwc;
...@@ -486,6 +505,18 @@ struct dwc3_ep { ...@@ -486,6 +505,18 @@ struct dwc3_ep {
/* This last one is specific to EP0 */ /* This last one is specific to EP0 */
#define DWC3_EP0_DIR_IN (1 << 31) #define DWC3_EP0_DIR_IN (1 << 31)
/*
* IMPORTANT: we *know* we have 256 TRBs in our @trb_pool, so we will
* use a u8 type here. If anybody decides to increase number of TRBs to
* anything larger than 256 - I can't see why people would want to do
* this though - then this type needs to be changed.
*
* By using u8 types we ensure that our % operator when incrementing
* enqueue and dequeue get optimized away by the compiler.
*/
u8 trb_enqueue;
u8 trb_dequeue;
u8 number; u8 number;
u8 type; u8 type;
u8 resource_index; u8 resource_index;
...@@ -557,6 +588,7 @@ enum dwc3_link_state { ...@@ -557,6 +588,7 @@ enum dwc3_link_state {
#define DWC3_TRB_CTRL_IOC (1 << 11) #define DWC3_TRB_CTRL_IOC (1 << 11)
#define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14) #define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14)
#define DWC3_TRBCTL_TYPE(n) ((n) & (0x3f << 4))
#define DWC3_TRBCTL_NORMAL DWC3_TRB_CTRL_TRBCTL(1) #define DWC3_TRBCTL_NORMAL DWC3_TRB_CTRL_TRBCTL(1)
#define DWC3_TRBCTL_CONTROL_SETUP DWC3_TRB_CTRL_TRBCTL(2) #define DWC3_TRBCTL_CONTROL_SETUP DWC3_TRB_CTRL_TRBCTL(2)
#define DWC3_TRBCTL_CONTROL_STATUS2 DWC3_TRB_CTRL_TRBCTL(3) #define DWC3_TRBCTL_CONTROL_STATUS2 DWC3_TRB_CTRL_TRBCTL(3)
...@@ -623,19 +655,32 @@ struct dwc3_hwparams { ...@@ -623,19 +655,32 @@ struct dwc3_hwparams {
/* HWPARAMS7 */ /* HWPARAMS7 */
#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff) #define DWC3_RAM1_DEPTH(n) ((n) & 0xffff)
/**
* struct dwc3_request - representation of a transfer request
* @request: struct usb_request to be transferred
* @list: a list_head used for request queueing
* @dep: struct dwc3_ep owning this request
* @first_trb_index: index to first trb used by this request
* @epnum: endpoint number to which this request refers
* @trb: pointer to struct dwc3_trb
* @trb_dma: DMA address of @trb
* @direction: IN or OUT direction flag
* @mapped: true when request has been dma-mapped
* @queued: true when request has been queued to HW
*/
struct dwc3_request { struct dwc3_request {
struct usb_request request; struct usb_request request;
struct list_head list; struct list_head list;
struct dwc3_ep *dep; struct dwc3_ep *dep;
u32 start_slot;
u8 first_trb_index;
u8 epnum; u8 epnum;
struct dwc3_trb *trb; struct dwc3_trb *trb;
dma_addr_t trb_dma; dma_addr_t trb_dma;
unsigned direction:1; unsigned direction:1;
unsigned mapped:1; unsigned mapped:1;
unsigned queued:1; unsigned started:1;
}; };
/* /*
...@@ -667,7 +712,6 @@ struct dwc3_scratchpad_array { ...@@ -667,7 +712,6 @@ struct dwc3_scratchpad_array {
* @regs: base address for our registers * @regs: base address for our registers
* @regs_size: address space size * @regs_size: address space size
* @nr_scratch: number of scratch buffers * @nr_scratch: number of scratch buffers
* @num_event_buffers: calculated number of event buffers
* @u1u2: only used on revisions <1.83a for workaround * @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes) * @maximum_speed: maximum speed requested (mainly for testing purposes)
* @revision: revision register contents * @revision: revision register contents
...@@ -709,9 +753,7 @@ struct dwc3_scratchpad_array { ...@@ -709,9 +753,7 @@ struct dwc3_scratchpad_array {
* 0 - utmi_sleep_n * 0 - utmi_sleep_n
* 1 - utmi_l1_suspend_n * 1 - utmi_l1_suspend_n
* @is_fpga: true when we are using the FPGA board * @is_fpga: true when we are using the FPGA board
* @needs_fifo_resize: not all users might want fifo resizing, flag it
* @pullups_connected: true when Run/Stop bit is set * @pullups_connected: true when Run/Stop bit is set
* @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
* @start_config_issued: true when StartConfig command has been issued * @start_config_issued: true when StartConfig command has been issued
* @three_stage_setup: set if we perform a three phase setup * @three_stage_setup: set if we perform a three phase setup
...@@ -756,7 +798,7 @@ struct dwc3 { ...@@ -756,7 +798,7 @@ struct dwc3 {
struct platform_device *xhci; struct platform_device *xhci;
struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM]; struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM];
struct dwc3_event_buffer **ev_buffs; struct dwc3_event_buffer *ev_buf;
struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM];
struct usb_gadget gadget; struct usb_gadget gadget;
...@@ -780,7 +822,6 @@ struct dwc3 { ...@@ -780,7 +822,6 @@ struct dwc3 {
u32 gctl; u32 gctl;
u32 nr_scratch; u32 nr_scratch;
u32 num_event_buffers;
u32 u1u2; u32 u1u2;
u32 maximum_speed; u32 maximum_speed;
...@@ -855,9 +896,7 @@ struct dwc3 { ...@@ -855,9 +896,7 @@ struct dwc3 {
unsigned has_lpm_erratum:1; unsigned has_lpm_erratum:1;
unsigned is_utmi_l1_suspend:1; unsigned is_utmi_l1_suspend:1;
unsigned is_fpga:1; unsigned is_fpga:1;
unsigned needs_fifo_resize:1;
unsigned pullups_connected:1; unsigned pullups_connected:1;
unsigned resize_fifos:1;
unsigned setup_packet_pending:1; unsigned setup_packet_pending:1;
unsigned three_stage_setup:1; unsigned three_stage_setup:1;
unsigned usb3_lpm_capable:1; unsigned usb3_lpm_capable:1;
...@@ -873,6 +912,7 @@ struct dwc3 { ...@@ -873,6 +912,7 @@ struct dwc3 {
unsigned dis_u3_susphy_quirk:1; unsigned dis_u3_susphy_quirk:1;
unsigned dis_u2_susphy_quirk:1; unsigned dis_u2_susphy_quirk:1;
unsigned dis_enblslpm_quirk:1; unsigned dis_enblslpm_quirk:1;
unsigned dis_rxdet_inp3_quirk:1;
unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2; unsigned tx_de_emphasis:2;
...@@ -938,6 +978,10 @@ struct dwc3_event_depevt { ...@@ -938,6 +978,10 @@ struct dwc3_event_depevt {
#define DEPEVT_STATUS_CONTROL_DATA 1 #define DEPEVT_STATUS_CONTROL_DATA 1
#define DEPEVT_STATUS_CONTROL_STATUS 2 #define DEPEVT_STATUS_CONTROL_STATUS 2
/* In response to Start Transfer */
#define DEPEVT_TRANSFER_NO_RESOURCE 1
#define DEPEVT_TRANSFER_BUS_EXPIRY 2
u32 parameters:16; u32 parameters:16;
} __packed; } __packed;
...@@ -1025,7 +1069,7 @@ struct dwc3_gadget_ep_cmd_params { ...@@ -1025,7 +1069,7 @@ struct dwc3_gadget_ep_cmd_params {
/* prototypes */ /* prototypes */
void dwc3_set_mode(struct dwc3 *dwc, u32 mode); void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc); u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
/* check whether we are on the DWC_usb31 core */ /* check whether we are on the DWC_usb31 core */
static inline bool dwc3_is_usb31(struct dwc3 *dwc) static inline bool dwc3_is_usb31(struct dwc3 *dwc)
......
...@@ -217,11 +217,11 @@ static inline const char *dwc3_gadget_event_type_string(u8 event) ...@@ -217,11 +217,11 @@ static inline const char *dwc3_gadget_event_type_string(u8 event)
void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...); void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
extern int dwc3_debugfs_init(struct dwc3 *); extern void dwc3_debugfs_init(struct dwc3 *);
extern void dwc3_debugfs_exit(struct dwc3 *); extern void dwc3_debugfs_exit(struct dwc3 *);
#else #else
static inline int dwc3_debugfs_init(struct dwc3 *d) static inline void dwc3_debugfs_init(struct dwc3 *d)
{ return 0; } { }
static inline void dwc3_debugfs_exit(struct dwc3 *d) static inline void dwc3_debugfs_exit(struct dwc3 *d)
{ } { }
#endif #endif
......
...@@ -618,24 +618,323 @@ static const struct file_operations dwc3_link_state_fops = { ...@@ -618,24 +618,323 @@ static const struct file_operations dwc3_link_state_fops = {
.release = single_release, .release = single_release,
}; };
int dwc3_debugfs_init(struct dwc3 *dwc) struct dwc3_ep_file_map {
char name[25];
int (*show)(struct seq_file *s, void *unused);
};
static int dwc3_tx_fifo_queue_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_TXFIFOQ);
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_rx_fifo_queue_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_RXFIFOQ);
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_tx_request_queue_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_TXREQQ);
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_rx_request_queue_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_RXREQQ);
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_rx_info_queue_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_RXINFOQ);
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_descriptor_fetch_queue_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_DESCFETCHQ);
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_event_queue_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_EVENTQ);
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_ep_transfer_type_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
if (!(dep->flags & DWC3_EP_ENABLED) ||
!dep->endpoint.desc) {
seq_printf(s, "--\n");
goto out;
}
switch (usb_endpoint_type(dep->endpoint.desc)) {
case USB_ENDPOINT_XFER_CONTROL:
seq_printf(s, "control\n");
break;
case USB_ENDPOINT_XFER_ISOC:
seq_printf(s, "isochronous\n");
break;
case USB_ENDPOINT_XFER_BULK:
seq_printf(s, "bulk\n");
break;
case USB_ENDPOINT_XFER_INT:
seq_printf(s, "interrupt\n");
break;
default:
seq_printf(s, "--\n");
}
out:
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static inline const char *dwc3_trb_type_string(struct dwc3_trb *trb)
{
switch (DWC3_TRBCTL_TYPE(trb->ctrl)) {
case DWC3_TRBCTL_NORMAL:
return "normal";
case DWC3_TRBCTL_CONTROL_SETUP:
return "control-setup";
case DWC3_TRBCTL_CONTROL_STATUS2:
return "control-status2";
case DWC3_TRBCTL_CONTROL_STATUS3:
return "control-status3";
case DWC3_TRBCTL_CONTROL_DATA:
return "control-data";
case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
return "isoc-first";
case DWC3_TRBCTL_ISOCHRONOUS:
return "isoc";
case DWC3_TRBCTL_LINK_TRB:
return "link";
default:
return "UNKNOWN";
}
}
static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
int i;
spin_lock_irqsave(&dwc->lock, flags);
if (dep->number <= 1) {
seq_printf(s, "--\n");
goto out;
}
seq_printf(s, "enqueue pointer %d\n", dep->trb_enqueue);
seq_printf(s, "dequeue pointer %d\n", dep->trb_dequeue);
seq_printf(s, "\n--------------------------------------------------\n\n");
seq_printf(s, "buffer_addr,size,type,ioc,isp_imi,csp,chn,lst,hwo\n");
for (i = 0; i < DWC3_TRB_NUM; i++) {
struct dwc3_trb *trb = &dep->trb_pool[i];
seq_printf(s, "%08x%08x,%d,%s,%d,%d,%d,%d,%d,%d\n",
trb->bph, trb->bpl, trb->size,
dwc3_trb_type_string(trb),
!!(trb->ctrl & DWC3_TRB_CTRL_IOC),
!!(trb->ctrl & DWC3_TRB_CTRL_ISP_IMI),
!!(trb->ctrl & DWC3_TRB_CTRL_CSP),
!!(trb->ctrl & DWC3_TRB_CTRL_CHN),
!!(trb->ctrl & DWC3_TRB_CTRL_LST),
!!(trb->ctrl & DWC3_TRB_CTRL_HWO));
}
out:
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static struct dwc3_ep_file_map map[] = {
{ "tx_fifo_queue", dwc3_tx_fifo_queue_show, },
{ "rx_fifo_queue", dwc3_rx_fifo_queue_show, },
{ "tx_request_queue", dwc3_tx_request_queue_show, },
{ "rx_request_queue", dwc3_rx_request_queue_show, },
{ "rx_info_queue", dwc3_rx_info_queue_show, },
{ "descriptor_fetch_queue", dwc3_descriptor_fetch_queue_show, },
{ "event_queue", dwc3_event_queue_show, },
{ "transfer_type", dwc3_ep_transfer_type_show, },
{ "trb_ring", dwc3_ep_trb_ring_show, },
};
static int dwc3_endpoint_open(struct inode *inode, struct file *file)
{
const char *file_name = file_dentry(file)->d_iname;
struct dwc3_ep_file_map *f_map;
int i;
for (i = 0; i < ARRAY_SIZE(map); i++) {
f_map = &map[i];
if (strcmp(f_map->name, file_name) == 0)
break;
}
return single_open(file, f_map->show, inode->i_private);
}
static const struct file_operations dwc3_endpoint_fops = {
.open = dwc3_endpoint_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static void dwc3_debugfs_create_endpoint_file(struct dwc3_ep *dep,
struct dentry *parent, int type)
{ {
struct dentry *root;
struct dentry *file; struct dentry *file;
int ret; struct dwc3_ep_file_map *ep_file = &map[type];
root = debugfs_create_dir(dev_name(dwc->dev), NULL); file = debugfs_create_file(ep_file->name, S_IRUGO, parent, dep,
if (!root) { &dwc3_endpoint_fops);
ret = -ENOMEM; }
goto err0;
static void dwc3_debugfs_create_endpoint_files(struct dwc3_ep *dep,
struct dentry *parent)
{
int i;
for (i = 0; i < ARRAY_SIZE(map); i++)
dwc3_debugfs_create_endpoint_file(dep, parent, i);
}
static void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep,
struct dentry *parent)
{
struct dentry *dir;
dir = debugfs_create_dir(dep->name, parent);
if (IS_ERR_OR_NULL(dir))
return;
dwc3_debugfs_create_endpoint_files(dep, dir);
}
static void dwc3_debugfs_create_endpoint_dirs(struct dwc3 *dwc,
struct dentry *parent)
{
int i;
for (i = 0; i < dwc->num_in_eps; i++) {
u8 epnum = (i << 1) | 1;
struct dwc3_ep *dep = dwc->eps[epnum];
if (!dep)
continue;
dwc3_debugfs_create_endpoint_dir(dep, parent);
}
for (i = 0; i < dwc->num_out_eps; i++) {
u8 epnum = (i << 1);
struct dwc3_ep *dep = dwc->eps[epnum];
if (!dep)
continue;
dwc3_debugfs_create_endpoint_dir(dep, parent);
} }
}
void dwc3_debugfs_init(struct dwc3 *dwc)
{
struct dentry *root;
struct dentry *file;
root = debugfs_create_dir(dev_name(dwc->dev), NULL);
if (IS_ERR_OR_NULL(root)) {
if (!root)
dev_err(dwc->dev, "Can't create debugfs root\n");
return;
}
dwc->root = root; dwc->root = root;
dwc->regset = kzalloc(sizeof(*dwc->regset), GFP_KERNEL); dwc->regset = kzalloc(sizeof(*dwc->regset), GFP_KERNEL);
if (!dwc->regset) { if (!dwc->regset) {
ret = -ENOMEM; debugfs_remove_recursive(root);
goto err1; return;
} }
dwc->regset->regs = dwc3_regs; dwc->regset->regs = dwc3_regs;
...@@ -643,47 +942,30 @@ int dwc3_debugfs_init(struct dwc3 *dwc) ...@@ -643,47 +942,30 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
dwc->regset->base = dwc->regs; dwc->regset->base = dwc->regs;
file = debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset); file = debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset);
if (!file) { if (!file)
ret = -ENOMEM; dev_dbg(dwc->dev, "Can't create debugfs regdump\n");
goto err2;
}
if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) { if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) {
file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
dwc, &dwc3_mode_fops); dwc, &dwc3_mode_fops);
if (!file) { if (!file)
ret = -ENOMEM; dev_dbg(dwc->dev, "Can't create debugfs mode\n");
goto err2;
}
} }
if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) || if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) ||
IS_ENABLED(CONFIG_USB_DWC3_GADGET)) { IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
dwc, &dwc3_testmode_fops); dwc, &dwc3_testmode_fops);
if (!file) { if (!file)
ret = -ENOMEM; dev_dbg(dwc->dev, "Can't create debugfs testmode\n");
goto err2;
}
file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
dwc, &dwc3_link_state_fops);
if (!file) {
ret = -ENOMEM;
goto err2;
}
}
return 0; file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR,
root, dwc, &dwc3_link_state_fops);
if (!file)
dev_dbg(dwc->dev, "Can't create debugfs link_state\n");
err2: dwc3_debugfs_create_endpoint_dirs(dwc, root);
kfree(dwc->regset); }
err1:
debugfs_remove_recursive(root);
err0:
return ret;
} }
void dwc3_debugfs_exit(struct dwc3 *dwc) void dwc3_debugfs_exit(struct dwc3 *dwc)
......
...@@ -126,8 +126,6 @@ struct dwc3_omap { ...@@ -126,8 +126,6 @@ struct dwc3_omap {
u32 debug_offset; u32 debug_offset;
u32 irq0_offset; u32 irq0_offset;
u32 dma_status:1;
struct extcon_dev *edev; struct extcon_dev *edev;
struct notifier_block vbus_nb; struct notifier_block vbus_nb;
struct notifier_block id_nb; struct notifier_block id_nb;
...@@ -277,9 +275,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) ...@@ -277,9 +275,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
reg = dwc3_omap_read_irqmisc_status(omap); reg = dwc3_omap_read_irqmisc_status(omap);
if (reg & USBOTGSS_IRQMISC_DMADISABLECLR)
omap->dma_status = false;
dwc3_omap_write_irqmisc_status(omap, reg); dwc3_omap_write_irqmisc_status(omap, reg);
reg = dwc3_omap_read_irq0_status(omap); reg = dwc3_omap_read_irq0_status(omap);
...@@ -331,8 +326,6 @@ static void dwc3_omap_disable_irqs(struct dwc3_omap *omap) ...@@ -331,8 +326,6 @@ static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
dwc3_omap_write_irqmisc_clr(omap, reg); dwc3_omap_write_irqmisc_clr(omap, reg);
} }
static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
static int dwc3_omap_id_notifier(struct notifier_block *nb, static int dwc3_omap_id_notifier(struct notifier_block *nb,
unsigned long event, void *ptr) unsigned long event, void *ptr)
{ {
...@@ -490,7 +483,6 @@ static int dwc3_omap_probe(struct platform_device *pdev) ...@@ -490,7 +483,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)
omap->irq = irq; omap->irq = irq;
omap->base = base; omap->base = base;
omap->vbus_reg = vbus_reg; omap->vbus_reg = vbus_reg;
dev->dma_mask = &dwc3_omap_dma_mask;
pm_runtime_enable(dev); pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev); ret = pm_runtime_get_sync(dev);
...@@ -504,7 +496,6 @@ static int dwc3_omap_probe(struct platform_device *pdev) ...@@ -504,7 +496,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)
/* check the DMA Status */ /* check the DMA Status */
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG); reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0, ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
"dwc3-omap", omap); "dwc3-omap", omap);
......
...@@ -47,7 +47,7 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = { ...@@ -47,7 +47,7 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
{ }, { },
}; };
static int dwc3_pci_quirks(struct pci_dev *pdev) static int dwc3_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc3)
{ {
if (pdev->vendor == PCI_VENDOR_ID_AMD && if (pdev->vendor == PCI_VENDOR_ID_AMD &&
pdev->device == PCI_DEVICE_ID_AMD_NL_USB) { pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
...@@ -77,8 +77,7 @@ static int dwc3_pci_quirks(struct pci_dev *pdev) ...@@ -77,8 +77,7 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
pdata.dis_u3_susphy_quirk = true; pdata.dis_u3_susphy_quirk = true;
pdata.dis_u2_susphy_quirk = true; pdata.dis_u2_susphy_quirk = true;
return platform_device_add_data(pci_get_drvdata(pdev), &pdata, return platform_device_add_data(dwc3, &pdata, sizeof(pdata));
sizeof(pdata));
} }
if (pdev->vendor == PCI_VENDOR_ID_INTEL && if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
...@@ -123,8 +122,7 @@ static int dwc3_pci_quirks(struct pci_dev *pdev) ...@@ -123,8 +122,7 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
pdata.has_lpm_erratum = true; pdata.has_lpm_erratum = true;
pdata.dis_enblslpm_quirk = true; pdata.dis_enblslpm_quirk = true;
return platform_device_add_data(pci_get_drvdata(pdev), &pdata, return platform_device_add_data(dwc3, &pdata, sizeof(pdata));
sizeof(pdata));
} }
return 0; return 0;
...@@ -169,20 +167,20 @@ static int dwc3_pci_probe(struct pci_dev *pci, ...@@ -169,20 +167,20 @@ static int dwc3_pci_probe(struct pci_dev *pci,
return ret; return ret;
} }
pci_set_drvdata(pci, dwc3);
ret = dwc3_pci_quirks(pci);
if (ret)
goto err;
dwc3->dev.parent = dev; dwc3->dev.parent = dev;
ACPI_COMPANION_SET(&dwc3->dev, ACPI_COMPANION(dev)); ACPI_COMPANION_SET(&dwc3->dev, ACPI_COMPANION(dev));
ret = dwc3_pci_quirks(pci, dwc3);
if (ret)
goto err;
ret = platform_device_add(dwc3); ret = platform_device_add(dwc3);
if (ret) { if (ret) {
dev_err(dev, "failed to register dwc3 device\n"); dev_err(dev, "failed to register dwc3 device\n");
goto err; goto err;
} }
pci_set_drvdata(pci, dwc3);
return 0; return 0;
err: err:
platform_device_put(dwc3); platform_device_put(dwc3);
......
...@@ -70,10 +70,10 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, ...@@ -70,10 +70,10 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
return 0; return 0;
} }
trb = &dwc->ep0_trb[dep->free_slot]; trb = &dwc->ep0_trb[dep->trb_enqueue];
if (chain) if (chain)
dep->free_slot++; dep->trb_enqueue++;
trb->bpl = lower_32_bits(buf_dma); trb->bpl = lower_32_bits(buf_dma);
trb->bph = upper_32_bits(buf_dma); trb->bph = upper_32_bits(buf_dma);
...@@ -124,7 +124,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, ...@@ -124,7 +124,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
req->request.status = -EINPROGRESS; req->request.status = -EINPROGRESS;
req->epnum = dep->number; req->epnum = dep->number;
list_add_tail(&req->list, &dep->request_list); list_add_tail(&req->list, &dep->pending_list);
/* /*
* Gadget driver might not be quick enough to queue a request * Gadget driver might not be quick enough to queue a request
...@@ -240,7 +240,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, ...@@ -240,7 +240,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
} }
/* we share one TRB for ep0/1 */ /* we share one TRB for ep0/1 */
if (!list_empty(&dep->request_list)) { if (!list_empty(&dep->pending_list)) {
ret = -EBUSY; ret = -EBUSY;
goto out; goto out;
} }
...@@ -272,10 +272,10 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) ...@@ -272,10 +272,10 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
dep->flags = DWC3_EP_ENABLED; dep->flags = DWC3_EP_ENABLED;
dwc->delayed_status = false; dwc->delayed_status = false;
if (!list_empty(&dep->request_list)) { if (!list_empty(&dep->pending_list)) {
struct dwc3_request *req; struct dwc3_request *req;
req = next_request(&dep->request_list); req = next_request(&dep->pending_list);
dwc3_gadget_giveback(dep, req, -ECONNRESET); dwc3_gadget_giveback(dep, req, -ECONNRESET);
} }
...@@ -463,8 +463,18 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, ...@@ -463,8 +463,18 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
if (!set) if (!set)
return -EINVAL; return -EINVAL;
dwc->test_mode_nr = wIndex >> 8; switch (wIndex >> 8) {
dwc->test_mode = true; case TEST_J:
case TEST_K:
case TEST_SE0_NAK:
case TEST_PACKET:
case TEST_FORCE_EN:
dwc->test_mode_nr = wIndex >> 8;
dwc->test_mode = true;
break;
default:
return -EINVAL;
}
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -586,9 +596,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) ...@@ -586,9 +596,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc->resize_fifos = true;
dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET");
} }
break; break;
...@@ -809,7 +816,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, ...@@ -809,7 +816,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
trace_dwc3_complete_trb(ep0, trb); trace_dwc3_complete_trb(ep0, trb);
r = next_request(&ep0->request_list); r = next_request(&ep0->pending_list);
if (!r) if (!r)
return; return;
...@@ -848,7 +855,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, ...@@ -848,7 +855,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
trb++; trb++;
length = trb->size & DWC3_TRB_SIZE_MASK; length = trb->size & DWC3_TRB_SIZE_MASK;
ep0->free_slot = 0; ep0->trb_enqueue = 0;
} }
transfer_size = roundup((ur->length - transfer_size), transfer_size = roundup((ur->length - transfer_size),
...@@ -897,8 +904,8 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc, ...@@ -897,8 +904,8 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
trace_dwc3_complete_trb(dep, trb); trace_dwc3_complete_trb(dep, trb);
if (!list_empty(&dep->request_list)) { if (!list_empty(&dep->pending_list)) {
r = next_request(&dep->request_list); r = next_request(&dep->pending_list);
dwc3_gadget_giveback(dep, r, 0); dwc3_gadget_giveback(dep, r, 0);
} }
...@@ -1027,12 +1034,6 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) ...@@ -1027,12 +1034,6 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep) static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
{ {
if (dwc->resize_fifos) {
dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs");
dwc3_gadget_resize_tx_fifos(dwc);
dwc->resize_fifos = 0;
}
WARN_ON(dwc3_ep0_start_control_status(dep)); WARN_ON(dwc3_ep0_start_control_status(dep));
} }
......
此差异已折叠。
...@@ -68,12 +68,12 @@ static inline struct dwc3_request *next_request(struct list_head *list) ...@@ -68,12 +68,12 @@ static inline struct dwc3_request *next_request(struct list_head *list)
return list_first_entry(list, struct dwc3_request, list); return list_first_entry(list, struct dwc3_request, list);
} }
static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req) static inline void dwc3_gadget_move_started_request(struct dwc3_request *req)
{ {
struct dwc3_ep *dep = req->dep; struct dwc3_ep *dep = req->dep;
req->queued = true; req->started = true;
list_move_tail(&req->list, &dep->req_queued); list_move_tail(&req->list, &dep->started_list);
} }
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
struct dwc3_platform_data { struct dwc3_platform_data {
enum usb_device_speed maximum_speed; enum usb_device_speed maximum_speed;
enum usb_dr_mode dr_mode; enum usb_dr_mode dr_mode;
bool tx_fifo_resize;
bool usb3_lpm_capable; bool usb3_lpm_capable;
unsigned is_utmi_l1_suspend:1; unsigned is_utmi_l1_suspend:1;
...@@ -43,6 +42,7 @@ struct dwc3_platform_data { ...@@ -43,6 +42,7 @@ struct dwc3_platform_data {
unsigned dis_u3_susphy_quirk:1; unsigned dis_u3_susphy_quirk:1;
unsigned dis_u2_susphy_quirk:1; unsigned dis_u2_susphy_quirk:1;
unsigned dis_enblslpm_quirk:1; unsigned dis_enblslpm_quirk:1;
unsigned dis_rxdet_inp3_quirk:1;
unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2; unsigned tx_de_emphasis:2;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
menuconfig USB_GADGET menuconfig USB_GADGET
tristate "USB Gadget Support" tristate "USB Gadget Support"
select USB_COMMON
select NLS select NLS
help help
USB is a master/slave protocol, organized with one master USB is a master/slave protocol, organized with one master
......
...@@ -66,20 +66,36 @@ function_descriptors(struct usb_function *f, ...@@ -66,20 +66,36 @@ function_descriptors(struct usb_function *f,
{ {
struct usb_descriptor_header **descriptors; struct usb_descriptor_header **descriptors;
/*
* NOTE: we try to help gadget drivers which might not be setting
* max_speed appropriately.
*/
switch (speed) { switch (speed) {
case USB_SPEED_SUPER_PLUS: case USB_SPEED_SUPER_PLUS:
descriptors = f->ssp_descriptors; descriptors = f->ssp_descriptors;
break; if (descriptors)
break;
/* FALLTHROUGH */
case USB_SPEED_SUPER: case USB_SPEED_SUPER:
descriptors = f->ss_descriptors; descriptors = f->ss_descriptors;
break; if (descriptors)
break;
/* FALLTHROUGH */
case USB_SPEED_HIGH: case USB_SPEED_HIGH:
descriptors = f->hs_descriptors; descriptors = f->hs_descriptors;
break; if (descriptors)
break;
/* FALLTHROUGH */
default: default:
descriptors = f->fs_descriptors; descriptors = f->fs_descriptors;
} }
/*
* if we can't find any descriptors at all, then this gadget deserves to
* Oops with a NULL pointer dereference
*/
return descriptors; return descriptors;
} }
......
...@@ -651,7 +651,7 @@ static void ffs_user_copy_worker(struct work_struct *work) ...@@ -651,7 +651,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
if (io_data->read && ret > 0) { if (io_data->read && ret > 0) {
use_mm(io_data->mm); use_mm(io_data->mm);
ret = copy_to_iter(io_data->buf, ret, &io_data->data); ret = copy_to_iter(io_data->buf, ret, &io_data->data);
if (iov_iter_count(&io_data->data)) if (ret != io_data->req->actual && iov_iter_count(&io_data->data))
ret = -EFAULT; ret = -EFAULT;
unuse_mm(io_data->mm); unuse_mm(io_data->mm);
} }
......
...@@ -2977,25 +2977,6 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, ...@@ -2977,25 +2977,6 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn,
} }
EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string); EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string);
int fsg_common_run_thread(struct fsg_common *common)
{
common->state = FSG_STATE_IDLE;
/* Tell the thread to start working */
common->thread_task =
kthread_create(fsg_main_thread, common, "file-storage");
if (IS_ERR(common->thread_task)) {
common->state = FSG_STATE_TERMINATED;
return PTR_ERR(common->thread_task);
}
DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
wake_up_process(common->thread_task);
return 0;
}
EXPORT_SYMBOL_GPL(fsg_common_run_thread);
static void fsg_common_release(struct kref *ref) static void fsg_common_release(struct kref *ref)
{ {
struct fsg_common *common = container_of(ref, struct fsg_common, ref); struct fsg_common *common = container_of(ref, struct fsg_common, ref);
...@@ -3005,6 +2986,7 @@ static void fsg_common_release(struct kref *ref) ...@@ -3005,6 +2986,7 @@ static void fsg_common_release(struct kref *ref)
if (common->state != FSG_STATE_TERMINATED) { if (common->state != FSG_STATE_TERMINATED) {
raise_exception(common, FSG_STATE_EXIT); raise_exception(common, FSG_STATE_EXIT);
wait_for_completion(&common->thread_notifier); wait_for_completion(&common->thread_notifier);
common->thread_task = NULL;
} }
for (i = 0; i < ARRAY_SIZE(common->luns); ++i) { for (i = 0; i < ARRAY_SIZE(common->luns); ++i) {
...@@ -3050,9 +3032,21 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -3050,9 +3032,21 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
if (ret) if (ret)
return ret; return ret;
fsg_common_set_inquiry_string(fsg->common, NULL, NULL); fsg_common_set_inquiry_string(fsg->common, NULL, NULL);
ret = fsg_common_run_thread(fsg->common); }
if (ret)
if (!common->thread_task) {
common->state = FSG_STATE_IDLE;
common->thread_task =
kthread_create(fsg_main_thread, common, "file-storage");
if (IS_ERR(common->thread_task)) {
int ret = PTR_ERR(common->thread_task);
common->thread_task = NULL;
common->state = FSG_STATE_TERMINATED;
return ret; return ret;
}
DBG(common, "I/O thread pid: %d\n",
task_pid_nr(common->thread_task));
wake_up_process(common->thread_task);
} }
fsg->gadget = gadget; fsg->gadget = gadget;
......
...@@ -153,8 +153,6 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg); ...@@ -153,8 +153,6 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg);
void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn,
const char *pn); const char *pn);
int fsg_common_run_thread(struct fsg_common *common);
void fsg_config_from_params(struct fsg_config *cfg, void fsg_config_from_params(struct fsg_config *cfg,
const struct fsg_module_parameters *params, const struct fsg_module_parameters *params,
unsigned int fsg_num_buffers); unsigned int fsg_num_buffers);
......
...@@ -133,10 +133,6 @@ static int acm_ms_do_config(struct usb_configuration *c) ...@@ -133,10 +133,6 @@ static int acm_ms_do_config(struct usb_configuration *c)
if (status < 0) if (status < 0)
goto put_msg; goto put_msg;
status = fsg_common_run_thread(opts->common);
if (status)
goto remove_acm;
status = usb_add_function(c, f_msg); status = usb_add_function(c, f_msg);
if (status) if (status)
goto remove_acm; goto remove_acm;
......
...@@ -132,10 +132,6 @@ static int msg_do_config(struct usb_configuration *c) ...@@ -132,10 +132,6 @@ static int msg_do_config(struct usb_configuration *c)
if (IS_ERR(f_msg)) if (IS_ERR(f_msg))
return PTR_ERR(f_msg); return PTR_ERR(f_msg);
ret = fsg_common_run_thread(opts->common);
if (ret)
goto put_func;
ret = usb_add_function(c, f_msg); ret = usb_add_function(c, f_msg);
if (ret) if (ret)
goto put_func; goto put_func;
......
...@@ -137,7 +137,6 @@ static struct usb_function *f_msg_rndis; ...@@ -137,7 +137,6 @@ static struct usb_function *f_msg_rndis;
static int rndis_do_config(struct usb_configuration *c) static int rndis_do_config(struct usb_configuration *c)
{ {
struct fsg_opts *fsg_opts;
int ret; int ret;
if (gadget_is_otg(c->cdev->gadget)) { if (gadget_is_otg(c->cdev->gadget)) {
...@@ -169,11 +168,6 @@ static int rndis_do_config(struct usb_configuration *c) ...@@ -169,11 +168,6 @@ static int rndis_do_config(struct usb_configuration *c)
goto err_fsg; goto err_fsg;
} }
fsg_opts = fsg_opts_from_func_inst(fi_msg);
ret = fsg_common_run_thread(fsg_opts->common);
if (ret)
goto err_run;
ret = usb_add_function(c, f_msg_rndis); ret = usb_add_function(c, f_msg_rndis);
if (ret) if (ret)
goto err_run; goto err_run;
...@@ -225,7 +219,6 @@ static struct usb_function *f_msg_multi; ...@@ -225,7 +219,6 @@ static struct usb_function *f_msg_multi;
static int cdc_do_config(struct usb_configuration *c) static int cdc_do_config(struct usb_configuration *c)
{ {
struct fsg_opts *fsg_opts;
int ret; int ret;
if (gadget_is_otg(c->cdev->gadget)) { if (gadget_is_otg(c->cdev->gadget)) {
...@@ -258,11 +251,6 @@ static int cdc_do_config(struct usb_configuration *c) ...@@ -258,11 +251,6 @@ static int cdc_do_config(struct usb_configuration *c)
goto err_fsg; goto err_fsg;
} }
fsg_opts = fsg_opts_from_func_inst(fi_msg);
ret = fsg_common_run_thread(fsg_opts->common);
if (ret)
goto err_run;
ret = usb_add_function(c, f_msg_multi); ret = usb_add_function(c, f_msg_multi);
if (ret) if (ret)
goto err_run; goto err_run;
......
...@@ -152,7 +152,6 @@ static int nokia_bind_config(struct usb_configuration *c) ...@@ -152,7 +152,6 @@ static int nokia_bind_config(struct usb_configuration *c)
struct usb_function *f_ecm; struct usb_function *f_ecm;
struct usb_function *f_obex2 = NULL; struct usb_function *f_obex2 = NULL;
struct usb_function *f_msg; struct usb_function *f_msg;
struct fsg_opts *fsg_opts;
int status = 0; int status = 0;
int obex1_stat = -1; int obex1_stat = -1;
int obex2_stat = -1; int obex2_stat = -1;
...@@ -222,12 +221,6 @@ static int nokia_bind_config(struct usb_configuration *c) ...@@ -222,12 +221,6 @@ static int nokia_bind_config(struct usb_configuration *c)
goto err_ecm; goto err_ecm;
} }
fsg_opts = fsg_opts_from_func_inst(fi_msg);
status = fsg_common_run_thread(fsg_opts->common);
if (status)
goto err_msg;
status = usb_add_function(c, f_msg); status = usb_add_function(c, f_msg);
if (status) if (status)
goto err_msg; goto err_msg;
......
...@@ -1726,10 +1726,7 @@ static int at91sam9261_udc_init(struct at91_udc *udc) ...@@ -1726,10 +1726,7 @@ static int at91sam9261_udc_init(struct at91_udc *udc)
udc->matrix = syscon_regmap_lookup_by_phandle(udc->pdev->dev.of_node, udc->matrix = syscon_regmap_lookup_by_phandle(udc->pdev->dev.of_node,
"atmel,matrix"); "atmel,matrix");
if (IS_ERR(udc->matrix)) return PTR_ERR_OR_ZERO(udc->matrix);
return PTR_ERR(udc->matrix);
return 0;
} }
static void at91sam9261_udc_pullup(struct at91_udc *udc, int is_on) static void at91sam9261_udc_pullup(struct at91_udc *udc, int is_on)
......
...@@ -325,11 +325,8 @@ struct pch_vbus_gpio_data { ...@@ -325,11 +325,8 @@ struct pch_vbus_gpio_data {
* @pdev: reference to the PCI device * @pdev: reference to the PCI device
* @ep: array of endpoints * @ep: array of endpoints
* @lock: protects all state * @lock: protects all state
* @active: enabled the PCI device
* @stall: stall requested * @stall: stall requested
* @prot_stall: protcol stall requested * @prot_stall: protcol stall requested
* @irq_registered: irq registered with system
* @mem_region: device memory mapped
* @registered: driver registered with system * @registered: driver registered with system
* @suspended: driver in suspended state * @suspended: driver in suspended state
* @connected: gadget driver associated * @connected: gadget driver associated
...@@ -339,12 +336,8 @@ struct pch_vbus_gpio_data { ...@@ -339,12 +336,8 @@ struct pch_vbus_gpio_data {
* @data_requests: DMA pool for data requests * @data_requests: DMA pool for data requests
* @stp_requests: DMA pool for setup requests * @stp_requests: DMA pool for setup requests
* @dma_addr: DMA pool for received * @dma_addr: DMA pool for received
* @ep0out_buf: Buffer for DMA
* @setup_data: Received setup data * @setup_data: Received setup data
* @phys_addr: of device memory
* @base_addr: for mapped device memory * @base_addr: for mapped device memory
* @bar: Indicates which PCI BAR for USB regs
* @irq: IRQ line for the device
* @cfg_data: current cfg, intf, and alt in use * @cfg_data: current cfg, intf, and alt in use
* @vbus_gpio: GPIO informaton for detecting VBUS * @vbus_gpio: GPIO informaton for detecting VBUS
*/ */
...@@ -354,11 +347,9 @@ struct pch_udc_dev { ...@@ -354,11 +347,9 @@ struct pch_udc_dev {
struct pci_dev *pdev; struct pci_dev *pdev;
struct pch_udc_ep ep[PCH_UDC_EP_NUM]; struct pch_udc_ep ep[PCH_UDC_EP_NUM];
spinlock_t lock; /* protects all state */ spinlock_t lock; /* protects all state */
unsigned active:1, unsigned
stall:1, stall:1,
prot_stall:1, prot_stall:1,
irq_registered:1,
mem_region:1,
suspended:1, suspended:1,
connected:1, connected:1,
vbus_session:1, vbus_session:1,
...@@ -367,12 +358,8 @@ struct pch_udc_dev { ...@@ -367,12 +358,8 @@ struct pch_udc_dev {
struct pci_pool *data_requests; struct pci_pool *data_requests;
struct pci_pool *stp_requests; struct pci_pool *stp_requests;
dma_addr_t dma_addr; dma_addr_t dma_addr;
void *ep0out_buf;
struct usb_ctrlrequest setup_data; struct usb_ctrlrequest setup_data;
unsigned long phys_addr;
void __iomem *base_addr; void __iomem *base_addr;
unsigned bar;
unsigned irq;
struct pch_udc_cfg_data cfg_data; struct pch_udc_cfg_data cfg_data;
struct pch_vbus_gpio_data vbus_gpio; struct pch_vbus_gpio_data vbus_gpio;
}; };
...@@ -380,8 +367,10 @@ struct pch_udc_dev { ...@@ -380,8 +367,10 @@ struct pch_udc_dev {
#define PCH_UDC_PCI_BAR_QUARK_X1000 0 #define PCH_UDC_PCI_BAR_QUARK_X1000 0
#define PCH_UDC_PCI_BAR 1 #define PCH_UDC_PCI_BAR 1
#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808
#define PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC 0x0939 #define PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC 0x0939
#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808
#define PCI_VENDOR_ID_ROHM 0x10DB #define PCI_VENDOR_ID_ROHM 0x10DB
#define PCI_DEVICE_ID_ML7213_IOH_UDC 0x801D #define PCI_DEVICE_ID_ML7213_IOH_UDC 0x801D
#define PCI_DEVICE_ID_ML7831_IOH_UDC 0x8808 #define PCI_DEVICE_ID_ML7831_IOH_UDC 0x8808
...@@ -1732,14 +1721,12 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep, ...@@ -1732,14 +1721,12 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep,
static int pch_udc_pcd_ep_disable(struct usb_ep *usbep) static int pch_udc_pcd_ep_disable(struct usb_ep *usbep)
{ {
struct pch_udc_ep *ep; struct pch_udc_ep *ep;
struct pch_udc_dev *dev;
unsigned long iflags; unsigned long iflags;
if (!usbep) if (!usbep)
return -EINVAL; return -EINVAL;
ep = container_of(usbep, struct pch_udc_ep, ep); ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
if ((usbep->name == ep0_string) || !ep->ep.desc) if ((usbep->name == ep0_string) || !ep->ep.desc)
return -EINVAL; return -EINVAL;
...@@ -1770,12 +1757,10 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep, ...@@ -1770,12 +1757,10 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep,
struct pch_udc_request *req; struct pch_udc_request *req;
struct pch_udc_ep *ep; struct pch_udc_ep *ep;
struct pch_udc_data_dma_desc *dma_desc; struct pch_udc_data_dma_desc *dma_desc;
struct pch_udc_dev *dev;
if (!usbep) if (!usbep)
return NULL; return NULL;
ep = container_of(usbep, struct pch_udc_ep, ep); ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
req = kzalloc(sizeof *req, gfp); req = kzalloc(sizeof *req, gfp);
if (!req) if (!req)
return NULL; return NULL;
...@@ -1948,12 +1933,10 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep, ...@@ -1948,12 +1933,10 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep,
{ {
struct pch_udc_ep *ep; struct pch_udc_ep *ep;
struct pch_udc_request *req; struct pch_udc_request *req;
struct pch_udc_dev *dev;
unsigned long flags; unsigned long flags;
int ret = -EINVAL; int ret = -EINVAL;
ep = container_of(usbep, struct pch_udc_ep, ep); ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
if (!usbep || !usbreq || (!ep->ep.desc && ep->num)) if (!usbep || !usbreq || (!ep->ep.desc && ep->num))
return ret; return ret;
req = container_of(usbreq, struct pch_udc_request, req); req = container_of(usbreq, struct pch_udc_request, req);
...@@ -1985,14 +1968,12 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep, ...@@ -1985,14 +1968,12 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep,
static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt) static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
{ {
struct pch_udc_ep *ep; struct pch_udc_ep *ep;
struct pch_udc_dev *dev;
unsigned long iflags; unsigned long iflags;
int ret; int ret;
if (!usbep) if (!usbep)
return -EINVAL; return -EINVAL;
ep = container_of(usbep, struct pch_udc_ep, ep); ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
if (!ep->ep.desc && !ep->num) if (!ep->ep.desc && !ep->num)
return -EINVAL; return -EINVAL;
if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
...@@ -2030,14 +2011,12 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt) ...@@ -2030,14 +2011,12 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
static int pch_udc_pcd_set_wedge(struct usb_ep *usbep) static int pch_udc_pcd_set_wedge(struct usb_ep *usbep)
{ {
struct pch_udc_ep *ep; struct pch_udc_ep *ep;
struct pch_udc_dev *dev;
unsigned long iflags; unsigned long iflags;
int ret; int ret;
if (!usbep) if (!usbep)
return -EINVAL; return -EINVAL;
ep = container_of(usbep, struct pch_udc_ep, ep); ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
if (!ep->ep.desc && !ep->num) if (!ep->ep.desc && !ep->num)
return -EINVAL; return -EINVAL;
if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
...@@ -2647,7 +2626,7 @@ static void pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev) ...@@ -2647,7 +2626,7 @@ static void pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev)
static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
{ {
u32 reg, dev_stat = 0; u32 reg, dev_stat = 0;
int i, ret; int i;
dev_stat = pch_udc_read_device_status(dev); dev_stat = pch_udc_read_device_status(dev);
dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >> dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >>
...@@ -2676,7 +2655,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) ...@@ -2676,7 +2655,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
} }
dev->stall = 0; dev->stall = 0;
spin_lock(&dev->lock); spin_lock(&dev->lock);
ret = dev->driver->setup(&dev->gadget, &dev->setup_data); dev->driver->setup(&dev->gadget, &dev->setup_data);
spin_unlock(&dev->lock); spin_unlock(&dev->lock);
} }
...@@ -2687,7 +2666,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) ...@@ -2687,7 +2666,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
*/ */
static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
{ {
int i, ret; int i;
u32 reg, dev_stat = 0; u32 reg, dev_stat = 0;
dev_stat = pch_udc_read_device_status(dev); dev_stat = pch_udc_read_device_status(dev);
...@@ -2713,7 +2692,7 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) ...@@ -2713,7 +2692,7 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
/* call gadget zero with setup data received */ /* call gadget zero with setup data received */
spin_lock(&dev->lock); spin_lock(&dev->lock);
ret = dev->driver->setup(&dev->gadget, &dev->setup_data); dev->driver->setup(&dev->gadget, &dev->setup_data);
spin_unlock(&dev->lock); spin_unlock(&dev->lock);
} }
...@@ -2855,17 +2834,6 @@ static void pch_udc_setup_ep0(struct pch_udc_dev *dev) ...@@ -2855,17 +2834,6 @@ static void pch_udc_setup_ep0(struct pch_udc_dev *dev)
UDC_DEVINT_SI | UDC_DEVINT_SC); UDC_DEVINT_SI | UDC_DEVINT_SC);
} }
/**
* gadget_release() - Free the gadget driver private data
* @pdev reference to struct pci_dev
*/
static void gadget_release(struct device *pdev)
{
struct pch_udc_dev *dev = dev_get_drvdata(pdev);
kfree(dev);
}
/** /**
* pch_udc_pcd_reinit() - This API initializes the endpoint structures * pch_udc_pcd_reinit() - This API initializes the endpoint structures
* @dev: Reference to the driver structure * @dev: Reference to the driver structure
...@@ -2949,6 +2917,7 @@ static int init_dma_pools(struct pch_udc_dev *dev) ...@@ -2949,6 +2917,7 @@ static int init_dma_pools(struct pch_udc_dev *dev)
{ {
struct pch_udc_stp_dma_desc *td_stp; struct pch_udc_stp_dma_desc *td_stp;
struct pch_udc_data_dma_desc *td_data; struct pch_udc_data_dma_desc *td_data;
void *ep0out_buf;
/* DMA setup */ /* DMA setup */
dev->data_requests = pci_pool_create("data_requests", dev->pdev, dev->data_requests = pci_pool_create("data_requests", dev->pdev,
...@@ -2991,10 +2960,11 @@ static int init_dma_pools(struct pch_udc_dev *dev) ...@@ -2991,10 +2960,11 @@ static int init_dma_pools(struct pch_udc_dev *dev)
dev->ep[UDC_EP0IN_IDX].td_data = NULL; dev->ep[UDC_EP0IN_IDX].td_data = NULL;
dev->ep[UDC_EP0IN_IDX].td_data_phys = 0; dev->ep[UDC_EP0IN_IDX].td_data_phys = 0;
dev->ep0out_buf = kzalloc(UDC_EP0OUT_BUFF_SIZE * 4, GFP_KERNEL); ep0out_buf = devm_kzalloc(&dev->pdev->dev, UDC_EP0OUT_BUFF_SIZE * 4,
if (!dev->ep0out_buf) GFP_KERNEL);
if (!ep0out_buf)
return -ENOMEM; return -ENOMEM;
dev->dma_addr = dma_map_single(&dev->pdev->dev, dev->ep0out_buf, dev->dma_addr = dma_map_single(&dev->pdev->dev, ep0out_buf,
UDC_EP0OUT_BUFF_SIZE * 4, UDC_EP0OUT_BUFF_SIZE * 4,
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
return 0; return 0;
...@@ -3078,129 +3048,80 @@ static void pch_udc_remove(struct pci_dev *pdev) ...@@ -3078,129 +3048,80 @@ static void pch_udc_remove(struct pci_dev *pdev)
if (dev->dma_addr) if (dev->dma_addr)
dma_unmap_single(&dev->pdev->dev, dev->dma_addr, dma_unmap_single(&dev->pdev->dev, dev->dma_addr,
UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE); UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE);
kfree(dev->ep0out_buf);
pch_vbus_gpio_free(dev); pch_vbus_gpio_free(dev);
pch_udc_exit(dev); pch_udc_exit(dev);
if (dev->irq_registered)
free_irq(pdev->irq, dev);
if (dev->base_addr)
iounmap(dev->base_addr);
if (dev->mem_region)
release_mem_region(dev->phys_addr,
pci_resource_len(pdev, dev->bar));
if (dev->active)
pci_disable_device(pdev);
kfree(dev);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int pch_udc_suspend(struct pci_dev *pdev, pm_message_t state) static int pch_udc_suspend(struct device *d)
{ {
struct pci_dev *pdev = to_pci_dev(d);
struct pch_udc_dev *dev = pci_get_drvdata(pdev); struct pch_udc_dev *dev = pci_get_drvdata(pdev);
pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK); pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL); pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL);
pci_disable_device(pdev);
pci_enable_wake(pdev, PCI_D3hot, 0);
if (pci_save_state(pdev)) {
dev_err(&pdev->dev,
"%s: could not save PCI config state\n", __func__);
return -ENOMEM;
}
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0; return 0;
} }
static int pch_udc_resume(struct pci_dev *pdev) static int pch_udc_resume(struct device *d)
{ {
int ret;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
ret = pci_enable_device(pdev);
if (ret) {
dev_err(&pdev->dev, "%s: pci_enable_device failed\n", __func__);
return ret;
}
pci_enable_wake(pdev, PCI_D3hot, 0);
return 0; return 0;
} }
static SIMPLE_DEV_PM_OPS(pch_udc_pm, pch_udc_suspend, pch_udc_resume);
#define PCH_UDC_PM_OPS (&pch_udc_pm)
#else #else
#define pch_udc_suspend NULL #define PCH_UDC_PM_OPS NULL
#define pch_udc_resume NULL #endif /* CONFIG_PM_SLEEP */
#endif /* CONFIG_PM */
static int pch_udc_probe(struct pci_dev *pdev, static int pch_udc_probe(struct pci_dev *pdev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
unsigned long resource; int bar;
unsigned long len;
int retval; int retval;
struct pch_udc_dev *dev; struct pch_udc_dev *dev;
/* init */ /* init */
dev = kzalloc(sizeof *dev, GFP_KERNEL); dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev) { if (!dev)
pr_err("%s: no memory for device structure\n", __func__);
return -ENOMEM; return -ENOMEM;
}
/* pci setup */ /* pci setup */
if (pci_enable_device(pdev) < 0) { retval = pcim_enable_device(pdev);
kfree(dev); if (retval)
pr_err("%s: pci_enable_device failed\n", __func__); return retval;
return -ENODEV;
}
dev->active = 1;
pci_set_drvdata(pdev, dev); pci_set_drvdata(pdev, dev);
/* Determine BAR based on PCI ID */ /* Determine BAR based on PCI ID */
if (id->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC) if (id->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC)
dev->bar = PCH_UDC_PCI_BAR_QUARK_X1000; bar = PCH_UDC_PCI_BAR_QUARK_X1000;
else else
dev->bar = PCH_UDC_PCI_BAR; bar = PCH_UDC_PCI_BAR;
/* PCI resource allocation */ /* PCI resource allocation */
resource = pci_resource_start(pdev, dev->bar); retval = pcim_iomap_regions(pdev, 1 << bar, pci_name(pdev));
len = pci_resource_len(pdev, dev->bar); if (retval)
return retval;
if (!request_mem_region(resource, len, KBUILD_MODNAME)) { dev->base_addr = pcim_iomap_table(pdev)[bar];
dev_err(&pdev->dev, "%s: pci device used already\n", __func__);
retval = -EBUSY;
goto finished;
}
dev->phys_addr = resource;
dev->mem_region = 1;
dev->base_addr = ioremap_nocache(resource, len);
if (!dev->base_addr) {
pr_err("%s: device memory cannot be mapped\n", __func__);
retval = -ENOMEM;
goto finished;
}
if (!pdev->irq) {
dev_err(&pdev->dev, "%s: irq not set\n", __func__);
retval = -ENODEV;
goto finished;
}
/* initialize the hardware */ /* initialize the hardware */
if (pch_udc_pcd_init(dev)) { if (pch_udc_pcd_init(dev))
retval = -ENODEV; return -ENODEV;
goto finished;
} pci_enable_msi(pdev);
if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME,
dev)) { retval = devm_request_irq(&pdev->dev, pdev->irq, pch_udc_isr,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (retval) {
dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__, dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__,
pdev->irq); pdev->irq);
retval = -ENODEV;
goto finished; goto finished;
} }
dev->irq = pdev->irq;
dev->irq_registered = 1;
pci_set_master(pdev); pci_set_master(pdev);
pci_try_set_mwi(pdev); pci_try_set_mwi(pdev);
...@@ -3219,8 +3140,7 @@ static int pch_udc_probe(struct pci_dev *pdev, ...@@ -3219,8 +3140,7 @@ static int pch_udc_probe(struct pci_dev *pdev,
/* Put the device in disconnected state till a driver is bound */ /* Put the device in disconnected state till a driver is bound */
pch_udc_set_disconnect(dev); pch_udc_set_disconnect(dev);
retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget, retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
gadget_release);
if (retval) if (retval)
goto finished; goto finished;
return 0; return 0;
...@@ -3262,9 +3182,10 @@ static struct pci_driver pch_udc_driver = { ...@@ -3262,9 +3182,10 @@ static struct pci_driver pch_udc_driver = {
.id_table = pch_udc_pcidev_id, .id_table = pch_udc_pcidev_id,
.probe = pch_udc_probe, .probe = pch_udc_probe,
.remove = pch_udc_remove, .remove = pch_udc_remove,
.suspend = pch_udc_suspend,
.resume = pch_udc_resume,
.shutdown = pch_udc_shutdown, .shutdown = pch_udc_shutdown,
.driver = {
.pm = PCH_UDC_PM_OPS,
},
}; };
module_pci_driver(pch_udc_driver); module_pci_driver(pch_udc_driver);
......
...@@ -296,7 +296,7 @@ static void r8a66597_change_curpipe(struct r8a66597 *r8a66597, u16 pipenum, ...@@ -296,7 +296,7 @@ static void r8a66597_change_curpipe(struct r8a66597 *r8a66597, u16 pipenum,
} while ((tmp & mask) != loop); } while ((tmp & mask) != loop);
} }
static inline void pipe_change(struct r8a66597 *r8a66597, u16 pipenum) static void pipe_change(struct r8a66597 *r8a66597, u16 pipenum)
{ {
struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum]; struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum];
......
...@@ -61,11 +61,9 @@ static int udc_bind_to_driver(struct usb_udc *udc, ...@@ -61,11 +61,9 @@ static int udc_bind_to_driver(struct usb_udc *udc,
#ifdef CONFIG_HAS_DMA #ifdef CONFIG_HAS_DMA
int usb_gadget_map_request(struct usb_gadget *gadget, int usb_gadget_map_request_by_dev(struct device *dev,
struct usb_request *req, int is_in) struct usb_request *req, int is_in)
{ {
struct device *dev = gadget->dev.parent;
if (req->length == 0) if (req->length == 0)
return 0; return 0;
...@@ -75,7 +73,7 @@ int usb_gadget_map_request(struct usb_gadget *gadget, ...@@ -75,7 +73,7 @@ int usb_gadget_map_request(struct usb_gadget *gadget,
mapped = dma_map_sg(dev, req->sg, req->num_sgs, mapped = dma_map_sg(dev, req->sg, req->num_sgs,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (mapped == 0) { if (mapped == 0) {
dev_err(&gadget->dev, "failed to map SGs\n"); dev_err(dev, "failed to map SGs\n");
return -EFAULT; return -EFAULT;
} }
...@@ -92,24 +90,38 @@ int usb_gadget_map_request(struct usb_gadget *gadget, ...@@ -92,24 +90,38 @@ int usb_gadget_map_request(struct usb_gadget *gadget,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev);
int usb_gadget_map_request(struct usb_gadget *gadget,
struct usb_request *req, int is_in)
{
return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in);
}
EXPORT_SYMBOL_GPL(usb_gadget_map_request); EXPORT_SYMBOL_GPL(usb_gadget_map_request);
void usb_gadget_unmap_request(struct usb_gadget *gadget, void usb_gadget_unmap_request_by_dev(struct device *dev,
struct usb_request *req, int is_in) struct usb_request *req, int is_in)
{ {
if (req->length == 0) if (req->length == 0)
return; return;
if (req->num_mapped_sgs) { if (req->num_mapped_sgs) {
dma_unmap_sg(gadget->dev.parent, req->sg, req->num_mapped_sgs, dma_unmap_sg(dev, req->sg, req->num_mapped_sgs,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->num_mapped_sgs = 0; req->num_mapped_sgs = 0;
} else { } else {
dma_unmap_single(gadget->dev.parent, req->dma, req->length, dma_unmap_single(dev, req->dma, req->length,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
} }
} }
EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev);
void usb_gadget_unmap_request(struct usb_gadget *gadget,
struct usb_request *req, int is_in)
{
usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in);
}
EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
#endif /* CONFIG_HAS_DMA */ #endif /* CONFIG_HAS_DMA */
......
...@@ -35,6 +35,7 @@ config USB_XHCI_PCI ...@@ -35,6 +35,7 @@ config USB_XHCI_PCI
config USB_XHCI_PLATFORM config USB_XHCI_PLATFORM
tristate "Generic xHCI driver for a platform device" tristate "Generic xHCI driver for a platform device"
select USB_XHCI_RCAR if ARCH_RENESAS
---help--- ---help---
Adds an xHCI host driver for a generic platform device, which Adds an xHCI host driver for a generic platform device, which
provides a memory space and an irq. provides a memory space and an irq.
...@@ -63,7 +64,7 @@ config USB_XHCI_MVEBU ...@@ -63,7 +64,7 @@ config USB_XHCI_MVEBU
config USB_XHCI_RCAR config USB_XHCI_RCAR
tristate "xHCI support for Renesas R-Car SoCs" tristate "xHCI support for Renesas R-Car SoCs"
select USB_XHCI_PLATFORM depends on USB_XHCI_PLATFORM
depends on ARCH_RENESAS || COMPILE_TEST depends on ARCH_RENESAS || COMPILE_TEST
---help--- ---help---
Say 'Y' to enable the support for the xHCI host controller Say 'Y' to enable the support for the xHCI host controller
......
...@@ -352,10 +352,8 @@ static int bcma_hcd_probe(struct bcma_device *core) ...@@ -352,10 +352,8 @@ static int bcma_hcd_probe(struct bcma_device *core)
usb_dev->core = core; usb_dev->core = core;
if (core->dev.of_node) if (core->dev.of_node)
usb_dev->gpio_desc = devm_get_gpiod_from_child(&core->dev, "vcc", usb_dev->gpio_desc = devm_gpiod_get(&core->dev, "vcc",
&core->dev.of_node->fwnode); GPIOD_OUT_HIGH);
if (!IS_ERR_OR_NULL(usb_dev->gpio_desc))
gpiod_direction_output(usb_dev->gpio_desc, 1);
switch (core->id.id) { switch (core->id.id) {
case BCMA_CORE_USB20_HOST: case BCMA_CORE_USB20_HOST:
......
...@@ -52,13 +52,6 @@ static void dbg_hcs_params(struct ehci_hcd *ehci, char *label) ...@@ -52,13 +52,6 @@ static void dbg_hcs_params(struct ehci_hcd *ehci, char *label)
ehci_dbg(ehci, "%s portroute %s\n", label, buf); ehci_dbg(ehci, "%s portroute %s\n", label, buf);
} }
} }
#else
static inline void dbg_hcs_params(struct ehci_hcd *ehci, char *label) {}
#endif
#ifdef CONFIG_DYNAMIC_DEBUG
/* /*
* check the values in the HCCPARAMS register * check the values in the HCCPARAMS register
...@@ -92,13 +85,6 @@ static void dbg_hcc_params(struct ehci_hcd *ehci, char *label) ...@@ -92,13 +85,6 @@ static void dbg_hcc_params(struct ehci_hcd *ehci, char *label)
" 32 periodic list" : ""); " 32 periodic list" : "");
} }
} }
#else
static inline void dbg_hcc_params(struct ehci_hcd *ehci, char *label) {}
#endif
#ifdef CONFIG_DYNAMIC_DEBUG
static void __maybe_unused static void __maybe_unused
dbg_qtd(const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd) dbg_qtd(const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
...@@ -281,37 +267,6 @@ dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status) ...@@ -281,37 +267,6 @@ dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
(status & PORT_CONNECT) ? " CONNECT" : ""); (status & PORT_CONNECT) ? " CONNECT" : "");
} }
#else
static inline void __maybe_unused
dbg_qh(char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
{}
static inline int __maybe_unused
dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
{
return 0;
}
static inline int __maybe_unused
dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
{
return 0;
}
static inline int __maybe_unused
dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
{
return 0;
}
static inline int __maybe_unused
dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
{
return 0;
}
#endif /* CONFIG_DYNAMIC_DEBUG */
static inline void static inline void
dbg_status(struct ehci_hcd *ehci, const char *label, u32 status) dbg_status(struct ehci_hcd *ehci, const char *label, u32 status)
{ {
...@@ -341,13 +296,6 @@ dbg_port(struct ehci_hcd *ehci, const char *label, int port, u32 status) ...@@ -341,13 +296,6 @@ dbg_port(struct ehci_hcd *ehci, const char *label, int port, u32 status)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#ifndef CONFIG_DYNAMIC_DEBUG
static inline void create_debug_files(struct ehci_hcd *bus) { }
static inline void remove_debug_files(struct ehci_hcd *bus) { }
#else
/* troubleshooting help: expose state in debugfs */ /* troubleshooting help: expose state in debugfs */
static int debug_async_open(struct inode *, struct file *); static int debug_async_open(struct inode *, struct file *);
...@@ -1120,4 +1068,38 @@ static inline void remove_debug_files(struct ehci_hcd *ehci) ...@@ -1120,4 +1068,38 @@ static inline void remove_debug_files(struct ehci_hcd *ehci)
debugfs_remove_recursive(ehci->debug_dir); debugfs_remove_recursive(ehci->debug_dir);
} }
#else /* CONFIG_DYNAMIC_DEBUG */
static inline void dbg_hcs_params(struct ehci_hcd *ehci, char *label) { }
static inline void dbg_hcc_params(struct ehci_hcd *ehci, char *label) { }
static inline void __maybe_unused dbg_qh(const char *label,
struct ehci_hcd *ehci, struct ehci_qh *qh) { }
static inline int __maybe_unused dbg_status_buf(const char *buf,
unsigned int len, const char *label, u32 status)
{ return 0; }
static inline int __maybe_unused dbg_command_buf(const char *buf,
unsigned int len, const char *label, u32 command)
{ return 0; }
static inline int __maybe_unused dbg_intr_buf(const char *buf,
unsigned int len, const char *label, u32 enable)
{ return 0; }
static inline int __maybe_unused dbg_port_buf(char *buf,
unsigned int len, const char *label, int port, u32 status)
{ return 0; }
static inline void dbg_status(struct ehci_hcd *ehci, const char *label,
u32 status) { }
static inline void dbg_cmd(struct ehci_hcd *ehci, const char *label,
u32 command) { }
static inline void dbg_port(struct ehci_hcd *ehci, const char *label,
int port, u32 status) { }
static inline void create_debug_files(struct ehci_hcd *bus) { }
static inline void remove_debug_files(struct ehci_hcd *bus) { }
#endif /* CONFIG_DYNAMIC_DEBUG */ #endif /* CONFIG_DYNAMIC_DEBUG */
...@@ -321,7 +321,7 @@ static struct platform_driver exynos_ehci_driver = { ...@@ -321,7 +321,7 @@ static struct platform_driver exynos_ehci_driver = {
.of_match_table = of_match_ptr(exynos_ehci_match), .of_match_table = of_match_ptr(exynos_ehci_match),
} }
}; };
static const struct ehci_driver_overrides exynos_overrides __initdata = { static const struct ehci_driver_overrides exynos_overrides __initconst = {
.extra_priv_size = sizeof(struct exynos_ehci_hcd), .extra_priv_size = sizeof(struct exynos_ehci_hcd),
}; };
......
...@@ -229,7 +229,7 @@ static struct platform_driver ehci_msm_driver = { ...@@ -229,7 +229,7 @@ static struct platform_driver ehci_msm_driver = {
}, },
}; };
static const struct ehci_driver_overrides msm_overrides __initdata = { static const struct ehci_driver_overrides msm_overrides __initconst = {
.reset = ehci_msm_reset, .reset = ehci_msm_reset,
}; };
......
...@@ -86,7 +86,7 @@ static inline u32 ehci_read(void __iomem *base, u32 reg) ...@@ -86,7 +86,7 @@ static inline u32 ehci_read(void __iomem *base, u32 reg)
static struct hc_driver __read_mostly ehci_omap_hc_driver; static struct hc_driver __read_mostly ehci_omap_hc_driver;
static const struct ehci_driver_overrides ehci_omap_overrides __initdata = { static const struct ehci_driver_overrides ehci_omap_overrides __initconst = {
.extra_priv_size = sizeof(struct omap_hcd), .extra_priv_size = sizeof(struct omap_hcd),
}; };
......
...@@ -163,7 +163,7 @@ static struct platform_driver spear_ehci_hcd_driver = { ...@@ -163,7 +163,7 @@ static struct platform_driver spear_ehci_hcd_driver = {
} }
}; };
static const struct ehci_driver_overrides spear_overrides __initdata = { static const struct ehci_driver_overrides spear_overrides __initconst = {
.extra_priv_size = sizeof(struct spear_ehci), .extra_priv_size = sizeof(struct spear_ehci),
}; };
......
...@@ -288,7 +288,7 @@ static int scan_ed_list(struct fhci_usb *usb, ...@@ -288,7 +288,7 @@ static int scan_ed_list(struct fhci_usb *usb,
list_for_each_entry(ed, list, node) { list_for_each_entry(ed, list, node) {
td = ed->td_head; td = ed->td_head;
if (!td || (td && td->status == USB_TD_INPROGRESS)) if (!td || td->status == USB_TD_INPROGRESS)
continue; continue;
if (ed->state != FHCI_ED_OPER) { if (ed->state != FHCI_ED_OPER) {
......
...@@ -4795,14 +4795,8 @@ static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, ...@@ -4795,14 +4795,8 @@ static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max,
static inline int create_sysfs_files(struct fotg210_hcd *fotg210) static inline int create_sysfs_files(struct fotg210_hcd *fotg210)
{ {
struct device *controller = fotg210_to_hcd(fotg210)->self.controller; struct device *controller = fotg210_to_hcd(fotg210)->self.controller;
int i = 0;
if (i) return device_create_file(controller, &dev_attr_uframe_periodic_max);
goto out;
i = device_create_file(controller, &dev_attr_uframe_periodic_max);
out:
return i;
} }
static inline void remove_sysfs_files(struct fotg210_hcd *fotg210) static inline void remove_sysfs_files(struct fotg210_hcd *fotg210)
......
...@@ -257,14 +257,14 @@ static int whc_probe(struct umc_dev *umc) ...@@ -257,14 +257,14 @@ static int whc_probe(struct umc_dev *umc)
ret = whc_init(whc); ret = whc_init(whc);
if (ret) if (ret)
goto error; goto error_whc_init;
wusbhc->dev = dev; wusbhc->dev = dev;
wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent); wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent);
if (!wusbhc->uwb_rc) { if (!wusbhc->uwb_rc) {
ret = -ENODEV; ret = -ENODEV;
dev_err(dev, "cannot get radio controller\n"); dev_err(dev, "cannot get radio controller\n");
goto error; goto error_uwb_rc;
} }
if (whc->n_devices > USB_MAXCHILDREN) { if (whc->n_devices > USB_MAXCHILDREN) {
...@@ -311,8 +311,9 @@ static int whc_probe(struct umc_dev *umc) ...@@ -311,8 +311,9 @@ static int whc_probe(struct umc_dev *umc)
wusbhc_destroy(wusbhc); wusbhc_destroy(wusbhc);
error_wusbhc_create: error_wusbhc_create:
uwb_rc_put(wusbhc->uwb_rc); uwb_rc_put(wusbhc->uwb_rc);
error: error_uwb_rc:
whc_clean_up(whc); whc_clean_up(whc);
error_whc_init:
usb_put_hcd(usb_hcd); usb_put_hcd(usb_hcd);
return ret; return ret;
} }
......
...@@ -314,7 +314,7 @@ void qset_free_std(struct whc *whc, struct whc_std *std) ...@@ -314,7 +314,7 @@ void qset_free_std(struct whc *whc, struct whc_std *std)
kfree(std->bounce_buf); kfree(std->bounce_buf);
} }
if (std->pl_virt) { if (std->pl_virt) {
if (std->dma_addr) if (!dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
dma_unmap_single(whc->wusbhc.dev, std->dma_addr, dma_unmap_single(whc->wusbhc.dev, std->dma_addr,
std->num_pointers * sizeof(struct whc_page_list_entry), std->num_pointers * sizeof(struct whc_page_list_entry),
DMA_TO_DEVICE); DMA_TO_DEVICE);
...@@ -535,9 +535,11 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u ...@@ -535,9 +535,11 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u
list_for_each_entry(std, &qset->stds, list_node) { list_for_each_entry(std, &qset->stds, list_node) {
if (std->ntds_remaining == -1) { if (std->ntds_remaining == -1) {
pl_len = std->num_pointers * sizeof(struct whc_page_list_entry); pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
std->ntds_remaining = ntds--;
std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt,
pl_len, DMA_TO_DEVICE); pl_len, DMA_TO_DEVICE);
if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
return -EFAULT;
std->ntds_remaining = ntds--;
} }
} }
return 0; return 0;
...@@ -618,6 +620,8 @@ static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset, ...@@ -618,6 +620,8 @@ static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset,
std->dma_addr = dma_map_single(&whc->umc->dev, std->bounce_buf, std->len, std->dma_addr = dma_map_single(&whc->umc->dev, std->bounce_buf, std->len,
is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE); is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (dma_mapping_error(&whc->umc->dev, std->dma_addr))
return -EFAULT;
if (qset_fill_page_list(whc, std, mem_flags) < 0) if (qset_fill_page_list(whc, std, mem_flags) < 0)
return -ENOMEM; return -ENOMEM;
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include "xhci-mvebu.h" #include "xhci-mvebu.h"
#define USB3_MAX_WINDOWS 4 #define USB3_MAX_WINDOWS 4
...@@ -41,8 +44,10 @@ static void xhci_mvebu_mbus_config(void __iomem *base, ...@@ -41,8 +44,10 @@ static void xhci_mvebu_mbus_config(void __iomem *base,
} }
} }
int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev) int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
{ {
struct device *dev = hcd->self.controller;
struct platform_device *pdev = to_platform_device(dev);
struct resource *res; struct resource *res;
void __iomem *base; void __iomem *base;
const struct mbus_dram_target_info *dram; const struct mbus_dram_target_info *dram;
......
...@@ -10,10 +10,13 @@ ...@@ -10,10 +10,13 @@
#ifndef __LINUX_XHCI_MVEBU_H #ifndef __LINUX_XHCI_MVEBU_H
#define __LINUX_XHCI_MVEBU_H #define __LINUX_XHCI_MVEBU_H
struct usb_hcd;
#if IS_ENABLED(CONFIG_USB_XHCI_MVEBU) #if IS_ENABLED(CONFIG_USB_XHCI_MVEBU)
int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev); int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd);
#else #else
static inline int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev) static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
{ {
return 0; return 0;
} }
......
...@@ -37,27 +37,32 @@ static const struct xhci_driver_overrides xhci_plat_overrides __initconst = { ...@@ -37,27 +37,32 @@ static const struct xhci_driver_overrides xhci_plat_overrides __initconst = {
.start = xhci_plat_start, .start = xhci_plat_start,
}; };
static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) static void xhci_priv_plat_start(struct usb_hcd *hcd)
{
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
if (priv->plat_start)
priv->plat_start(hcd);
}
static int xhci_priv_init_quirk(struct usb_hcd *hcd)
{ {
struct usb_hcd *hcd = xhci_to_hcd(xhci); struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
if (!priv->init_quirk)
return 0;
return priv->init_quirk(hcd);
}
static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
{
/* /*
* As of now platform drivers don't provide MSI support so we ensure * As of now platform drivers don't provide MSI support so we ensure
* here that the generic code does not try to make a pci_dev from our * here that the generic code does not try to make a pci_dev from our
* dev struct in order to setup MSI * dev struct in order to setup MSI
*/ */
xhci->quirks |= XHCI_PLAT; xhci->quirks |= XHCI_PLAT;
/*
* On R-Car Gen2 and Gen3, the AC64 bit (bit 0) of HCCPARAMS1 is set
* to 1. However, these SoCs don't support 64-bit address memory
* pointers. So, this driver clears the AC64 bit of xhci->hcc_params
* to call dma_set_coherent_mask(dev, DMA_BIT_MASK(32)) in
* xhci_gen_setup().
*/
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) ||
xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3))
xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
} }
/* called during probe() after chip reset completes */ /* called during probe() after chip reset completes */
...@@ -65,38 +70,35 @@ static int xhci_plat_setup(struct usb_hcd *hcd) ...@@ -65,38 +70,35 @@ static int xhci_plat_setup(struct usb_hcd *hcd)
{ {
int ret; int ret;
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) ||
xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3)) { ret = xhci_priv_init_quirk(hcd);
ret = xhci_rcar_init_quirk(hcd); if (ret)
if (ret) return ret;
return ret;
}
return xhci_gen_setup(hcd, xhci_plat_quirks); return xhci_gen_setup(hcd, xhci_plat_quirks);
} }
static int xhci_plat_start(struct usb_hcd *hcd) static int xhci_plat_start(struct usb_hcd *hcd)
{ {
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2) || xhci_priv_plat_start(hcd);
xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3))
xhci_rcar_start(hcd);
return xhci_run(hcd); return xhci_run(hcd);
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct xhci_plat_priv xhci_plat_marvell_armada = { static const struct xhci_plat_priv xhci_plat_marvell_armada = {
.type = XHCI_PLAT_TYPE_MARVELL_ARMADA, .init_quirk = xhci_mvebu_mbus_init_quirk,
}; };
static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = { static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = {
.type = XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2,
.firmware_name = XHCI_RCAR_FIRMWARE_NAME_V1, .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V1,
.init_quirk = xhci_rcar_init_quirk,
.plat_start = xhci_rcar_start,
}; };
static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = { static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
.type = XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3,
.firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2, .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2,
.init_quirk = xhci_rcar_init_quirk,
.plat_start = xhci_rcar_start,
}; };
static const struct of_device_id usb_xhci_of_match[] = { static const struct of_device_id usb_xhci_of_match[] = {
...@@ -207,12 +209,6 @@ static int xhci_plat_probe(struct platform_device *pdev) ...@@ -207,12 +209,6 @@ static int xhci_plat_probe(struct platform_device *pdev)
*priv = *priv_match; *priv = *priv_match;
} }
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_MARVELL_ARMADA)) {
ret = xhci_mvebu_mbus_init_quirk(pdev);
if (ret)
goto disable_clk;
}
device_wakeup_enable(hcd->self.controller); device_wakeup_enable(hcd->self.controller);
xhci->clk = clk; xhci->clk = clk;
......
...@@ -13,27 +13,11 @@ ...@@ -13,27 +13,11 @@
#include "xhci.h" /* for hcd_to_xhci() */ #include "xhci.h" /* for hcd_to_xhci() */
enum xhci_plat_type {
XHCI_PLAT_TYPE_MARVELL_ARMADA = 1,
XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2,
XHCI_PLAT_TYPE_RENESAS_RCAR_GEN3,
};
struct xhci_plat_priv { struct xhci_plat_priv {
enum xhci_plat_type type;
const char *firmware_name; const char *firmware_name;
void (*plat_start)(struct usb_hcd *);
int (*init_quirk)(struct usb_hcd *);
}; };
#define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv) #define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
static inline bool xhci_plat_type_is(struct usb_hcd *hcd,
enum xhci_plat_type type)
{
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
if (priv && priv->type == type)
return true;
else
return false;
}
#endif /* _XHCI_PLAT_H */ #endif /* _XHCI_PLAT_H */
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/usb/phy.h> #include <linux/usb/phy.h>
#include "xhci.h" #include "xhci.h"
...@@ -76,6 +77,24 @@ static void xhci_rcar_start_gen2(struct usb_hcd *hcd) ...@@ -76,6 +77,24 @@ static void xhci_rcar_start_gen2(struct usb_hcd *hcd)
writel(RCAR_USB3_TX_POL_VAL, hcd->regs + RCAR_USB3_TX_POL); writel(RCAR_USB3_TX_POL_VAL, hcd->regs + RCAR_USB3_TX_POL);
} }
static int xhci_rcar_is_gen2(struct device *dev)
{
struct device_node *node = dev->of_node;
return of_device_is_compatible(node, "renesas,xhci-r8a7790") ||
of_device_is_compatible(node, "renesas,xhci-r8a7791") ||
of_device_is_compatible(node, "renesas,xhci-r8a7793") ||
of_device_is_compatible(node, "renensas,rcar-gen2-xhci");
}
static int xhci_rcar_is_gen3(struct device *dev)
{
struct device_node *node = dev->of_node;
return of_device_is_compatible(node, "renesas,xhci-r8a7795") ||
of_device_is_compatible(node, "renesas,rcar-gen3-xhci");
}
void xhci_rcar_start(struct usb_hcd *hcd) void xhci_rcar_start(struct usb_hcd *hcd)
{ {
u32 temp; u32 temp;
...@@ -85,7 +104,7 @@ void xhci_rcar_start(struct usb_hcd *hcd) ...@@ -85,7 +104,7 @@ void xhci_rcar_start(struct usb_hcd *hcd)
temp = readl(hcd->regs + RCAR_USB3_INT_ENA); temp = readl(hcd->regs + RCAR_USB3_INT_ENA);
temp |= RCAR_USB3_INT_ENA_VAL; temp |= RCAR_USB3_INT_ENA_VAL;
writel(temp, hcd->regs + RCAR_USB3_INT_ENA); writel(temp, hcd->regs + RCAR_USB3_INT_ENA);
if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_RENESAS_RCAR_GEN2)) if (xhci_rcar_is_gen2(hcd->self.controller))
xhci_rcar_start_gen2(hcd); xhci_rcar_start_gen2(hcd);
} }
} }
...@@ -156,9 +175,22 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) ...@@ -156,9 +175,22 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd)
/* This function needs to initialize a "phy" of usb before */ /* This function needs to initialize a "phy" of usb before */
int xhci_rcar_init_quirk(struct usb_hcd *hcd) int xhci_rcar_init_quirk(struct usb_hcd *hcd)
{ {
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
/* If hcd->regs is NULL, we don't just call the following function */ /* If hcd->regs is NULL, we don't just call the following function */
if (!hcd->regs) if (!hcd->regs)
return 0; return 0;
/*
* On R-Car Gen2 and Gen3, the AC64 bit (bit 0) of HCCPARAMS1 is set
* to 1. However, these SoCs don't support 64-bit address memory
* pointers. So, this driver clears the AC64 bit of xhci->hcc_params
* to call dma_set_coherent_mask(dev, DMA_BIT_MASK(32)) in
* xhci_gen_setup().
*/
if (xhci_rcar_is_gen2(hcd->self.controller) ||
xhci_rcar_is_gen3(hcd->self.controller))
xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
return xhci_rcar_download_firmware(hcd); return xhci_rcar_download_firmware(hcd);
} }
此差异已折叠。
此差异已折叠。
...@@ -1338,6 +1338,9 @@ union xhci_trb { ...@@ -1338,6 +1338,9 @@ union xhci_trb {
/* TRB buffer pointers can't cross 64KB boundaries */ /* TRB buffer pointers can't cross 64KB boundaries */
#define TRB_MAX_BUFF_SHIFT 16 #define TRB_MAX_BUFF_SHIFT 16
#define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT) #define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT)
/* How much data is left before the 64KB boundary? */
#define TRB_BUFF_LEN_UP_TO_BOUNDARY(addr) (TRB_MAX_BUFF_SIZE - \
(addr & (TRB_MAX_BUFF_SIZE - 1)))
struct xhci_segment { struct xhci_segment {
union xhci_trb *trbs; union xhci_trb *trbs;
...@@ -1965,4 +1968,15 @@ struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_container_ ...@@ -1965,4 +1968,15 @@ struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_container_
struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index); struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index);
struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
unsigned int stream_id);
static inline struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
struct urb *urb)
{
return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id,
xhci_get_endpoint_index(&urb->ep->desc),
urb->stream_id);
}
#endif /* __LINUX_XHCI_HCD_H */ #endif /* __LINUX_XHCI_HCD_H */
...@@ -163,7 +163,7 @@ static void isp1761_pci_shutdown(struct pci_dev *dev) ...@@ -163,7 +163,7 @@ static void isp1761_pci_shutdown(struct pci_dev *dev)
printk(KERN_ERR "ips1761_pci_shutdown\n"); printk(KERN_ERR "ips1761_pci_shutdown\n");
} }
static const struct pci_device_id isp1760_plx [] = { static const struct pci_device_id isp1760_plx[] = {
{ {
.class = PCI_CLASS_BRIDGE_OTHER << 8, .class = PCI_CLASS_BRIDGE_OTHER << 8,
.class_mask = ~0, .class_mask = ~0,
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册