mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-01 03:11:59 +00:00
USB/PHY patches for 4.20-rc1
Here is the big USB/PHY driver patches for 4.20-rc1 Lots of USB changes in here, primarily in these areas: - typec updates and new drivers - new PHY drivers - dwc2 driver updates and additions (this old core keeps getting added to new devices.) - usbtmc major update based on the industry group coming together and working to add new features and performance to the driver. - USB gadget additions for new features - USB gadget configfs updates - chipidea driver updates - other USB gadget updates - USB serial driver updates - renesas driver updates - xhci driver updates - other tiny USB driver updates All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCW9LlHw8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymnvwCffYmMWyMG9zSOw1oSzFPl7TVN1hYAoMyJqzLg umyLwWxC9ZWWkrpc3iD8 =ux+Y -----END PGP SIGNATURE----- Merge tag 'usb-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB/PHY updates from Greg KH: "Here is the big USB/PHY driver patches for 4.20-rc1 Lots of USB changes in here, primarily in these areas: - typec updates and new drivers - new PHY drivers - dwc2 driver updates and additions (this old core keeps getting added to new devices.) - usbtmc major update based on the industry group coming together and working to add new features and performance to the driver. - USB gadget additions for new features - USB gadget configfs updates - chipidea driver updates - other USB gadget updates - USB serial driver updates - renesas driver updates - xhci driver updates - other tiny USB driver updates All of these have been in linux-next for a while with no reported issues" * tag 'usb-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (229 commits) usb: phy: ab8500: silence some uninitialized variable warnings usb: xhci: tegra: Add genpd support usb: xhci: tegra: Power-off power-domains on removal usbip:vudc: BUG kmalloc-2048 (Not tainted): Poison overwritten usbip: tools: fix atoi() on non-null terminated string USB: misc: appledisplay: fix backlight update_status return code phy: phy-pxa-usb: add a new driver usb: host: add DT bindings for faraday fotg2 usb: host: ohci-at91: fix request of irq for optional gpio usb/early: remove set but not used variable 'remain_length' usb: typec: Fix copy/paste on typec_set_vconn_role() kerneldoc usb: typec: tcpm: Report back negotiated PPS voltage and current USB: core: remove set but not used variable 'udev' usb: core: fix memory leak on port_dev_path allocation USB: net2280: Remove ->disconnect() callback from net2280_pullup() usb: dwc2: disable power_down on rockchip devices usb: gadget: udc: renesas_usb3: add support for r8a77990 dt-bindings: usb: renesas_usb3: add bindings for r8a77990 usb: gadget: udc: renesas_usb3: Add r8a774a1 support USB: serial: cypress_m8: remove set but not used variable 'iflag' ...
This commit is contained in:
commit
9703fc8caf
181 changed files with 8807 additions and 2209 deletions
|
@ -25,38 +25,3 @@ Description:
|
||||||
4.2.2.
|
4.2.2.
|
||||||
|
|
||||||
The files are read only.
|
The files are read only.
|
||||||
|
|
||||||
|
|
||||||
What: /sys/bus/usb/drivers/usbtmc/*/TermChar
|
|
||||||
Date: August 2008
|
|
||||||
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
||||||
Description:
|
|
||||||
This file is the TermChar value to be sent to the USB TMC
|
|
||||||
device as described by the document, "Universal Serial Bus Test
|
|
||||||
and Measurement Class Specification
|
|
||||||
(USBTMC) Revision 1.0" as published by the USB-IF.
|
|
||||||
|
|
||||||
Note that the TermCharEnabled file determines if this value is
|
|
||||||
sent to the device or not.
|
|
||||||
|
|
||||||
|
|
||||||
What: /sys/bus/usb/drivers/usbtmc/*/TermCharEnabled
|
|
||||||
Date: August 2008
|
|
||||||
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
||||||
Description:
|
|
||||||
This file determines if the TermChar is to be sent to the
|
|
||||||
device on every transaction or not. For more details about
|
|
||||||
this, please see the document, "Universal Serial Bus Test and
|
|
||||||
Measurement Class Specification (USBTMC) Revision 1.0" as
|
|
||||||
published by the USB-IF.
|
|
||||||
|
|
||||||
|
|
||||||
What: /sys/bus/usb/drivers/usbtmc/*/auto_abort
|
|
||||||
Date: August 2008
|
|
||||||
Contact: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
||||||
Description:
|
|
||||||
This file determines if the transaction of the USB TMC
|
|
||||||
device is to be automatically aborted if there is any error.
|
|
||||||
For more details about this, please see the document,
|
|
||||||
"Universal Serial Bus Test and Measurement Class Specification
|
|
||||||
(USBTMC) Revision 1.0" as published by the USB-IF.
|
|
||||||
|
|
|
@ -12,6 +12,10 @@ Date: Dec 2014
|
||||||
KernelVersion: 4.0
|
KernelVersion: 4.0
|
||||||
Description: Control descriptors
|
Description: Control descriptors
|
||||||
|
|
||||||
|
All attributes read only:
|
||||||
|
bInterfaceNumber - USB interface number for this
|
||||||
|
streaming interface
|
||||||
|
|
||||||
What: /config/usb-gadget/gadget/functions/uvc.name/control/class
|
What: /config/usb-gadget/gadget/functions/uvc.name/control/class
|
||||||
Date: Dec 2014
|
Date: Dec 2014
|
||||||
KernelVersion: 4.0
|
KernelVersion: 4.0
|
||||||
|
@ -109,6 +113,10 @@ Date: Dec 2014
|
||||||
KernelVersion: 4.0
|
KernelVersion: 4.0
|
||||||
Description: Streaming descriptors
|
Description: Streaming descriptors
|
||||||
|
|
||||||
|
All attributes read only:
|
||||||
|
bInterfaceNumber - USB interface number for this
|
||||||
|
streaming interface
|
||||||
|
|
||||||
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class
|
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class
|
||||||
Date: Dec 2014
|
Date: Dec 2014
|
||||||
KernelVersion: 4.0
|
KernelVersion: 4.0
|
||||||
|
@ -160,6 +168,10 @@ Description: Specific MJPEG format descriptors
|
||||||
|
|
||||||
All attributes read only,
|
All attributes read only,
|
||||||
except bmaControls and bDefaultFrameIndex:
|
except bmaControls and bDefaultFrameIndex:
|
||||||
|
bFormatIndex - unique id for this format descriptor;
|
||||||
|
only defined after parent header is
|
||||||
|
linked into the streaming class;
|
||||||
|
read-only
|
||||||
bmaControls - this format's data for bmaControls in
|
bmaControls - this format's data for bmaControls in
|
||||||
the streaming header
|
the streaming header
|
||||||
bmInterfaceFlags - specifies interlace information,
|
bmInterfaceFlags - specifies interlace information,
|
||||||
|
@ -177,6 +189,10 @@ Date: Dec 2014
|
||||||
KernelVersion: 4.0
|
KernelVersion: 4.0
|
||||||
Description: Specific MJPEG frame descriptors
|
Description: Specific MJPEG frame descriptors
|
||||||
|
|
||||||
|
bFrameIndex - unique id for this framedescriptor;
|
||||||
|
only defined after parent format is
|
||||||
|
linked into the streaming header;
|
||||||
|
read-only
|
||||||
dwFrameInterval - indicates how frame interval can be
|
dwFrameInterval - indicates how frame interval can be
|
||||||
programmed; a number of values
|
programmed; a number of values
|
||||||
separated by newline can be specified
|
separated by newline can be specified
|
||||||
|
@ -204,6 +220,10 @@ Date: Dec 2014
|
||||||
KernelVersion: 4.0
|
KernelVersion: 4.0
|
||||||
Description: Specific uncompressed format descriptors
|
Description: Specific uncompressed format descriptors
|
||||||
|
|
||||||
|
bFormatIndex - unique id for this format descriptor;
|
||||||
|
only defined after parent header is
|
||||||
|
linked into the streaming class;
|
||||||
|
read-only
|
||||||
bmaControls - this format's data for bmaControls in
|
bmaControls - this format's data for bmaControls in
|
||||||
the streaming header
|
the streaming header
|
||||||
bmInterfaceFlags - specifies interlace information,
|
bmInterfaceFlags - specifies interlace information,
|
||||||
|
@ -224,6 +244,10 @@ Date: Dec 2014
|
||||||
KernelVersion: 4.0
|
KernelVersion: 4.0
|
||||||
Description: Specific uncompressed frame descriptors
|
Description: Specific uncompressed frame descriptors
|
||||||
|
|
||||||
|
bFrameIndex - unique id for this framedescriptor;
|
||||||
|
only defined after parent format is
|
||||||
|
linked into the streaming header;
|
||||||
|
read-only
|
||||||
dwFrameInterval - indicates how frame interval can be
|
dwFrameInterval - indicates how frame interval can be
|
||||||
programmed; a number of values
|
programmed; a number of values
|
||||||
separated by newline can be specified
|
separated by newline can be specified
|
||||||
|
|
|
@ -189,6 +189,16 @@ Description:
|
||||||
The file will read "hotplug", "wired" and "not used" if the
|
The file will read "hotplug", "wired" and "not used" if the
|
||||||
information is available, and "unknown" otherwise.
|
information is available, and "unknown" otherwise.
|
||||||
|
|
||||||
|
What: /sys/bus/usb/devices/.../(hub interface)/portX/location
|
||||||
|
Date: October 2018
|
||||||
|
Contact: Bjørn Mork <bjorn@mork.no>
|
||||||
|
Description:
|
||||||
|
Some platforms provide usb port physical location through
|
||||||
|
firmware. This is used by the kernel to pair up logical ports
|
||||||
|
mapping to the same physical connector. The attribute exposes the
|
||||||
|
raw location value as a hex integer.
|
||||||
|
|
||||||
|
|
||||||
What: /sys/bus/usb/devices/.../(hub interface)/portX/quirks
|
What: /sys/bus/usb/devices/.../(hub interface)/portX/quirks
|
||||||
Date: May 2018
|
Date: May 2018
|
||||||
Contact: Nicolas Boichat <drinkcat@chromium.org>
|
Contact: Nicolas Boichat <drinkcat@chromium.org>
|
||||||
|
@ -219,7 +229,14 @@ Description:
|
||||||
ports and report them to the kernel. This attribute is to expose
|
ports and report them to the kernel. This attribute is to expose
|
||||||
the number of over-current situation occurred on a specific port
|
the number of over-current situation occurred on a specific port
|
||||||
to user space. This file will contain an unsigned 32 bit value
|
to user space. This file will contain an unsigned 32 bit value
|
||||||
which wraps to 0 after its maximum is reached.
|
which wraps to 0 after its maximum is reached. This file supports
|
||||||
|
poll() for monitoring changes to this value in user space.
|
||||||
|
|
||||||
|
Any time this value changes the corresponding hub device will send a
|
||||||
|
udev event with the following attributes:
|
||||||
|
|
||||||
|
OVER_CURRENT_PORT=/sys/bus/usb/devices/.../(hub interface)/portX
|
||||||
|
OVER_CURRENT_COUNT=[current value of this sysfs attribute]
|
||||||
|
|
||||||
What: /sys/bus/usb/devices/.../(hub interface)/portX/usb3_lpm_permit
|
What: /sys/bus/usb/devices/.../(hub interface)/portX/usb3_lpm_permit
|
||||||
Date: November 2015
|
Date: November 2015
|
||||||
|
|
|
@ -4623,7 +4623,8 @@
|
||||||
|
|
||||||
usbcore.old_scheme_first=
|
usbcore.old_scheme_first=
|
||||||
[USB] Start with the old device initialization
|
[USB] Start with the old device initialization
|
||||||
scheme (default 0 = off).
|
scheme, applies only to low and full-speed devices
|
||||||
|
(default 0 = off).
|
||||||
|
|
||||||
usbcore.usbfs_memory_mb=
|
usbcore.usbfs_memory_mb=
|
||||||
[USB] Memory limit (in MB) for buffers allocated by
|
[USB] Memory limit (in MB) for buffers allocated by
|
||||||
|
|
|
@ -29,15 +29,15 @@ Required properties for usb-c-connector with power delivery support:
|
||||||
in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.2
|
in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.2
|
||||||
Source_Capabilities Message, the order of each entry(PDO) should follow
|
Source_Capabilities Message, the order of each entry(PDO) should follow
|
||||||
the PD spec chapter 6.4.1. Required for power source and power dual role.
|
the PD spec chapter 6.4.1. Required for power source and power dual role.
|
||||||
User can specify the source PDO array via PDO_FIXED/BATT/VAR() defined in
|
User can specify the source PDO array via PDO_FIXED/BATT/VAR/PPS_APDO()
|
||||||
dt-bindings/usb/pd.h.
|
defined in dt-bindings/usb/pd.h.
|
||||||
- sink-pdos: An array of u32 with each entry providing supported power
|
- sink-pdos: An array of u32 with each entry providing supported power
|
||||||
sink data object(PDO), the detailed bit definitions of PDO can be found
|
sink data object(PDO), the detailed bit definitions of PDO can be found
|
||||||
in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.3
|
in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.3
|
||||||
Sink Capabilities Message, the order of each entry(PDO) should follow
|
Sink Capabilities Message, the order of each entry(PDO) should follow
|
||||||
the PD spec chapter 6.4.1. Required for power sink and power dual role.
|
the PD spec chapter 6.4.1. Required for power sink and power dual role.
|
||||||
User can specify the sink PDO array via PDO_FIXED/BATT/VAR() defined in
|
User can specify the sink PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() defined
|
||||||
dt-bindings/usb/pd.h.
|
in dt-bindings/usb/pd.h.
|
||||||
- op-sink-microwatt: Sink required operating power in microwatt, if source
|
- op-sink-microwatt: Sink required operating power in microwatt, if source
|
||||||
can't offer the power, Capability Mismatch is set. Required for power
|
can't offer the power, Capability Mismatch is set. Required for power
|
||||||
sink and power dual role.
|
sink and power dual role.
|
||||||
|
|
|
@ -8,6 +8,7 @@ Required properties:
|
||||||
"brcm,iproc-nsp-sata-phy"
|
"brcm,iproc-nsp-sata-phy"
|
||||||
"brcm,phy-sata3"
|
"brcm,phy-sata3"
|
||||||
"brcm,iproc-sr-sata-phy"
|
"brcm,iproc-sr-sata-phy"
|
||||||
|
"brcm,bcm63138-sata-phy"
|
||||||
- address-cells: should be 1
|
- address-cells: should be 1
|
||||||
- size-cells: should be 0
|
- size-cells: should be 0
|
||||||
- reg: register ranges for the PHY PCB interface
|
- reg: register ranges for the PHY PCB interface
|
||||||
|
|
30
Documentation/devicetree/bindings/phy/phy-cadence-dp.txt
Normal file
30
Documentation/devicetree/bindings/phy/phy-cadence-dp.txt
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
Cadence MHDP DisplayPort SD0801 PHY binding
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
This binding describes the Cadence SD0801 PHY hardware included with
|
||||||
|
the Cadence MHDP DisplayPort controller.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Required properties (controller (parent) node):
|
||||||
|
- compatible : Should be "cdns,dp-phy"
|
||||||
|
- reg : Defines the following sets of registers in the parent
|
||||||
|
mhdp device:
|
||||||
|
- Offset of the DPTX PHY configuration registers
|
||||||
|
- Offset of the SD0801 PHY configuration registers
|
||||||
|
- #phy-cells : from the generic PHY bindings, must be 0.
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- num_lanes : Number of DisplayPort lanes to use (1, 2 or 4)
|
||||||
|
- max_bit_rate : Maximum DisplayPort link bit rate to use, in Mbps (2160,
|
||||||
|
2430, 2700, 3240, 4320, 5400 or 8100)
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Example:
|
||||||
|
dp_phy: phy@f0fb030a00 {
|
||||||
|
compatible = "cdns,dp-phy";
|
||||||
|
reg = <0xf0 0xfb030a00 0x0 0x00000040>,
|
||||||
|
<0xf0 0xfb500000 0x0 0x00100000>;
|
||||||
|
num_lanes = <4>;
|
||||||
|
max_bit_rate = <8100>;
|
||||||
|
#phy-cells = <0>;
|
||||||
|
};
|
|
@ -0,0 +1,43 @@
|
||||||
|
ROCKCHIP HDMI PHY WITH INNO IP BLOCK
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible : should be one of the listed compatibles:
|
||||||
|
* "rockchip,rk3228-hdmi-phy",
|
||||||
|
* "rockchip,rk3328-hdmi-phy";
|
||||||
|
- reg : Address and length of the hdmi phy control register set
|
||||||
|
- clocks : phandle + clock specifier for the phy clocks
|
||||||
|
- clock-names : string, clock name, must contain "sysclk" for system
|
||||||
|
control and register configuration, "refoclk" for crystal-
|
||||||
|
oscillator reference PLL clock input and "refpclk" for pclk-
|
||||||
|
based refeference PLL clock input.
|
||||||
|
- #clock-cells: should be 0.
|
||||||
|
- clock-output-names : shall be the name for the output clock.
|
||||||
|
- interrupts : phandle + interrupt specified for the hdmiphy interrupt
|
||||||
|
- #phy-cells : must be 0. See ./phy-bindings.txt for details.
|
||||||
|
|
||||||
|
Optional properties for rk3328-hdmi-phy:
|
||||||
|
- nvmem-cells = phandle + nvmem specifier for the cpu-version efuse
|
||||||
|
- nvmem-cell-names : "cpu-version" to read the chip version, required
|
||||||
|
for adjustment to some frequency settings
|
||||||
|
|
||||||
|
Example:
|
||||||
|
hdmi_phy: hdmi-phy@12030000 {
|
||||||
|
compatible = "rockchip,rk3228-hdmi-phy";
|
||||||
|
reg = <0x12030000 0x10000>;
|
||||||
|
#phy-cells = <0>;
|
||||||
|
clocks = <&cru PCLK_HDMI_PHY>, <&xin24m>, <&cru DCLK_HDMIPHY>;
|
||||||
|
clock-names = "sysclk", "refoclk", "refpclk";
|
||||||
|
#clock-cells = <0>;
|
||||||
|
clock-output-names = "hdmi_phy";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
Then the PHY can be used in other nodes such as:
|
||||||
|
|
||||||
|
hdmi: hdmi@200a0000 {
|
||||||
|
compatible = "rockchip,rk3228-dw-hdmi";
|
||||||
|
...
|
||||||
|
phys = <&hdmi_phy>;
|
||||||
|
phy-names = "hdmi";
|
||||||
|
...
|
||||||
|
};
|
|
@ -10,16 +10,20 @@ Required properties:
|
||||||
"qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
|
"qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
|
||||||
"qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996,
|
"qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996,
|
||||||
"qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845,
|
"qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845,
|
||||||
"qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845.
|
"qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845,
|
||||||
|
"qcom,sdm845-qmp-ufs-phy" for UFS QMP phy on sdm845.
|
||||||
|
|
||||||
- reg:
|
- reg:
|
||||||
|
- index 0: address and length of register set for PHY's common
|
||||||
|
serdes block.
|
||||||
|
- index 1: address and length of the DP_COM control block (for
|
||||||
|
"qcom,sdm845-qmp-usb3-phy" only).
|
||||||
|
|
||||||
|
- reg-names:
|
||||||
- For "qcom,sdm845-qmp-usb3-phy":
|
- For "qcom,sdm845-qmp-usb3-phy":
|
||||||
- index 0: address and length of register set for PHY's common serdes
|
- Should be: "reg-base", "dp_com"
|
||||||
block.
|
|
||||||
- named register "dp_com" (using reg-names): address and length of the
|
|
||||||
DP_COM control block.
|
|
||||||
- For all others:
|
- For all others:
|
||||||
- offset and length of register set for PHY's common serdes block.
|
- The reg-names property shouldn't be defined.
|
||||||
|
|
||||||
- #clock-cells: must be 1
|
- #clock-cells: must be 1
|
||||||
- Phy pll outputs a bunch of clocks for Tx, Rx and Pipe
|
- Phy pll outputs a bunch of clocks for Tx, Rx and Pipe
|
||||||
|
@ -35,6 +39,7 @@ Required properties:
|
||||||
"aux" for phy aux clock,
|
"aux" for phy aux clock,
|
||||||
"ref" for 19.2 MHz ref clk,
|
"ref" for 19.2 MHz ref clk,
|
||||||
"com_aux" for phy common block aux clock,
|
"com_aux" for phy common block aux clock,
|
||||||
|
"ref_aux" for phy reference aux clock,
|
||||||
For "qcom,msm8996-qmp-pcie-phy" must contain:
|
For "qcom,msm8996-qmp-pcie-phy" must contain:
|
||||||
"aux", "cfg_ahb", "ref".
|
"aux", "cfg_ahb", "ref".
|
||||||
For "qcom,msm8996-qmp-usb3-phy" must contain:
|
For "qcom,msm8996-qmp-usb3-phy" must contain:
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
* Renesas R-Car generation 3 USB 2.0 PHY
|
* Renesas R-Car generation 3 USB 2.0 PHY
|
||||||
|
|
||||||
This file provides information on what the device node for the R-Car generation
|
This file provides information on what the device node for the R-Car generation
|
||||||
3 USB 2.0 PHY contains.
|
3 and RZ/G2 USB 2.0 PHY contain.
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795
|
- compatible: "renesas,usb2-phy-r8a774a1" if the device is a part of an R8A774A1
|
||||||
|
SoC.
|
||||||
|
"renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795
|
||||||
SoC.
|
SoC.
|
||||||
"renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796
|
"renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796
|
||||||
SoC.
|
SoC.
|
||||||
|
@ -14,7 +16,8 @@ Required properties:
|
||||||
R8A77990 SoC.
|
R8A77990 SoC.
|
||||||
"renesas,usb2-phy-r8a77995" if the device is a part of an
|
"renesas,usb2-phy-r8a77995" if the device is a part of an
|
||||||
R8A77995 SoC.
|
R8A77995 SoC.
|
||||||
"renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device.
|
"renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 or RZ/G2
|
||||||
|
compatible device.
|
||||||
|
|
||||||
When compatible with the generic version, nodes must list the
|
When compatible with the generic version, nodes must list the
|
||||||
SoC-specific version corresponding to the platform first
|
SoC-specific version corresponding to the platform first
|
||||||
|
@ -31,6 +34,8 @@ 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
|
- vbus-supply: Phandle to a regulator that provides power to the VBUS. This
|
||||||
regulator will be managed during the PHY power on/off sequence.
|
regulator will be managed during the PHY power on/off sequence.
|
||||||
|
- renesas,no-otg-pins: boolean, specify when a board does not provide proper
|
||||||
|
otg pins.
|
||||||
|
|
||||||
Example (R-Car H3):
|
Example (R-Car H3):
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
* Renesas R-Car generation 3 USB 3.0 PHY
|
* Renesas R-Car generation 3 USB 3.0 PHY
|
||||||
|
|
||||||
This file provides information on what the device node for the R-Car generation
|
This file provides information on what the device node for the R-Car generation
|
||||||
3 USB 3.0 PHY contains.
|
3 and RZ/G2 USB 3.0 PHY contain.
|
||||||
If you want to enable spread spectrum clock (ssc), you should use USB_EXTAL
|
If you want to enable spread spectrum clock (ssc), you should use USB_EXTAL
|
||||||
instead of USB3_CLK. However, if you don't want to these features, you don't
|
instead of USB3_CLK. However, if you don't want to these features, you don't
|
||||||
need this driver.
|
need this driver.
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: "renesas,r8a7795-usb3-phy" if the device is a part of an R8A7795
|
- compatible: "renesas,r8a774a1-usb3-phy" if the device is a part of an R8A774A1
|
||||||
|
SoC.
|
||||||
|
"renesas,r8a7795-usb3-phy" if the device is a part of an R8A7795
|
||||||
SoC.
|
SoC.
|
||||||
"renesas,r8a7796-usb3-phy" if the device is a part of an R8A7796
|
"renesas,r8a7796-usb3-phy" if the device is a part of an R8A7796
|
||||||
SoC.
|
SoC.
|
||||||
"renesas,r8a77965-usb3-phy" if the device is a part of an
|
"renesas,r8a77965-usb3-phy" if the device is a part of an
|
||||||
R8A77965 SoC.
|
R8A77965 SoC.
|
||||||
"renesas,rcar-gen3-usb3-phy" for a generic R-Car Gen3 compatible
|
"renesas,rcar-gen3-usb3-phy" for a generic R-Car Gen3 or RZ/G2
|
||||||
device.
|
compatible device.
|
||||||
|
|
||||||
When compatible with the generic version, nodes must list the
|
When compatible with the generic version, nodes must list the
|
||||||
SoC-specific version corresponding to the platform first
|
SoC-specific version corresponding to the platform first
|
||||||
|
|
31
Documentation/devicetree/bindings/phy/uniphier-pcie-phy.txt
Normal file
31
Documentation/devicetree/bindings/phy/uniphier-pcie-phy.txt
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
Socionext UniPhier PCIe PHY bindings
|
||||||
|
|
||||||
|
This describes the devicetree bindings for PHY interface built into
|
||||||
|
PCIe controller implemented on Socionext UniPhier SoCs.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: Should contain one of the following:
|
||||||
|
"socionext,uniphier-ld20-pcie-phy" - for LD20 PHY
|
||||||
|
"socionext,uniphier-pxs3-pcie-phy" - for PXs3 PHY
|
||||||
|
- reg: Specifies offset and length of the register set for the device.
|
||||||
|
- #phy-cells: Must be zero.
|
||||||
|
- clocks: A phandle to the clock gate for PCIe glue layer including
|
||||||
|
this phy.
|
||||||
|
- resets: A phandle to the reset line for PCIe glue layer including
|
||||||
|
this phy.
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- socionext,syscon: A phandle to system control to set configurations
|
||||||
|
for phy.
|
||||||
|
|
||||||
|
Refer to phy/phy-bindings.txt for the generic PHY binding properties.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
pcie_phy: phy@66038000 {
|
||||||
|
compatible = "socionext,uniphier-ld20-pcie-phy";
|
||||||
|
reg = <0x66038000 0x4000>;
|
||||||
|
#phy-cells = <0>;
|
||||||
|
clocks = <&sys_clk 24>;
|
||||||
|
resets = <&sys_rst 24>;
|
||||||
|
socionext,syscon = <&soc_glue>;
|
||||||
|
};
|
45
Documentation/devicetree/bindings/phy/uniphier-usb2-phy.txt
Normal file
45
Documentation/devicetree/bindings/phy/uniphier-usb2-phy.txt
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
Socionext UniPhier USB2 PHY
|
||||||
|
|
||||||
|
This describes the devicetree bindings for PHY interface built into
|
||||||
|
USB2 controller implemented on Socionext UniPhier SoCs.
|
||||||
|
|
||||||
|
Pro4 SoC has both USB2 and USB3 host controllers, however, this USB3
|
||||||
|
controller doesn't include its own High-Speed PHY. This needs to specify
|
||||||
|
USB2 PHY instead of USB3 HS-PHY.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: Should contain one of the following:
|
||||||
|
"socionext,uniphier-pro4-usb2-phy" - for Pro4 SoC
|
||||||
|
"socionext,uniphier-ld11-usb2-phy" - for LD11 SoC
|
||||||
|
|
||||||
|
Sub-nodes:
|
||||||
|
Each PHY should be represented as a sub-node.
|
||||||
|
|
||||||
|
Sub-nodes required properties:
|
||||||
|
- #phy-cells: Should be 0.
|
||||||
|
- reg: The number of the PHY.
|
||||||
|
|
||||||
|
Sub-nodes optional properties:
|
||||||
|
- vbus-supply: A phandle to the regulator for USB VBUS.
|
||||||
|
|
||||||
|
Refer to phy/phy-bindings.txt for the generic PHY binding properties.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
soc-glue@5f800000 {
|
||||||
|
...
|
||||||
|
usb-phy {
|
||||||
|
compatible = "socionext,uniphier-ld11-usb2-phy";
|
||||||
|
usb_phy0: phy@0 {
|
||||||
|
reg = <0>;
|
||||||
|
#phy-cells = <0>;
|
||||||
|
};
|
||||||
|
...
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
usb@5a800100 {
|
||||||
|
compatible = "socionext,uniphier-ehci", "generic-ehci";
|
||||||
|
...
|
||||||
|
phy-names = "usb";
|
||||||
|
phys = <&usb_phy0>;
|
||||||
|
};
|
|
@ -0,0 +1,69 @@
|
||||||
|
Socionext UniPhier USB3 High-Speed (HS) PHY
|
||||||
|
|
||||||
|
This describes the devicetree bindings for PHY interfaces built into
|
||||||
|
USB3 controller implemented on Socionext UniPhier SoCs.
|
||||||
|
Although the controller includes High-Speed PHY and Super-Speed PHY,
|
||||||
|
this describes about High-Speed PHY.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: Should contain one of the following:
|
||||||
|
"socionext,uniphier-pro4-usb3-hsphy" - for Pro4 SoC
|
||||||
|
"socionext,uniphier-pxs2-usb3-hsphy" - for PXs2 SoC
|
||||||
|
"socionext,uniphier-ld20-usb3-hsphy" - for LD20 SoC
|
||||||
|
"socionext,uniphier-pxs3-usb3-hsphy" - for PXs3 SoC
|
||||||
|
- reg: Specifies offset and length of the register set for the device.
|
||||||
|
- #phy-cells: Should be 0.
|
||||||
|
- clocks: A list of phandles to the clock gate for USB3 glue layer.
|
||||||
|
According to the clock-names, appropriate clocks are required.
|
||||||
|
- clock-names: Should contain the following:
|
||||||
|
"gio", "link" - for Pro4 SoC
|
||||||
|
"phy", "phy-ext", "link" - for PXs3 SoC, "phy-ext" is optional.
|
||||||
|
"phy", "link" - for others
|
||||||
|
- resets: A list of phandles to the reset control for USB3 glue layer.
|
||||||
|
According to the reset-names, appropriate resets are required.
|
||||||
|
- reset-names: Should contain the following:
|
||||||
|
"gio", "link" - for Pro4 SoC
|
||||||
|
"phy", "link" - for others
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- vbus-supply: A phandle to the regulator for USB VBUS.
|
||||||
|
- nvmem-cells: Phandles to nvmem cell that contains the trimming data.
|
||||||
|
Available only for HS-PHY implemented on LD20 and PXs3, and
|
||||||
|
if unspecified, default value is used.
|
||||||
|
- nvmem-cell-names: Should be the following names, which correspond to
|
||||||
|
each nvmem-cells.
|
||||||
|
All of the 3 parameters associated with the following names are
|
||||||
|
required for each port, if any one is omitted, the trimming data
|
||||||
|
of the port will not be set at all.
|
||||||
|
"rterm", "sel_t", "hs_i" - Each cell name for phy parameters
|
||||||
|
|
||||||
|
Refer to phy/phy-bindings.txt for the generic PHY binding properties.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
usb-glue@65b00000 {
|
||||||
|
compatible = "socionext,uniphier-ld20-dwc3-glue",
|
||||||
|
"simple-mfd";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
ranges = <0 0x65b00000 0x400>;
|
||||||
|
|
||||||
|
usb_vbus0: regulator {
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
usb_hsphy0: hs-phy@200 {
|
||||||
|
compatible = "socionext,uniphier-ld20-usb3-hsphy";
|
||||||
|
reg = <0x200 0x10>;
|
||||||
|
#phy-cells = <0>;
|
||||||
|
clock-names = "link", "phy";
|
||||||
|
clocks = <&sys_clk 14>, <&sys_clk 16>;
|
||||||
|
reset-names = "link", "phy";
|
||||||
|
resets = <&sys_rst 14>, <&sys_rst 16>;
|
||||||
|
vbus-supply = <&usb_vbus0>;
|
||||||
|
nvmem-cell-names = "rterm", "sel_t", "hs_i";
|
||||||
|
nvmem-cells = <&usb_rterm0>, <&usb_sel_t0>,
|
||||||
|
<&usb_hs_i0>;
|
||||||
|
};
|
||||||
|
...
|
||||||
|
};
|
|
@ -0,0 +1,57 @@
|
||||||
|
Socionext UniPhier USB3 Super-Speed (SS) PHY
|
||||||
|
|
||||||
|
This describes the devicetree bindings for PHY interfaces built into
|
||||||
|
USB3 controller implemented on Socionext UniPhier SoCs.
|
||||||
|
Although the controller includes High-Speed PHY and Super-Speed PHY,
|
||||||
|
this describes about Super-Speed PHY.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: Should contain one of the following:
|
||||||
|
"socionext,uniphier-pro4-usb3-ssphy" - for Pro4 SoC
|
||||||
|
"socionext,uniphier-pxs2-usb3-ssphy" - for PXs2 SoC
|
||||||
|
"socionext,uniphier-ld20-usb3-ssphy" - for LD20 SoC
|
||||||
|
"socionext,uniphier-pxs3-usb3-ssphy" - for PXs3 SoC
|
||||||
|
- reg: Specifies offset and length of the register set for the device.
|
||||||
|
- #phy-cells: Should be 0.
|
||||||
|
- clocks: A list of phandles to the clock gate for USB3 glue layer.
|
||||||
|
According to the clock-names, appropriate clocks are required.
|
||||||
|
- clock-names:
|
||||||
|
"gio", "link" - for Pro4 SoC
|
||||||
|
"phy", "phy-ext", "link" - for PXs3 SoC, "phy-ext" is optional.
|
||||||
|
"phy", "link" - for others
|
||||||
|
- resets: A list of phandles to the reset control for USB3 glue layer.
|
||||||
|
According to the reset-names, appropriate resets are required.
|
||||||
|
- reset-names:
|
||||||
|
"gio", "link" - for Pro4 SoC
|
||||||
|
"phy", "link" - for others
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- vbus-supply: A phandle to the regulator for USB VBUS.
|
||||||
|
|
||||||
|
Refer to phy/phy-bindings.txt for the generic PHY binding properties.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
usb-glue@65b00000 {
|
||||||
|
compatible = "socionext,uniphier-ld20-dwc3-glue",
|
||||||
|
"simple-mfd";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
ranges = <0 0x65b00000 0x400>;
|
||||||
|
|
||||||
|
usb_vbus0: regulator {
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
usb_ssphy0: ss-phy@300 {
|
||||||
|
compatible = "socionext,uniphier-ld20-usb3-ssphy";
|
||||||
|
reg = <0x300 0x10>;
|
||||||
|
#phy-cells = <0>;
|
||||||
|
clock-names = "link", "phy";
|
||||||
|
clocks = <&sys_clk 14>, <&sys_clk 16>;
|
||||||
|
reset-names = "link", "phy";
|
||||||
|
resets = <&sys_rst 14>, <&sys_rst 16>;
|
||||||
|
vbus-supply = <&usb_vbus0>;
|
||||||
|
};
|
||||||
|
...
|
||||||
|
};
|
|
@ -80,6 +80,8 @@ Optional properties:
|
||||||
controller. It's expected that a mux state of 0 indicates device mode and a
|
controller. It's expected that a mux state of 0 indicates device mode and a
|
||||||
mux state of 1 indicates host mode.
|
mux state of 1 indicates host mode.
|
||||||
- mux-control-names: Shall be "usb_switch" if mux-controls is specified.
|
- mux-control-names: Shall be "usb_switch" if mux-controls is specified.
|
||||||
|
- pinctrl-names: Names for optional pin modes in "default", "host", "device"
|
||||||
|
- pinctrl-n: alternate pin modes
|
||||||
|
|
||||||
i.mx specific properties
|
i.mx specific properties
|
||||||
- fsl,usbmisc: phandler of non-core register device, with one
|
- fsl,usbmisc: phandler of non-core register device, with one
|
||||||
|
|
|
@ -19,6 +19,7 @@ Exception for clocks:
|
||||||
"cavium,octeon-7130-usb-uctl"
|
"cavium,octeon-7130-usb-uctl"
|
||||||
"qcom,dwc3"
|
"qcom,dwc3"
|
||||||
"samsung,exynos5250-dwusb3"
|
"samsung,exynos5250-dwusb3"
|
||||||
|
"samsung,exynos5433-dwusb3"
|
||||||
"samsung,exynos7-dwusb3"
|
"samsung,exynos7-dwusb3"
|
||||||
"sprd,sc9860-dwc3"
|
"sprd,sc9860-dwc3"
|
||||||
"st,stih407-dwc3"
|
"st,stih407-dwc3"
|
||||||
|
|
23
Documentation/devicetree/bindings/usb/ehci-mv.txt
Normal file
23
Documentation/devicetree/bindings/usb/ehci-mv.txt
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
* Marvell PXA/MMP EHCI controller.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
|
||||||
|
- compatible: must be "marvell,pxau2o-ehci"
|
||||||
|
- reg: physical base addresses of the controller and length of memory mapped region
|
||||||
|
- interrupts: one EHCI controller interrupt should be described here
|
||||||
|
- clocks: phandle list of usb clocks
|
||||||
|
- clock-names: should be "USBCLK"
|
||||||
|
- phys: phandle for the PHY device
|
||||||
|
- phy-names: should be "usb"
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
ehci0: usb-ehci@d4208000 {
|
||||||
|
compatible = "marvell,pxau2o-ehci";
|
||||||
|
reg = <0xd4208000 0x200>;
|
||||||
|
interrupts = <44>;
|
||||||
|
clocks = <&soc_clocks MMP2_CLK_USB>;
|
||||||
|
clock-names = "USBCLK";
|
||||||
|
phys = <&usb_otg_phy>;
|
||||||
|
phy-names = "usb";
|
||||||
|
};
|
|
@ -83,6 +83,8 @@ Required properties:
|
||||||
- compatible: should be one of the following -
|
- compatible: should be one of the following -
|
||||||
"samsung,exynos5250-dwusb3": for USB 3.0 DWC3 controller on
|
"samsung,exynos5250-dwusb3": for USB 3.0 DWC3 controller on
|
||||||
Exynos5250/5420.
|
Exynos5250/5420.
|
||||||
|
"samsung,exynos5433-dwusb3": for USB 3.0 DWC3 controller on
|
||||||
|
Exynos5433.
|
||||||
"samsung,exynos7-dwusb3": for USB 3.0 DWC3 controller on Exynos7.
|
"samsung,exynos7-dwusb3": for USB 3.0 DWC3 controller on Exynos7.
|
||||||
- #address-cells, #size-cells : should be '1' if the device has sub-nodes
|
- #address-cells, #size-cells : should be '1' if the device has sub-nodes
|
||||||
with 'reg' property.
|
with 'reg' property.
|
||||||
|
|
35
Documentation/devicetree/bindings/usb/faraday,fotg210.txt
Normal file
35
Documentation/devicetree/bindings/usb/faraday,fotg210.txt
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
Faraday FOTG Host controller
|
||||||
|
|
||||||
|
This OTG-capable USB host controller is found in Cortina Systems
|
||||||
|
Gemini and other SoC products.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be one of:
|
||||||
|
"faraday,fotg210"
|
||||||
|
"cortina,gemini-usb", "faraday,fotg210"
|
||||||
|
- reg: should contain one register range i.e. start and length
|
||||||
|
- interrupts: description of the interrupt line
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- clocks: should contain the IP block clock
|
||||||
|
- clock-names: should be "PCLK" for the IP block clock
|
||||||
|
|
||||||
|
Required properties for "cortina,gemini-usb" compatible:
|
||||||
|
- syscon: a phandle to the system controller to access PHY registers
|
||||||
|
|
||||||
|
Optional properties for "cortina,gemini-usb" compatible:
|
||||||
|
- cortina,gemini-mini-b: boolean property that indicates that a Mini-B
|
||||||
|
OTG connector is in use
|
||||||
|
- wakeup-source: see power/wakeup-source.txt
|
||||||
|
|
||||||
|
Example for Gemini:
|
||||||
|
|
||||||
|
usb@68000000 {
|
||||||
|
compatible = "cortina,gemini-usb", "faraday,fotg210";
|
||||||
|
reg = <0x68000000 0x1000>;
|
||||||
|
interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
clocks = <&cc 12>;
|
||||||
|
clock-names = "PCLK";
|
||||||
|
syscon = <&syscon>;
|
||||||
|
wakeup-source;
|
||||||
|
};
|
|
@ -5,11 +5,20 @@ Required properties :
|
||||||
- reg : I2C slave address
|
- reg : I2C slave address
|
||||||
- interrupts : Interrupt specifier
|
- interrupts : Interrupt specifier
|
||||||
|
|
||||||
Optional properties :
|
Required sub-node:
|
||||||
- fcs,operating-sink-microwatt :
|
- connector : The "usb-c-connector" attached to the FUSB302 IC. The bindings
|
||||||
Minimum amount of power accepted from a sink
|
of the connector node are specified in:
|
||||||
|
|
||||||
|
Documentation/devicetree/bindings/connector/usb-connector.txt
|
||||||
|
|
||||||
|
Deprecated properties :
|
||||||
|
- fcs,max-sink-microvolt : Maximum sink voltage accepted by port controller
|
||||||
|
- fcs,max-sink-microamp : Maximum sink current accepted by port controller
|
||||||
|
- fcs,max-sink-microwatt : Maximum sink power accepted by port controller
|
||||||
|
- fcs,operating-sink-microwatt : Minimum amount of power accepted from a sink
|
||||||
when negotiating
|
when negotiating
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
fusb302: typec-portc@54 {
|
fusb302: typec-portc@54 {
|
||||||
|
@ -17,7 +26,16 @@ fusb302: typec-portc@54 {
|
||||||
reg = <0x54>;
|
reg = <0x54>;
|
||||||
interrupt-parent = <&nmi_intc>;
|
interrupt-parent = <&nmi_intc>;
|
||||||
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
|
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
|
||||||
fcs,max-sink-microvolt = <12000000>;
|
|
||||||
fcs,max-sink-microamp = <3000000>;
|
usb_con: connector {
|
||||||
fcs,max-sink-microwatt = <36000000>;
|
compatible = "usb-c-connector";
|
||||||
|
label = "USB-C";
|
||||||
|
power-role = "dual";
|
||||||
|
try-power-role = "sink";
|
||||||
|
source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
|
||||||
|
sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
|
||||||
|
PDO_VAR(3000, 12000, 3000)
|
||||||
|
PDO_PPS_APDO(3000, 11000, 3000)>;
|
||||||
|
op-sink-microwatt = <10000000>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,11 +2,13 @@ Renesas Electronics USB3.0 Peripheral driver
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: Must contain one of the following:
|
- compatible: Must contain one of the following:
|
||||||
|
- "renesas,r8a774a1-usb3-peri"
|
||||||
- "renesas,r8a7795-usb3-peri"
|
- "renesas,r8a7795-usb3-peri"
|
||||||
- "renesas,r8a7796-usb3-peri"
|
- "renesas,r8a7796-usb3-peri"
|
||||||
- "renesas,r8a77965-usb3-peri"
|
- "renesas,r8a77965-usb3-peri"
|
||||||
- "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 compatible
|
- "renesas,r8a77990-usb3-peri"
|
||||||
device
|
- "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 or RZ/G2
|
||||||
|
compatible device
|
||||||
|
|
||||||
When compatible with the generic version, nodes must list the
|
When compatible with the generic version, nodes must list the
|
||||||
SoC-specific version corresponding to the platform first
|
SoC-specific version corresponding to the platform first
|
||||||
|
|
|
@ -4,7 +4,9 @@ Required properties:
|
||||||
- compatible: Must contain one or more of the following:
|
- compatible: Must contain one or more of the following:
|
||||||
|
|
||||||
- "renesas,usbhs-r8a7743" for r8a7743 (RZ/G1M) compatible device
|
- "renesas,usbhs-r8a7743" for r8a7743 (RZ/G1M) compatible device
|
||||||
|
- "renesas,usbhs-r8a7744" for r8a7744 (RZ/G1N) compatible device
|
||||||
- "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device
|
- "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device
|
||||||
|
- "renesas,usbhs-r8a774a1" for r8a774a1 (RZ/G2M) compatible device
|
||||||
- "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device
|
- "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device
|
||||||
- "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device
|
- "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device
|
||||||
- "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device
|
- "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device
|
||||||
|
@ -13,10 +15,11 @@ Required properties:
|
||||||
- "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
|
- "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
|
||||||
- "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device
|
- "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device
|
||||||
- "renesas,usbhs-r8a77965" for r8a77965 (R-Car M3-N) compatible device
|
- "renesas,usbhs-r8a77965" for r8a77965 (R-Car M3-N) compatible device
|
||||||
|
- "renesas,usbhs-r8a77990" for r8a77990 (R-Car E3) compatible device
|
||||||
- "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device
|
- "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device
|
||||||
- "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device
|
- "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device
|
||||||
- "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices
|
- "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices
|
||||||
- "renesas,rcar-gen3-usbhs" for R-Car Gen3 compatible device
|
- "renesas,rcar-gen3-usbhs" for R-Car Gen3 or RZ/G2 compatible devices
|
||||||
- "renesas,rza1-usbhs" for RZ/A1 compatible device
|
- "renesas,rza1-usbhs" for RZ/A1 compatible device
|
||||||
|
|
||||||
When compatible with the generic version, nodes must list the
|
When compatible with the generic version, nodes must list the
|
||||||
|
@ -25,7 +28,11 @@ Required properties:
|
||||||
|
|
||||||
- reg: Base address and length of the register for the USBHS
|
- reg: Base address and length of the register for the USBHS
|
||||||
- interrupts: Interrupt specifier for the USBHS
|
- interrupts: Interrupt specifier for the USBHS
|
||||||
- clocks: A list of phandle + clock specifier pairs
|
- clocks: A list of phandle + clock specifier pairs.
|
||||||
|
- In case of "renesas,rcar-gen3-usbhs", two clocks are required.
|
||||||
|
First clock should be peripheral and second one should be host.
|
||||||
|
- In case of except above, one clock is required. First clock
|
||||||
|
should be peripheral.
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- renesas,buswait: Integer to use BUSWAIT register
|
- renesas,buswait: Integer to use BUSWAIT register
|
||||||
|
|
|
@ -15,7 +15,11 @@ Optional properties:
|
||||||
- needs-reset-on-resume : boolean, set this to force EHCI reset after resume
|
- needs-reset-on-resume : boolean, set this to force EHCI reset after resume
|
||||||
- has-transaction-translator : boolean, set this if EHCI have a Transaction
|
- has-transaction-translator : boolean, set this if EHCI have a Transaction
|
||||||
Translator built into the root hub.
|
Translator built into the root hub.
|
||||||
- clocks : a list of phandle + clock specifier pairs
|
- clocks : a list of phandle + clock specifier pairs. In case of Renesas
|
||||||
|
R-Car Gen3 SoCs:
|
||||||
|
- if a host only channel: first clock should be host.
|
||||||
|
- if a USB DRD channel: first clock should be host and second one
|
||||||
|
should be peripheral.
|
||||||
- phys : see usb-hcd.txt in the current directory
|
- phys : see usb-hcd.txt in the current directory
|
||||||
- resets : phandle + reset specifier pair
|
- resets : phandle + reset specifier pair
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,11 @@ Optional properties:
|
||||||
- no-big-frame-no : boolean, set if frame_no lives in bits [15:0] of HCCA
|
- no-big-frame-no : boolean, set if frame_no lives in bits [15:0] of HCCA
|
||||||
- remote-wakeup-connected: remote wakeup is wired on the platform
|
- remote-wakeup-connected: remote wakeup is wired on the platform
|
||||||
- num-ports : u32, to override the detected port count
|
- num-ports : u32, to override the detected port count
|
||||||
- clocks : a list of phandle + clock specifier pairs
|
- clocks : a list of phandle + clock specifier pairs. In case of Renesas
|
||||||
|
R-Car Gen3 SoCs:
|
||||||
|
- if a host only channel: first clock should be host.
|
||||||
|
- if a USB DRD channel: first clock should be host and second one
|
||||||
|
should be peripheral.
|
||||||
- phys : see usb-hcd.txt in the current directory
|
- phys : see usb-hcd.txt in the current directory
|
||||||
- resets : a list of phandle + reset specifier pairs
|
- resets : a list of phandle + reset specifier pairs
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ Required properties:
|
||||||
- "marvell,armada-375-xhci" for Armada 375 SoCs
|
- "marvell,armada-375-xhci" for Armada 375 SoCs
|
||||||
- "marvell,armada-380-xhci" for Armada 38x SoCs
|
- "marvell,armada-380-xhci" for Armada 38x SoCs
|
||||||
- "renesas,xhci-r8a7743" for r8a7743 SoC
|
- "renesas,xhci-r8a7743" for r8a7743 SoC
|
||||||
|
- "renesas,xhci-r8a7744" for r8a7744 SoC
|
||||||
|
- "renesas,xhci-r8a774a1" for r8a774a1 SoC
|
||||||
- "renesas,xhci-r8a7790" for r8a7790 SoC
|
- "renesas,xhci-r8a7790" for r8a7790 SoC
|
||||||
- "renesas,xhci-r8a7791" for r8a7791 SoC
|
- "renesas,xhci-r8a7791" for r8a7791 SoC
|
||||||
- "renesas,xhci-r8a7793" for r8a7793 SoC
|
- "renesas,xhci-r8a7793" for r8a7793 SoC
|
||||||
|
@ -17,7 +19,8 @@ Required properties:
|
||||||
- "renesas,xhci-r8a77990" for r8a77990 SoC
|
- "renesas,xhci-r8a77990" for r8a77990 SoC
|
||||||
- "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 or RZ/G1 compatible
|
- "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 or RZ/G1 compatible
|
||||||
device
|
device
|
||||||
- "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device
|
- "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 or RZ/G2 compatible
|
||||||
|
device
|
||||||
- "xhci-platform" (deprecated)
|
- "xhci-platform" (deprecated)
|
||||||
|
|
||||||
When compatible with the generic version, nodes must list the
|
When compatible with the generic version, nodes must list the
|
||||||
|
|
|
@ -201,7 +201,7 @@ Code Seq#(hex) Include File Comments
|
||||||
'X' 01 linux/pktcdvd.h conflict!
|
'X' 01 linux/pktcdvd.h conflict!
|
||||||
'Y' all linux/cyclades.h
|
'Y' all linux/cyclades.h
|
||||||
'Z' 14-15 drivers/message/fusion/mptctl.h
|
'Z' 14-15 drivers/message/fusion/mptctl.h
|
||||||
'[' 00-07 linux/usb/tmc.h USB Test and Measurement Devices
|
'[' 00-3F linux/usb/tmc.h USB Test and Measurement Devices
|
||||||
<mailto:gregkh@linuxfoundation.org>
|
<mailto:gregkh@linuxfoundation.org>
|
||||||
'a' all linux/atm*.h, linux/sonet.h ATM on linux
|
'a' all linux/atm*.h, linux/sonet.h ATM on linux
|
||||||
<http://lrcwww.epfl.ch/>
|
<http://lrcwww.epfl.ch/>
|
||||||
|
|
|
@ -15443,6 +15443,12 @@ F: Documentation/driver-api/usb/typec_bus.rst
|
||||||
F: drivers/usb/typec/altmodes/
|
F: drivers/usb/typec/altmodes/
|
||||||
F: include/linux/usb/typec_altmode.h
|
F: include/linux/usb/typec_altmode.h
|
||||||
|
|
||||||
|
USB TYPEC PORT CONTROLLER DRIVERS
|
||||||
|
M: Guenter Roeck <linux@roeck-us.net>
|
||||||
|
L: linux-usb@vger.kernel.org
|
||||||
|
S: Maintained
|
||||||
|
F: drivers/usb/typec/tcpm/
|
||||||
|
|
||||||
USB UHCI DRIVER
|
USB UHCI DRIVER
|
||||||
M: Alan Stern <stern@rowland.harvard.edu>
|
M: Alan Stern <stern@rowland.harvard.edu>
|
||||||
L: linux-usb@vger.kernel.org
|
L: linux-usb@vger.kernel.org
|
||||||
|
|
|
@ -277,21 +277,12 @@ struct platform_device pxa168_device_u2o = {
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_USB_EHCI_MV_U2O)
|
#if IS_ENABLED(CONFIG_USB_EHCI_MV_U2O)
|
||||||
struct resource pxa168_u2oehci_resources[] = {
|
struct resource pxa168_u2oehci_resources[] = {
|
||||||
/* regbase */
|
|
||||||
[0] = {
|
[0] = {
|
||||||
.start = PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET,
|
.start = PXA168_U2O_REGBASE,
|
||||||
.end = PXA168_U2O_REGBASE + USB_REG_RANGE,
|
.end = PXA168_U2O_REGBASE + USB_REG_RANGE,
|
||||||
.flags = IORESOURCE_MEM,
|
.flags = IORESOURCE_MEM,
|
||||||
.name = "capregs",
|
|
||||||
},
|
},
|
||||||
/* phybase */
|
|
||||||
[1] = {
|
[1] = {
|
||||||
.start = PXA168_U2O_PHYBASE,
|
|
||||||
.end = PXA168_U2O_PHYBASE + USB_PHY_RANGE,
|
|
||||||
.flags = IORESOURCE_MEM,
|
|
||||||
.name = "phyregs",
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
.start = IRQ_PXA168_USB1,
|
.start = IRQ_PXA168_USB1,
|
||||||
.end = IRQ_PXA168_USB1,
|
.end = IRQ_PXA168_USB1,
|
||||||
.flags = IORESOURCE_IRQ,
|
.flags = IORESOURCE_IRQ,
|
||||||
|
|
|
@ -116,6 +116,7 @@ static void em28xx_audio_isocirq(struct urb *urb)
|
||||||
stride = runtime->frame_bits >> 3;
|
stride = runtime->frame_bits >> 3;
|
||||||
|
|
||||||
for (i = 0; i < urb->number_of_packets; i++) {
|
for (i = 0; i < urb->number_of_packets; i++) {
|
||||||
|
unsigned long flags;
|
||||||
int length =
|
int length =
|
||||||
urb->iso_frame_desc[i].actual_length / stride;
|
urb->iso_frame_desc[i].actual_length / stride;
|
||||||
cp = (unsigned char *)urb->transfer_buffer +
|
cp = (unsigned char *)urb->transfer_buffer +
|
||||||
|
@ -137,7 +138,7 @@ static void em28xx_audio_isocirq(struct urb *urb)
|
||||||
length * stride);
|
length * stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
snd_pcm_stream_lock(substream);
|
snd_pcm_stream_lock_irqsave(substream, flags);
|
||||||
|
|
||||||
dev->adev.hwptr_done_capture += length;
|
dev->adev.hwptr_done_capture += length;
|
||||||
if (dev->adev.hwptr_done_capture >=
|
if (dev->adev.hwptr_done_capture >=
|
||||||
|
@ -153,7 +154,7 @@ static void em28xx_audio_isocirq(struct urb *urb)
|
||||||
period_elapsed = 1;
|
period_elapsed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
snd_pcm_stream_unlock(substream);
|
snd_pcm_stream_unlock_irqrestore(substream, flags);
|
||||||
}
|
}
|
||||||
if (period_elapsed)
|
if (period_elapsed)
|
||||||
snd_pcm_period_elapsed(substream);
|
snd_pcm_period_elapsed(substream);
|
||||||
|
|
|
@ -777,6 +777,7 @@ EXPORT_SYMBOL_GPL(em28xx_set_mode);
|
||||||
static void em28xx_irq_callback(struct urb *urb)
|
static void em28xx_irq_callback(struct urb *urb)
|
||||||
{
|
{
|
||||||
struct em28xx *dev = urb->context;
|
struct em28xx *dev = urb->context;
|
||||||
|
unsigned long flags;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
switch (urb->status) {
|
switch (urb->status) {
|
||||||
|
@ -793,9 +794,9 @@ static void em28xx_irq_callback(struct urb *urb)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy data from URB */
|
/* Copy data from URB */
|
||||||
spin_lock(&dev->slock);
|
spin_lock_irqsave(&dev->slock, flags);
|
||||||
dev->usb_ctl.urb_data_copy(dev, urb);
|
dev->usb_ctl.urb_data_copy(dev, urb);
|
||||||
spin_unlock(&dev->slock);
|
spin_unlock_irqrestore(&dev->slock, flags);
|
||||||
|
|
||||||
/* Reset urb buffers */
|
/* Reset urb buffers */
|
||||||
for (i = 0; i < urb->number_of_packets; i++) {
|
for (i = 0; i < urb->number_of_packets; i++) {
|
||||||
|
|
|
@ -419,6 +419,7 @@ static void tm6000_irq_callback(struct urb *urb)
|
||||||
{
|
{
|
||||||
struct tm6000_dmaqueue *dma_q = urb->context;
|
struct tm6000_dmaqueue *dma_q = urb->context;
|
||||||
struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
|
struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
|
||||||
|
unsigned long flags;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
switch (urb->status) {
|
switch (urb->status) {
|
||||||
|
@ -436,9 +437,9 @@ static void tm6000_irq_callback(struct urb *urb)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&dev->slock);
|
spin_lock_irqsave(&dev->slock, flags);
|
||||||
tm6000_isoc_copy(urb);
|
tm6000_isoc_copy(urb);
|
||||||
spin_unlock(&dev->slock);
|
spin_unlock_irqrestore(&dev->slock, flags);
|
||||||
|
|
||||||
/* Reset urb buffers */
|
/* Reset urb buffers */
|
||||||
for (i = 0; i < urb->number_of_packets; i++) {
|
for (i = 0; i < urb->number_of_packets; i++) {
|
||||||
|
|
|
@ -43,6 +43,7 @@ config PHY_XGENE
|
||||||
source "drivers/phy/allwinner/Kconfig"
|
source "drivers/phy/allwinner/Kconfig"
|
||||||
source "drivers/phy/amlogic/Kconfig"
|
source "drivers/phy/amlogic/Kconfig"
|
||||||
source "drivers/phy/broadcom/Kconfig"
|
source "drivers/phy/broadcom/Kconfig"
|
||||||
|
source "drivers/phy/cadence/Kconfig"
|
||||||
source "drivers/phy/hisilicon/Kconfig"
|
source "drivers/phy/hisilicon/Kconfig"
|
||||||
source "drivers/phy/lantiq/Kconfig"
|
source "drivers/phy/lantiq/Kconfig"
|
||||||
source "drivers/phy/marvell/Kconfig"
|
source "drivers/phy/marvell/Kconfig"
|
||||||
|
@ -54,6 +55,7 @@ source "drivers/phy/ralink/Kconfig"
|
||||||
source "drivers/phy/renesas/Kconfig"
|
source "drivers/phy/renesas/Kconfig"
|
||||||
source "drivers/phy/rockchip/Kconfig"
|
source "drivers/phy/rockchip/Kconfig"
|
||||||
source "drivers/phy/samsung/Kconfig"
|
source "drivers/phy/samsung/Kconfig"
|
||||||
|
source "drivers/phy/socionext/Kconfig"
|
||||||
source "drivers/phy/st/Kconfig"
|
source "drivers/phy/st/Kconfig"
|
||||||
source "drivers/phy/tegra/Kconfig"
|
source "drivers/phy/tegra/Kconfig"
|
||||||
source "drivers/phy/ti/Kconfig"
|
source "drivers/phy/ti/Kconfig"
|
||||||
|
|
|
@ -15,6 +15,7 @@ obj-$(CONFIG_ARCH_RENESAS) += renesas/
|
||||||
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
|
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
|
||||||
obj-$(CONFIG_ARCH_TEGRA) += tegra/
|
obj-$(CONFIG_ARCH_TEGRA) += tegra/
|
||||||
obj-y += broadcom/ \
|
obj-y += broadcom/ \
|
||||||
|
cadence/ \
|
||||||
hisilicon/ \
|
hisilicon/ \
|
||||||
marvell/ \
|
marvell/ \
|
||||||
motorola/ \
|
motorola/ \
|
||||||
|
@ -22,5 +23,6 @@ obj-y += broadcom/ \
|
||||||
qualcomm/ \
|
qualcomm/ \
|
||||||
ralink/ \
|
ralink/ \
|
||||||
samsung/ \
|
samsung/ \
|
||||||
|
socionext/ \
|
||||||
st/ \
|
st/ \
|
||||||
ti/
|
ti/
|
||||||
|
|
|
@ -60,7 +60,8 @@ config PHY_NS2_USB_DRD
|
||||||
|
|
||||||
config PHY_BRCM_SATA
|
config PHY_BRCM_SATA
|
||||||
tristate "Broadcom SATA PHY driver"
|
tristate "Broadcom SATA PHY driver"
|
||||||
depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || COMPILE_TEST
|
depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || \
|
||||||
|
ARCH_BCM_63XX || COMPILE_TEST
|
||||||
depends on OF
|
depends on OF
|
||||||
select GENERIC_PHY
|
select GENERIC_PHY
|
||||||
default ARCH_BCM_IPROC
|
default ARCH_BCM_IPROC
|
||||||
|
|
|
@ -153,8 +153,8 @@ static int cygnus_pcie_phy_probe(struct platform_device *pdev)
|
||||||
struct cygnus_pcie_phy *p;
|
struct cygnus_pcie_phy *p;
|
||||||
|
|
||||||
if (of_property_read_u32(child, "reg", &id)) {
|
if (of_property_read_u32(child, "reg", &id)) {
|
||||||
dev_err(dev, "missing reg property for %s\n",
|
dev_err(dev, "missing reg property for %pOFn\n",
|
||||||
child->name);
|
child);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto put_child;
|
goto put_child;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ enum brcm_sata_phy_version {
|
||||||
BRCM_SATA_PHY_IPROC_NS2,
|
BRCM_SATA_PHY_IPROC_NS2,
|
||||||
BRCM_SATA_PHY_IPROC_NSP,
|
BRCM_SATA_PHY_IPROC_NSP,
|
||||||
BRCM_SATA_PHY_IPROC_SR,
|
BRCM_SATA_PHY_IPROC_SR,
|
||||||
|
BRCM_SATA_PHY_DSL_28NM,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum brcm_sata_phy_rxaeq_mode {
|
enum brcm_sata_phy_rxaeq_mode {
|
||||||
|
@ -96,7 +97,10 @@ enum sata_phy_regs {
|
||||||
PLLCONTROL_0_FREQ_DET_RESTART = BIT(13),
|
PLLCONTROL_0_FREQ_DET_RESTART = BIT(13),
|
||||||
PLLCONTROL_0_FREQ_MONITOR = BIT(12),
|
PLLCONTROL_0_FREQ_MONITOR = BIT(12),
|
||||||
PLLCONTROL_0_SEQ_START = BIT(15),
|
PLLCONTROL_0_SEQ_START = BIT(15),
|
||||||
|
PLL_CAP_CHARGE_TIME = 0x83,
|
||||||
|
PLL_VCO_CAL_THRESH = 0x84,
|
||||||
PLL_CAP_CONTROL = 0x85,
|
PLL_CAP_CONTROL = 0x85,
|
||||||
|
PLL_FREQ_DET_TIME = 0x86,
|
||||||
PLL_ACTRL2 = 0x8b,
|
PLL_ACTRL2 = 0x8b,
|
||||||
PLL_ACTRL2_SELDIV_MASK = 0x1f,
|
PLL_ACTRL2_SELDIV_MASK = 0x1f,
|
||||||
PLL_ACTRL2_SELDIV_SHIFT = 9,
|
PLL_ACTRL2_SELDIV_SHIFT = 9,
|
||||||
|
@ -106,6 +110,9 @@ enum sata_phy_regs {
|
||||||
PLL1_ACTRL2 = 0x82,
|
PLL1_ACTRL2 = 0x82,
|
||||||
PLL1_ACTRL3 = 0x83,
|
PLL1_ACTRL3 = 0x83,
|
||||||
PLL1_ACTRL4 = 0x84,
|
PLL1_ACTRL4 = 0x84,
|
||||||
|
PLL1_ACTRL5 = 0x85,
|
||||||
|
PLL1_ACTRL6 = 0x86,
|
||||||
|
PLL1_ACTRL7 = 0x87,
|
||||||
|
|
||||||
TX_REG_BANK = 0x070,
|
TX_REG_BANK = 0x070,
|
||||||
TX_ACTRL0 = 0x80,
|
TX_ACTRL0 = 0x80,
|
||||||
|
@ -119,6 +126,8 @@ enum sata_phy_regs {
|
||||||
AEQ_FRC_EQ_FORCE = BIT(0),
|
AEQ_FRC_EQ_FORCE = BIT(0),
|
||||||
AEQ_FRC_EQ_FORCE_VAL = BIT(1),
|
AEQ_FRC_EQ_FORCE_VAL = BIT(1),
|
||||||
AEQRX_REG_BANK_1 = 0xe0,
|
AEQRX_REG_BANK_1 = 0xe0,
|
||||||
|
AEQRX_SLCAL0_CTRL0 = 0x82,
|
||||||
|
AEQRX_SLCAL1_CTRL0 = 0x86,
|
||||||
|
|
||||||
OOB_REG_BANK = 0x150,
|
OOB_REG_BANK = 0x150,
|
||||||
OOB1_REG_BANK = 0x160,
|
OOB1_REG_BANK = 0x160,
|
||||||
|
@ -168,6 +177,7 @@ static inline void __iomem *brcm_sata_pcb_base(struct brcm_sata_port *port)
|
||||||
switch (priv->version) {
|
switch (priv->version) {
|
||||||
case BRCM_SATA_PHY_STB_28NM:
|
case BRCM_SATA_PHY_STB_28NM:
|
||||||
case BRCM_SATA_PHY_IPROC_NS2:
|
case BRCM_SATA_PHY_IPROC_NS2:
|
||||||
|
case BRCM_SATA_PHY_DSL_28NM:
|
||||||
size = SATA_PCB_REG_28NM_SPACE_SIZE;
|
size = SATA_PCB_REG_28NM_SPACE_SIZE;
|
||||||
break;
|
break;
|
||||||
case BRCM_SATA_PHY_STB_40NM:
|
case BRCM_SATA_PHY_STB_40NM:
|
||||||
|
@ -482,6 +492,61 @@ static int brcm_sr_sata_init(struct brcm_sata_port *port)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int brcm_dsl_sata_init(struct brcm_sata_port *port)
|
||||||
|
{
|
||||||
|
void __iomem *base = brcm_sata_pcb_base(port);
|
||||||
|
struct device *dev = port->phy_priv->dev;
|
||||||
|
unsigned int try;
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL7, 0, 0x873);
|
||||||
|
|
||||||
|
brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL6, 0, 0xc000);
|
||||||
|
|
||||||
|
brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
|
||||||
|
0, 0x3089);
|
||||||
|
usleep_range(1000, 2000);
|
||||||
|
|
||||||
|
brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
|
||||||
|
0, 0x3088);
|
||||||
|
usleep_range(1000, 2000);
|
||||||
|
|
||||||
|
brcm_sata_phy_wr(base, AEQRX_REG_BANK_1, AEQRX_SLCAL0_CTRL0,
|
||||||
|
0, 0x3000);
|
||||||
|
|
||||||
|
brcm_sata_phy_wr(base, AEQRX_REG_BANK_1, AEQRX_SLCAL1_CTRL0,
|
||||||
|
0, 0x3000);
|
||||||
|
usleep_range(1000, 2000);
|
||||||
|
|
||||||
|
brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_CAP_CHARGE_TIME, 0, 0x32);
|
||||||
|
|
||||||
|
brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_VCO_CAL_THRESH, 0, 0xa);
|
||||||
|
|
||||||
|
brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_FREQ_DET_TIME, 0, 0x64);
|
||||||
|
usleep_range(1000, 2000);
|
||||||
|
|
||||||
|
/* Acquire PLL lock */
|
||||||
|
try = 50;
|
||||||
|
while (try) {
|
||||||
|
tmp = brcm_sata_phy_rd(base, BLOCK0_REG_BANK,
|
||||||
|
BLOCK0_XGXSSTATUS);
|
||||||
|
if (tmp & 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;
|
int rc;
|
||||||
|
@ -501,6 +566,9 @@ static int brcm_sata_phy_init(struct phy *phy)
|
||||||
case BRCM_SATA_PHY_IPROC_SR:
|
case BRCM_SATA_PHY_IPROC_SR:
|
||||||
rc = brcm_sr_sata_init(port);
|
rc = brcm_sr_sata_init(port);
|
||||||
break;
|
break;
|
||||||
|
case BRCM_SATA_PHY_DSL_28NM:
|
||||||
|
rc = brcm_dsl_sata_init(port);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
rc = -ENODEV;
|
rc = -ENODEV;
|
||||||
}
|
}
|
||||||
|
@ -552,6 +620,8 @@ static const struct of_device_id brcm_sata_phy_of_match[] = {
|
||||||
.data = (void *)BRCM_SATA_PHY_IPROC_NSP },
|
.data = (void *)BRCM_SATA_PHY_IPROC_NSP },
|
||||||
{ .compatible = "brcm,iproc-sr-sata-phy",
|
{ .compatible = "brcm,iproc-sr-sata-phy",
|
||||||
.data = (void *)BRCM_SATA_PHY_IPROC_SR },
|
.data = (void *)BRCM_SATA_PHY_IPROC_SR },
|
||||||
|
{ .compatible = "brcm,bcm63138-sata-phy",
|
||||||
|
.data = (void *)BRCM_SATA_PHY_DSL_28NM },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match);
|
MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match);
|
||||||
|
@ -600,8 +670,8 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
|
||||||
struct brcm_sata_port *port;
|
struct brcm_sata_port *port;
|
||||||
|
|
||||||
if (of_property_read_u32(child, "reg", &id)) {
|
if (of_property_read_u32(child, "reg", &id)) {
|
||||||
dev_err(dev, "missing reg property in node %s\n",
|
dev_err(dev, "missing reg property in node %pOFn\n",
|
||||||
child->name);
|
child);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto put_child;
|
goto put_child;
|
||||||
}
|
}
|
||||||
|
|
|
@ -372,10 +372,8 @@ static int brcm_usb_phy_probe(struct platform_device *pdev)
|
||||||
clk_disable(priv->usb_30_clk);
|
clk_disable(priv->usb_30_clk);
|
||||||
|
|
||||||
phy_provider = devm_of_phy_provider_register(dev, brcm_usb_phy_xlate);
|
phy_provider = devm_of_phy_provider_register(dev, brcm_usb_phy_xlate);
|
||||||
if (IS_ERR(phy_provider))
|
|
||||||
return PTR_ERR(phy_provider);
|
|
||||||
|
|
||||||
return 0;
|
return PTR_ERR_OR_ZERO(phy_provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
|
10
drivers/phy/cadence/Kconfig
Normal file
10
drivers/phy/cadence/Kconfig
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#
|
||||||
|
# Phy driver for Cadence MHDP DisplayPort controller
|
||||||
|
#
|
||||||
|
config PHY_CADENCE_DP
|
||||||
|
tristate "Cadence MHDP DisplayPort PHY driver"
|
||||||
|
depends on OF
|
||||||
|
depends on HAS_IOMEM
|
||||||
|
select GENERIC_PHY
|
||||||
|
help
|
||||||
|
Support for Cadence MHDP DisplayPort PHY.
|
1
drivers/phy/cadence/Makefile
Normal file
1
drivers/phy/cadence/Makefile
Normal file
|
@ -0,0 +1 @@
|
||||||
|
obj-$(CONFIG_PHY_CADENCE_DP) += phy-cadence-dp.o
|
541
drivers/phy/cadence/phy-cadence-dp.c
Normal file
541
drivers/phy/cadence/phy-cadence-dp.c
Normal file
|
@ -0,0 +1,541 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Cadence MHDP DisplayPort SD0801 PHY driver.
|
||||||
|
*
|
||||||
|
* Copyright 2018 Cadence Design Systems, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/phy/phy.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#define DEFAULT_NUM_LANES 2
|
||||||
|
#define MAX_NUM_LANES 4
|
||||||
|
#define DEFAULT_MAX_BIT_RATE 8100 /* in Mbps */
|
||||||
|
|
||||||
|
#define POLL_TIMEOUT_US 2000
|
||||||
|
#define LANE_MASK 0x7
|
||||||
|
|
||||||
|
/*
|
||||||
|
* register offsets from DPTX PHY register block base (i.e MHDP
|
||||||
|
* register base + 0x30a00)
|
||||||
|
*/
|
||||||
|
#define PHY_AUX_CONFIG 0x00
|
||||||
|
#define PHY_AUX_CTRL 0x04
|
||||||
|
#define PHY_RESET 0x20
|
||||||
|
#define PHY_PMA_XCVR_PLLCLK_EN 0x24
|
||||||
|
#define PHY_PMA_XCVR_PLLCLK_EN_ACK 0x28
|
||||||
|
#define PHY_PMA_XCVR_POWER_STATE_REQ 0x2c
|
||||||
|
#define PHY_POWER_STATE_LN_0 0x0000
|
||||||
|
#define PHY_POWER_STATE_LN_1 0x0008
|
||||||
|
#define PHY_POWER_STATE_LN_2 0x0010
|
||||||
|
#define PHY_POWER_STATE_LN_3 0x0018
|
||||||
|
#define PHY_PMA_XCVR_POWER_STATE_ACK 0x30
|
||||||
|
#define PHY_PMA_CMN_READY 0x34
|
||||||
|
#define PHY_PMA_XCVR_TX_VMARGIN 0x38
|
||||||
|
#define PHY_PMA_XCVR_TX_DEEMPH 0x3c
|
||||||
|
|
||||||
|
/*
|
||||||
|
* register offsets from SD0801 PHY register block base (i.e MHDP
|
||||||
|
* register base + 0x500000)
|
||||||
|
*/
|
||||||
|
#define CMN_SSM_BANDGAP_TMR 0x00084
|
||||||
|
#define CMN_SSM_BIAS_TMR 0x00088
|
||||||
|
#define CMN_PLLSM0_PLLPRE_TMR 0x000a8
|
||||||
|
#define CMN_PLLSM0_PLLLOCK_TMR 0x000b0
|
||||||
|
#define CMN_PLLSM1_PLLPRE_TMR 0x000c8
|
||||||
|
#define CMN_PLLSM1_PLLLOCK_TMR 0x000d0
|
||||||
|
#define CMN_BGCAL_INIT_TMR 0x00190
|
||||||
|
#define CMN_BGCAL_ITER_TMR 0x00194
|
||||||
|
#define CMN_IBCAL_INIT_TMR 0x001d0
|
||||||
|
#define CMN_PLL0_VCOCAL_INIT_TMR 0x00210
|
||||||
|
#define CMN_PLL0_VCOCAL_ITER_TMR 0x00214
|
||||||
|
#define CMN_PLL0_VCOCAL_REFTIM_START 0x00218
|
||||||
|
#define CMN_PLL0_VCOCAL_PLLCNT_START 0x00220
|
||||||
|
#define CMN_PLL0_INTDIV_M0 0x00240
|
||||||
|
#define CMN_PLL0_FRACDIVL_M0 0x00244
|
||||||
|
#define CMN_PLL0_FRACDIVH_M0 0x00248
|
||||||
|
#define CMN_PLL0_HIGH_THR_M0 0x0024c
|
||||||
|
#define CMN_PLL0_DSM_DIAG_M0 0x00250
|
||||||
|
#define CMN_PLL0_LOCK_PLLCNT_START 0x00278
|
||||||
|
#define CMN_PLL1_VCOCAL_INIT_TMR 0x00310
|
||||||
|
#define CMN_PLL1_VCOCAL_ITER_TMR 0x00314
|
||||||
|
#define CMN_PLL1_DSM_DIAG_M0 0x00350
|
||||||
|
#define CMN_TXPUCAL_INIT_TMR 0x00410
|
||||||
|
#define CMN_TXPUCAL_ITER_TMR 0x00414
|
||||||
|
#define CMN_TXPDCAL_INIT_TMR 0x00430
|
||||||
|
#define CMN_TXPDCAL_ITER_TMR 0x00434
|
||||||
|
#define CMN_RXCAL_INIT_TMR 0x00450
|
||||||
|
#define CMN_RXCAL_ITER_TMR 0x00454
|
||||||
|
#define CMN_SD_CAL_INIT_TMR 0x00490
|
||||||
|
#define CMN_SD_CAL_ITER_TMR 0x00494
|
||||||
|
#define CMN_SD_CAL_REFTIM_START 0x00498
|
||||||
|
#define CMN_SD_CAL_PLLCNT_START 0x004a0
|
||||||
|
#define CMN_PDIAG_PLL0_CTRL_M0 0x00680
|
||||||
|
#define CMN_PDIAG_PLL0_CLK_SEL_M0 0x00684
|
||||||
|
#define CMN_PDIAG_PLL0_CP_PADJ_M0 0x00690
|
||||||
|
#define CMN_PDIAG_PLL0_CP_IADJ_M0 0x00694
|
||||||
|
#define CMN_PDIAG_PLL0_FILT_PADJ_M0 0x00698
|
||||||
|
#define CMN_PDIAG_PLL0_CP_PADJ_M1 0x006d0
|
||||||
|
#define CMN_PDIAG_PLL0_CP_IADJ_M1 0x006d4
|
||||||
|
#define CMN_PDIAG_PLL1_CLK_SEL_M0 0x00704
|
||||||
|
#define XCVR_DIAG_PLLDRC_CTRL 0x10394
|
||||||
|
#define XCVR_DIAG_HSCLK_SEL 0x10398
|
||||||
|
#define XCVR_DIAG_HSCLK_DIV 0x1039c
|
||||||
|
#define TX_PSC_A0 0x10400
|
||||||
|
#define TX_PSC_A1 0x10404
|
||||||
|
#define TX_PSC_A2 0x10408
|
||||||
|
#define TX_PSC_A3 0x1040c
|
||||||
|
#define RX_PSC_A0 0x20000
|
||||||
|
#define RX_PSC_A1 0x20004
|
||||||
|
#define RX_PSC_A2 0x20008
|
||||||
|
#define RX_PSC_A3 0x2000c
|
||||||
|
#define PHY_PLL_CFG 0x30038
|
||||||
|
|
||||||
|
struct cdns_dp_phy {
|
||||||
|
void __iomem *base; /* DPTX registers base */
|
||||||
|
void __iomem *sd_base; /* SD0801 registers base */
|
||||||
|
u32 num_lanes; /* Number of lanes to use */
|
||||||
|
u32 max_bit_rate; /* Maximum link bit rate to use (in Mbps) */
|
||||||
|
struct device *dev;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int cdns_dp_phy_init(struct phy *phy);
|
||||||
|
static void cdns_dp_phy_run(struct cdns_dp_phy *cdns_phy);
|
||||||
|
static void cdns_dp_phy_wait_pma_cmn_ready(struct cdns_dp_phy *cdns_phy);
|
||||||
|
static void cdns_dp_phy_pma_cfg(struct cdns_dp_phy *cdns_phy);
|
||||||
|
static void cdns_dp_phy_pma_cmn_cfg_25mhz(struct cdns_dp_phy *cdns_phy);
|
||||||
|
static void cdns_dp_phy_pma_lane_cfg(struct cdns_dp_phy *cdns_phy,
|
||||||
|
unsigned int lane);
|
||||||
|
static void cdns_dp_phy_pma_cmn_vco_cfg_25mhz(struct cdns_dp_phy *cdns_phy);
|
||||||
|
static void cdns_dp_phy_pma_cmn_rate(struct cdns_dp_phy *cdns_phy);
|
||||||
|
static void cdns_dp_phy_write_field(struct cdns_dp_phy *cdns_phy,
|
||||||
|
unsigned int offset,
|
||||||
|
unsigned char start_bit,
|
||||||
|
unsigned char num_bits,
|
||||||
|
unsigned int val);
|
||||||
|
|
||||||
|
static const struct phy_ops cdns_dp_phy_ops = {
|
||||||
|
.init = cdns_dp_phy_init,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int cdns_dp_phy_init(struct phy *phy)
|
||||||
|
{
|
||||||
|
unsigned char lane_bits;
|
||||||
|
|
||||||
|
struct cdns_dp_phy *cdns_phy = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
writel(0x0003, cdns_phy->base + PHY_AUX_CTRL); /* enable AUX */
|
||||||
|
|
||||||
|
/* PHY PMA registers configuration function */
|
||||||
|
cdns_dp_phy_pma_cfg(cdns_phy);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set lines power state to A0
|
||||||
|
* Set lines pll clk enable to 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_POWER_STATE_REQ,
|
||||||
|
PHY_POWER_STATE_LN_0, 6, 0x0000);
|
||||||
|
|
||||||
|
if (cdns_phy->num_lanes >= 2) {
|
||||||
|
cdns_dp_phy_write_field(cdns_phy,
|
||||||
|
PHY_PMA_XCVR_POWER_STATE_REQ,
|
||||||
|
PHY_POWER_STATE_LN_1, 6, 0x0000);
|
||||||
|
|
||||||
|
if (cdns_phy->num_lanes == 4) {
|
||||||
|
cdns_dp_phy_write_field(cdns_phy,
|
||||||
|
PHY_PMA_XCVR_POWER_STATE_REQ,
|
||||||
|
PHY_POWER_STATE_LN_2, 6, 0);
|
||||||
|
cdns_dp_phy_write_field(cdns_phy,
|
||||||
|
PHY_PMA_XCVR_POWER_STATE_REQ,
|
||||||
|
PHY_POWER_STATE_LN_3, 6, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN,
|
||||||
|
0, 1, 0x0000);
|
||||||
|
|
||||||
|
if (cdns_phy->num_lanes >= 2) {
|
||||||
|
cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN,
|
||||||
|
1, 1, 0x0000);
|
||||||
|
if (cdns_phy->num_lanes == 4) {
|
||||||
|
cdns_dp_phy_write_field(cdns_phy,
|
||||||
|
PHY_PMA_XCVR_PLLCLK_EN,
|
||||||
|
2, 1, 0x0000);
|
||||||
|
cdns_dp_phy_write_field(cdns_phy,
|
||||||
|
PHY_PMA_XCVR_PLLCLK_EN,
|
||||||
|
3, 1, 0x0000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on
|
||||||
|
* used lanes
|
||||||
|
*/
|
||||||
|
lane_bits = (1 << cdns_phy->num_lanes) - 1;
|
||||||
|
writel(((0xF & ~lane_bits) << 4) | (0xF & lane_bits),
|
||||||
|
cdns_phy->base + PHY_RESET);
|
||||||
|
|
||||||
|
/* release pma_xcvr_pllclk_en_ln_*, only for the master lane */
|
||||||
|
writel(0x0001, cdns_phy->base + PHY_PMA_XCVR_PLLCLK_EN);
|
||||||
|
|
||||||
|
/* PHY PMA registers configuration functions */
|
||||||
|
cdns_dp_phy_pma_cmn_vco_cfg_25mhz(cdns_phy);
|
||||||
|
cdns_dp_phy_pma_cmn_rate(cdns_phy);
|
||||||
|
|
||||||
|
/* take out of reset */
|
||||||
|
cdns_dp_phy_write_field(cdns_phy, PHY_RESET, 8, 1, 1);
|
||||||
|
cdns_dp_phy_wait_pma_cmn_ready(cdns_phy);
|
||||||
|
cdns_dp_phy_run(cdns_phy);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cdns_dp_phy_wait_pma_cmn_ready(struct cdns_dp_phy *cdns_phy)
|
||||||
|
{
|
||||||
|
unsigned int reg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_CMN_READY, reg,
|
||||||
|
reg & 1, 0, 500);
|
||||||
|
if (ret == -ETIMEDOUT)
|
||||||
|
dev_err(cdns_phy->dev,
|
||||||
|
"timeout waiting for PMA common ready\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cdns_dp_phy_pma_cfg(struct cdns_dp_phy *cdns_phy)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
/* PMA common configuration */
|
||||||
|
cdns_dp_phy_pma_cmn_cfg_25mhz(cdns_phy);
|
||||||
|
|
||||||
|
/* PMA lane configuration to deal with multi-link operation */
|
||||||
|
for (i = 0; i < cdns_phy->num_lanes; i++)
|
||||||
|
cdns_dp_phy_pma_lane_cfg(cdns_phy, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cdns_dp_phy_pma_cmn_cfg_25mhz(struct cdns_dp_phy *cdns_phy)
|
||||||
|
{
|
||||||
|
/* refclock registers - assumes 25 MHz refclock */
|
||||||
|
writel(0x0019, cdns_phy->sd_base + CMN_SSM_BIAS_TMR);
|
||||||
|
writel(0x0032, cdns_phy->sd_base + CMN_PLLSM0_PLLPRE_TMR);
|
||||||
|
writel(0x00D1, cdns_phy->sd_base + CMN_PLLSM0_PLLLOCK_TMR);
|
||||||
|
writel(0x0032, cdns_phy->sd_base + CMN_PLLSM1_PLLPRE_TMR);
|
||||||
|
writel(0x00D1, cdns_phy->sd_base + CMN_PLLSM1_PLLLOCK_TMR);
|
||||||
|
writel(0x007D, cdns_phy->sd_base + CMN_BGCAL_INIT_TMR);
|
||||||
|
writel(0x007D, cdns_phy->sd_base + CMN_BGCAL_ITER_TMR);
|
||||||
|
writel(0x0019, cdns_phy->sd_base + CMN_IBCAL_INIT_TMR);
|
||||||
|
writel(0x001E, cdns_phy->sd_base + CMN_TXPUCAL_INIT_TMR);
|
||||||
|
writel(0x0006, cdns_phy->sd_base + CMN_TXPUCAL_ITER_TMR);
|
||||||
|
writel(0x001E, cdns_phy->sd_base + CMN_TXPDCAL_INIT_TMR);
|
||||||
|
writel(0x0006, cdns_phy->sd_base + CMN_TXPDCAL_ITER_TMR);
|
||||||
|
writel(0x02EE, cdns_phy->sd_base + CMN_RXCAL_INIT_TMR);
|
||||||
|
writel(0x0006, cdns_phy->sd_base + CMN_RXCAL_ITER_TMR);
|
||||||
|
writel(0x0002, cdns_phy->sd_base + CMN_SD_CAL_INIT_TMR);
|
||||||
|
writel(0x0002, cdns_phy->sd_base + CMN_SD_CAL_ITER_TMR);
|
||||||
|
writel(0x000E, cdns_phy->sd_base + CMN_SD_CAL_REFTIM_START);
|
||||||
|
writel(0x012B, cdns_phy->sd_base + CMN_SD_CAL_PLLCNT_START);
|
||||||
|
/* PLL registers */
|
||||||
|
writel(0x0409, cdns_phy->sd_base + CMN_PDIAG_PLL0_CP_PADJ_M0);
|
||||||
|
writel(0x1001, cdns_phy->sd_base + CMN_PDIAG_PLL0_CP_IADJ_M0);
|
||||||
|
writel(0x0F08, cdns_phy->sd_base + CMN_PDIAG_PLL0_FILT_PADJ_M0);
|
||||||
|
writel(0x0004, cdns_phy->sd_base + CMN_PLL0_DSM_DIAG_M0);
|
||||||
|
writel(0x00FA, cdns_phy->sd_base + CMN_PLL0_VCOCAL_INIT_TMR);
|
||||||
|
writel(0x0004, cdns_phy->sd_base + CMN_PLL0_VCOCAL_ITER_TMR);
|
||||||
|
writel(0x00FA, cdns_phy->sd_base + CMN_PLL1_VCOCAL_INIT_TMR);
|
||||||
|
writel(0x0004, cdns_phy->sd_base + CMN_PLL1_VCOCAL_ITER_TMR);
|
||||||
|
writel(0x0318, cdns_phy->sd_base + CMN_PLL0_VCOCAL_REFTIM_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cdns_dp_phy_pma_cmn_vco_cfg_25mhz(struct cdns_dp_phy *cdns_phy)
|
||||||
|
{
|
||||||
|
/* Assumes 25 MHz refclock */
|
||||||
|
switch (cdns_phy->max_bit_rate) {
|
||||||
|
/* Setting VCO for 10.8GHz */
|
||||||
|
case 2700:
|
||||||
|
case 5400:
|
||||||
|
writel(0x01B0, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0);
|
||||||
|
writel(0x0000, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0);
|
||||||
|
writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0);
|
||||||
|
writel(0x0120, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0);
|
||||||
|
break;
|
||||||
|
/* Setting VCO for 9.72GHz */
|
||||||
|
case 2430:
|
||||||
|
case 3240:
|
||||||
|
writel(0x0184, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0);
|
||||||
|
writel(0xCCCD, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0);
|
||||||
|
writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0);
|
||||||
|
writel(0x0104, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0);
|
||||||
|
break;
|
||||||
|
/* Setting VCO for 8.64GHz */
|
||||||
|
case 2160:
|
||||||
|
case 4320:
|
||||||
|
writel(0x0159, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0);
|
||||||
|
writel(0x999A, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0);
|
||||||
|
writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0);
|
||||||
|
writel(0x00E7, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0);
|
||||||
|
break;
|
||||||
|
/* Setting VCO for 8.1GHz */
|
||||||
|
case 8100:
|
||||||
|
writel(0x0144, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0);
|
||||||
|
writel(0x0000, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0);
|
||||||
|
writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0);
|
||||||
|
writel(0x00D8, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
writel(0x0002, cdns_phy->sd_base + CMN_PDIAG_PLL0_CTRL_M0);
|
||||||
|
writel(0x0318, cdns_phy->sd_base + CMN_PLL0_VCOCAL_PLLCNT_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cdns_dp_phy_pma_cmn_rate(struct cdns_dp_phy *cdns_phy)
|
||||||
|
{
|
||||||
|
unsigned int clk_sel_val = 0;
|
||||||
|
unsigned int hsclk_div_val = 0;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
/* 16'h0000 for single DP link configuration */
|
||||||
|
writel(0x0000, cdns_phy->sd_base + PHY_PLL_CFG);
|
||||||
|
|
||||||
|
switch (cdns_phy->max_bit_rate) {
|
||||||
|
case 1620:
|
||||||
|
clk_sel_val = 0x0f01;
|
||||||
|
hsclk_div_val = 2;
|
||||||
|
break;
|
||||||
|
case 2160:
|
||||||
|
case 2430:
|
||||||
|
case 2700:
|
||||||
|
clk_sel_val = 0x0701;
|
||||||
|
hsclk_div_val = 1;
|
||||||
|
break;
|
||||||
|
case 3240:
|
||||||
|
clk_sel_val = 0x0b00;
|
||||||
|
hsclk_div_val = 2;
|
||||||
|
break;
|
||||||
|
case 4320:
|
||||||
|
case 5400:
|
||||||
|
clk_sel_val = 0x0301;
|
||||||
|
hsclk_div_val = 0;
|
||||||
|
break;
|
||||||
|
case 8100:
|
||||||
|
clk_sel_val = 0x0200;
|
||||||
|
hsclk_div_val = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
writel(clk_sel_val, cdns_phy->sd_base + CMN_PDIAG_PLL0_CLK_SEL_M0);
|
||||||
|
|
||||||
|
/* PMA lane configuration to deal with multi-link operation */
|
||||||
|
for (i = 0; i < cdns_phy->num_lanes; i++) {
|
||||||
|
writel(hsclk_div_val,
|
||||||
|
cdns_phy->sd_base + (XCVR_DIAG_HSCLK_DIV | (i<<11)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cdns_dp_phy_pma_lane_cfg(struct cdns_dp_phy *cdns_phy,
|
||||||
|
unsigned int lane)
|
||||||
|
{
|
||||||
|
unsigned int lane_bits = (lane & LANE_MASK) << 11;
|
||||||
|
|
||||||
|
/* Writing Tx/Rx Power State Controllers registers */
|
||||||
|
writel(0x00FB, cdns_phy->sd_base + (TX_PSC_A0 | lane_bits));
|
||||||
|
writel(0x04AA, cdns_phy->sd_base + (TX_PSC_A2 | lane_bits));
|
||||||
|
writel(0x04AA, cdns_phy->sd_base + (TX_PSC_A3 | lane_bits));
|
||||||
|
writel(0x0000, cdns_phy->sd_base + (RX_PSC_A0 | lane_bits));
|
||||||
|
writel(0x0000, cdns_phy->sd_base + (RX_PSC_A2 | lane_bits));
|
||||||
|
writel(0x0000, cdns_phy->sd_base + (RX_PSC_A3 | lane_bits));
|
||||||
|
|
||||||
|
writel(0x0001, cdns_phy->sd_base + (XCVR_DIAG_PLLDRC_CTRL | lane_bits));
|
||||||
|
writel(0x0000, cdns_phy->sd_base + (XCVR_DIAG_HSCLK_SEL | lane_bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cdns_dp_phy_run(struct cdns_dp_phy *cdns_phy)
|
||||||
|
{
|
||||||
|
unsigned int read_val;
|
||||||
|
u32 write_val1 = 0;
|
||||||
|
u32 write_val2 = 0;
|
||||||
|
u32 mask = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* waiting for ACK of pma_xcvr_pllclk_en_ln_*, only for the
|
||||||
|
* master lane
|
||||||
|
*/
|
||||||
|
ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_PLLCLK_EN_ACK,
|
||||||
|
read_val, read_val & 1, 0, POLL_TIMEOUT_US);
|
||||||
|
if (ret == -ETIMEDOUT)
|
||||||
|
dev_err(cdns_phy->dev,
|
||||||
|
"timeout waiting for link PLL clock enable ack\n");
|
||||||
|
|
||||||
|
ndelay(100);
|
||||||
|
|
||||||
|
switch (cdns_phy->num_lanes) {
|
||||||
|
|
||||||
|
case 1: /* lane 0 */
|
||||||
|
write_val1 = 0x00000004;
|
||||||
|
write_val2 = 0x00000001;
|
||||||
|
mask = 0x0000003f;
|
||||||
|
break;
|
||||||
|
case 2: /* lane 0-1 */
|
||||||
|
write_val1 = 0x00000404;
|
||||||
|
write_val2 = 0x00000101;
|
||||||
|
mask = 0x00003f3f;
|
||||||
|
break;
|
||||||
|
case 4: /* lane 0-3 */
|
||||||
|
write_val1 = 0x04040404;
|
||||||
|
write_val2 = 0x01010101;
|
||||||
|
mask = 0x3f3f3f3f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
writel(write_val1, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ);
|
||||||
|
|
||||||
|
ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_ACK,
|
||||||
|
read_val, (read_val & mask) == write_val1, 0,
|
||||||
|
POLL_TIMEOUT_US);
|
||||||
|
if (ret == -ETIMEDOUT)
|
||||||
|
dev_err(cdns_phy->dev,
|
||||||
|
"timeout waiting for link power state ack\n");
|
||||||
|
|
||||||
|
writel(0, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ);
|
||||||
|
ndelay(100);
|
||||||
|
|
||||||
|
writel(write_val2, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ);
|
||||||
|
|
||||||
|
ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_ACK,
|
||||||
|
read_val, (read_val & mask) == write_val2, 0,
|
||||||
|
POLL_TIMEOUT_US);
|
||||||
|
if (ret == -ETIMEDOUT)
|
||||||
|
dev_err(cdns_phy->dev,
|
||||||
|
"timeout waiting for link power state ack\n");
|
||||||
|
|
||||||
|
writel(0, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ);
|
||||||
|
ndelay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cdns_dp_phy_write_field(struct cdns_dp_phy *cdns_phy,
|
||||||
|
unsigned int offset,
|
||||||
|
unsigned char start_bit,
|
||||||
|
unsigned char num_bits,
|
||||||
|
unsigned int val)
|
||||||
|
{
|
||||||
|
unsigned int read_val;
|
||||||
|
|
||||||
|
read_val = readl(cdns_phy->base + offset);
|
||||||
|
writel(((val << start_bit) | (read_val & ~(((1 << num_bits) - 1) <<
|
||||||
|
start_bit))), cdns_phy->base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cdns_dp_phy_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct resource *regs;
|
||||||
|
struct cdns_dp_phy *cdns_phy;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct phy_provider *phy_provider;
|
||||||
|
struct phy *phy;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
cdns_phy = devm_kzalloc(dev, sizeof(*cdns_phy), GFP_KERNEL);
|
||||||
|
if (!cdns_phy)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cdns_phy->dev = &pdev->dev;
|
||||||
|
|
||||||
|
phy = devm_phy_create(dev, NULL, &cdns_dp_phy_ops);
|
||||||
|
if (IS_ERR(phy)) {
|
||||||
|
dev_err(dev, "failed to create DisplayPort PHY\n");
|
||||||
|
return PTR_ERR(phy);
|
||||||
|
}
|
||||||
|
|
||||||
|
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
cdns_phy->base = devm_ioremap_resource(&pdev->dev, regs);
|
||||||
|
if (IS_ERR(cdns_phy->base))
|
||||||
|
return PTR_ERR(cdns_phy->base);
|
||||||
|
|
||||||
|
regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||||
|
cdns_phy->sd_base = devm_ioremap_resource(&pdev->dev, regs);
|
||||||
|
if (IS_ERR(cdns_phy->sd_base))
|
||||||
|
return PTR_ERR(cdns_phy->sd_base);
|
||||||
|
|
||||||
|
err = device_property_read_u32(dev, "num_lanes",
|
||||||
|
&(cdns_phy->num_lanes));
|
||||||
|
if (err)
|
||||||
|
cdns_phy->num_lanes = DEFAULT_NUM_LANES;
|
||||||
|
|
||||||
|
switch (cdns_phy->num_lanes) {
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
/* valid number of lanes */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(dev, "unsupported number of lanes: %d\n",
|
||||||
|
cdns_phy->num_lanes);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = device_property_read_u32(dev, "max_bit_rate",
|
||||||
|
&(cdns_phy->max_bit_rate));
|
||||||
|
if (err)
|
||||||
|
cdns_phy->max_bit_rate = DEFAULT_MAX_BIT_RATE;
|
||||||
|
|
||||||
|
switch (cdns_phy->max_bit_rate) {
|
||||||
|
case 2160:
|
||||||
|
case 2430:
|
||||||
|
case 2700:
|
||||||
|
case 3240:
|
||||||
|
case 4320:
|
||||||
|
case 5400:
|
||||||
|
case 8100:
|
||||||
|
/* valid bit rate */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(dev, "unsupported max bit rate: %dMbps\n",
|
||||||
|
cdns_phy->max_bit_rate);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
phy_set_drvdata(phy, cdns_phy);
|
||||||
|
|
||||||
|
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||||
|
|
||||||
|
dev_info(dev, "%d lanes, max bit rate %d.%03d Gbps\n",
|
||||||
|
cdns_phy->num_lanes,
|
||||||
|
cdns_phy->max_bit_rate / 1000,
|
||||||
|
cdns_phy->max_bit_rate % 1000);
|
||||||
|
|
||||||
|
return PTR_ERR_OR_ZERO(phy_provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id cdns_dp_phy_of_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "cdns,dp-phy"
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, cdns_dp_phy_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver cdns_dp_phy_driver = {
|
||||||
|
.probe = cdns_dp_phy_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "cdns-dp-phy",
|
||||||
|
.of_match_table = cdns_dp_phy_of_match,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
module_platform_driver(cdns_dp_phy_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Cadence Design Systems, Inc.");
|
||||||
|
MODULE_DESCRIPTION("Cadence MHDP PHY driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -156,7 +156,6 @@ static int ltq_rcu_usb2_of_parse(struct ltq_rcu_usb2_priv *priv,
|
||||||
{
|
{
|
||||||
struct device *dev = priv->dev;
|
struct device *dev = priv->dev;
|
||||||
const __be32 *offset;
|
const __be32 *offset;
|
||||||
int ret;
|
|
||||||
|
|
||||||
priv->reg_bits = of_device_get_match_data(dev);
|
priv->reg_bits = of_device_get_match_data(dev);
|
||||||
|
|
||||||
|
@ -196,10 +195,8 @@ static int ltq_rcu_usb2_of_parse(struct ltq_rcu_usb2_priv *priv,
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->phy_reset = devm_reset_control_get_optional(dev, "phy");
|
priv->phy_reset = devm_reset_control_get_optional(dev, "phy");
|
||||||
if (IS_ERR(priv->phy_reset))
|
|
||||||
return PTR_ERR(priv->phy_reset);
|
|
||||||
|
|
||||||
return 0;
|
return PTR_ERR_OR_ZERO(priv->phy_reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ltq_rcu_usb2_phy_probe(struct platform_device *pdev)
|
static int ltq_rcu_usb2_phy_probe(struct platform_device *pdev)
|
||||||
|
|
|
@ -59,3 +59,14 @@ config PHY_PXA_28NM_USB2
|
||||||
The PHY driver will be used by Marvell udc/ehci/otg driver.
|
The PHY driver will be used by Marvell udc/ehci/otg driver.
|
||||||
|
|
||||||
To compile this driver as a module, choose M here.
|
To compile this driver as a module, choose M here.
|
||||||
|
|
||||||
|
config PHY_PXA_USB
|
||||||
|
tristate "Marvell PXA USB PHY Driver"
|
||||||
|
depends on ARCH_PXA || ARCH_MMP
|
||||||
|
select GENERIC_PHY
|
||||||
|
help
|
||||||
|
Enable this to support Marvell PXA USB PHY driver for Marvell
|
||||||
|
SoC. This driver will do the PHY initialization and shutdown.
|
||||||
|
The PHY driver will be used by Marvell udc/ehci/otg driver.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here.
|
||||||
|
|
|
@ -6,3 +6,4 @@ obj-$(CONFIG_PHY_MVEBU_CP110_COMPHY) += phy-mvebu-cp110-comphy.o
|
||||||
obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
|
obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
|
||||||
obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o
|
obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o
|
||||||
obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o
|
obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o
|
||||||
|
obj-$(CONFIG_PHY_PXA_USB) += phy-pxa-usb.o
|
||||||
|
|
|
@ -231,14 +231,14 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
|
||||||
struct phy_berlin_desc *phy_desc;
|
struct phy_berlin_desc *phy_desc;
|
||||||
|
|
||||||
if (of_property_read_u32(child, "reg", &phy_id)) {
|
if (of_property_read_u32(child, "reg", &phy_id)) {
|
||||||
dev_err(dev, "missing reg property in node %s\n",
|
dev_err(dev, "missing reg property in node %pOFn\n",
|
||||||
child->name);
|
child);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto put_child;
|
goto put_child;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phy_id >= ARRAY_SIZE(phy_berlin_power_down_bits)) {
|
if (phy_id >= ARRAY_SIZE(phy_berlin_power_down_bits)) {
|
||||||
dev_err(dev, "invalid reg in node %s\n", child->name);
|
dev_err(dev, "invalid reg in node %pOFn\n", child);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto put_child;
|
goto put_child;
|
||||||
}
|
}
|
||||||
|
|
345
drivers/phy/marvell/phy-pxa-usb.c
Normal file
345
drivers/phy/marvell/phy-pxa-usb.c
Normal file
|
@ -0,0 +1,345 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2011 Marvell International Ltd. All rights reserved.
|
||||||
|
* Copyright (C) 2018 Lubomir Rintel <lkundrak@v3.sk>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dt-bindings/phy/phy.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/phy/phy.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
/* phy regs */
|
||||||
|
#define UTMI_REVISION 0x0
|
||||||
|
#define UTMI_CTRL 0x4
|
||||||
|
#define UTMI_PLL 0x8
|
||||||
|
#define UTMI_TX 0xc
|
||||||
|
#define UTMI_RX 0x10
|
||||||
|
#define UTMI_IVREF 0x14
|
||||||
|
#define UTMI_T0 0x18
|
||||||
|
#define UTMI_T1 0x1c
|
||||||
|
#define UTMI_T2 0x20
|
||||||
|
#define UTMI_T3 0x24
|
||||||
|
#define UTMI_T4 0x28
|
||||||
|
#define UTMI_T5 0x2c
|
||||||
|
#define UTMI_RESERVE 0x30
|
||||||
|
#define UTMI_USB_INT 0x34
|
||||||
|
#define UTMI_DBG_CTL 0x38
|
||||||
|
#define UTMI_OTG_ADDON 0x3c
|
||||||
|
|
||||||
|
/* For UTMICTRL Register */
|
||||||
|
#define UTMI_CTRL_USB_CLK_EN (1 << 31)
|
||||||
|
/* pxa168 */
|
||||||
|
#define UTMI_CTRL_SUSPEND_SET1 (1 << 30)
|
||||||
|
#define UTMI_CTRL_SUSPEND_SET2 (1 << 29)
|
||||||
|
#define UTMI_CTRL_RXBUF_PDWN (1 << 24)
|
||||||
|
#define UTMI_CTRL_TXBUF_PDWN (1 << 11)
|
||||||
|
|
||||||
|
#define UTMI_CTRL_INPKT_DELAY_SHIFT 30
|
||||||
|
#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT 28
|
||||||
|
#define UTMI_CTRL_PU_REF_SHIFT 20
|
||||||
|
#define UTMI_CTRL_ARC_PULLDN_SHIFT 12
|
||||||
|
#define UTMI_CTRL_PLL_PWR_UP_SHIFT 1
|
||||||
|
#define UTMI_CTRL_PWR_UP_SHIFT 0
|
||||||
|
|
||||||
|
/* For UTMI_PLL Register */
|
||||||
|
#define UTMI_PLL_PLLCALI12_SHIFT 29
|
||||||
|
#define UTMI_PLL_PLLCALI12_MASK (0x3 << 29)
|
||||||
|
|
||||||
|
#define UTMI_PLL_PLLVDD18_SHIFT 27
|
||||||
|
#define UTMI_PLL_PLLVDD18_MASK (0x3 << 27)
|
||||||
|
|
||||||
|
#define UTMI_PLL_PLLVDD12_SHIFT 25
|
||||||
|
#define UTMI_PLL_PLLVDD12_MASK (0x3 << 25)
|
||||||
|
|
||||||
|
#define UTMI_PLL_CLK_BLK_EN_SHIFT 24
|
||||||
|
#define CLK_BLK_EN (0x1 << 24)
|
||||||
|
#define PLL_READY (0x1 << 23)
|
||||||
|
#define KVCO_EXT (0x1 << 22)
|
||||||
|
#define VCOCAL_START (0x1 << 21)
|
||||||
|
|
||||||
|
#define UTMI_PLL_KVCO_SHIFT 15
|
||||||
|
#define UTMI_PLL_KVCO_MASK (0x7 << 15)
|
||||||
|
|
||||||
|
#define UTMI_PLL_ICP_SHIFT 12
|
||||||
|
#define UTMI_PLL_ICP_MASK (0x7 << 12)
|
||||||
|
|
||||||
|
#define UTMI_PLL_FBDIV_SHIFT 4
|
||||||
|
#define UTMI_PLL_FBDIV_MASK (0xFF << 4)
|
||||||
|
|
||||||
|
#define UTMI_PLL_REFDIV_SHIFT 0
|
||||||
|
#define UTMI_PLL_REFDIV_MASK (0xF << 0)
|
||||||
|
|
||||||
|
/* For UTMI_TX Register */
|
||||||
|
#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT 27
|
||||||
|
#define UTMI_TX_REG_EXT_FS_RCAL_MASK (0xf << 27)
|
||||||
|
|
||||||
|
#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT 26
|
||||||
|
#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK (0x1 << 26)
|
||||||
|
|
||||||
|
#define UTMI_TX_TXVDD12_SHIFT 22
|
||||||
|
#define UTMI_TX_TXVDD12_MASK (0x3 << 22)
|
||||||
|
|
||||||
|
#define UTMI_TX_CK60_PHSEL_SHIFT 17
|
||||||
|
#define UTMI_TX_CK60_PHSEL_MASK (0xf << 17)
|
||||||
|
|
||||||
|
#define UTMI_TX_IMPCAL_VTH_SHIFT 14
|
||||||
|
#define UTMI_TX_IMPCAL_VTH_MASK (0x7 << 14)
|
||||||
|
|
||||||
|
#define REG_RCAL_START (0x1 << 12)
|
||||||
|
|
||||||
|
#define UTMI_TX_LOW_VDD_EN_SHIFT 11
|
||||||
|
|
||||||
|
#define UTMI_TX_AMP_SHIFT 0
|
||||||
|
#define UTMI_TX_AMP_MASK (0x7 << 0)
|
||||||
|
|
||||||
|
/* For UTMI_RX Register */
|
||||||
|
#define UTMI_REG_SQ_LENGTH_SHIFT 15
|
||||||
|
#define UTMI_REG_SQ_LENGTH_MASK (0x3 << 15)
|
||||||
|
|
||||||
|
#define UTMI_RX_SQ_THRESH_SHIFT 4
|
||||||
|
#define UTMI_RX_SQ_THRESH_MASK (0xf << 4)
|
||||||
|
|
||||||
|
#define UTMI_OTG_ADDON_OTG_ON (1 << 0)
|
||||||
|
|
||||||
|
enum pxa_usb_phy_version {
|
||||||
|
PXA_USB_PHY_MMP2,
|
||||||
|
PXA_USB_PHY_PXA910,
|
||||||
|
PXA_USB_PHY_PXA168,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pxa_usb_phy {
|
||||||
|
struct phy *phy;
|
||||||
|
void __iomem *base;
|
||||||
|
enum pxa_usb_phy_version version;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* The registers read/write routines
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
static unsigned int u2o_get(void __iomem *base, unsigned int offset)
|
||||||
|
{
|
||||||
|
return readl_relaxed(base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void u2o_set(void __iomem *base, unsigned int offset,
|
||||||
|
unsigned int value)
|
||||||
|
{
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
|
reg = readl_relaxed(base + offset);
|
||||||
|
reg |= value;
|
||||||
|
writel_relaxed(reg, base + offset);
|
||||||
|
readl_relaxed(base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void u2o_clear(void __iomem *base, unsigned int offset,
|
||||||
|
unsigned int value)
|
||||||
|
{
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
|
reg = readl_relaxed(base + offset);
|
||||||
|
reg &= ~value;
|
||||||
|
writel_relaxed(reg, base + offset);
|
||||||
|
readl_relaxed(base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void u2o_write(void __iomem *base, unsigned int offset,
|
||||||
|
unsigned int value)
|
||||||
|
{
|
||||||
|
writel_relaxed(value, base + offset);
|
||||||
|
readl_relaxed(base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pxa_usb_phy_init(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct pxa_usb_phy *pxa_usb_phy = phy_get_drvdata(phy);
|
||||||
|
void __iomem *base = pxa_usb_phy->base;
|
||||||
|
int loops;
|
||||||
|
|
||||||
|
dev_info(&phy->dev, "initializing Marvell PXA USB PHY");
|
||||||
|
|
||||||
|
/* Initialize the USB PHY power */
|
||||||
|
if (pxa_usb_phy->version == PXA_USB_PHY_PXA910) {
|
||||||
|
u2o_set(base, UTMI_CTRL, (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
|
||||||
|
| (1<<UTMI_CTRL_PU_REF_SHIFT));
|
||||||
|
}
|
||||||
|
|
||||||
|
u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
|
||||||
|
u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
|
||||||
|
|
||||||
|
/* UTMI_PLL settings */
|
||||||
|
u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
|
||||||
|
| UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
|
||||||
|
| UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
|
||||||
|
| UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
|
||||||
|
|
||||||
|
u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT
|
||||||
|
| 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT
|
||||||
|
| 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT
|
||||||
|
| 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT);
|
||||||
|
|
||||||
|
/* UTMI_TX */
|
||||||
|
u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
|
||||||
|
| UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
|
||||||
|
| UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK
|
||||||
|
| UTMI_TX_AMP_MASK);
|
||||||
|
u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT
|
||||||
|
| 4<<UTMI_TX_CK60_PHSEL_SHIFT | 4<<UTMI_TX_IMPCAL_VTH_SHIFT
|
||||||
|
| 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT | 3<<UTMI_TX_AMP_SHIFT);
|
||||||
|
|
||||||
|
/* UTMI_RX */
|
||||||
|
u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
|
||||||
|
| UTMI_REG_SQ_LENGTH_MASK);
|
||||||
|
u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT
|
||||||
|
| 2<<UTMI_REG_SQ_LENGTH_SHIFT);
|
||||||
|
|
||||||
|
/* UTMI_IVREF */
|
||||||
|
if (pxa_usb_phy->version == PXA_USB_PHY_PXA168) {
|
||||||
|
/*
|
||||||
|
* fixing Microsoft Altair board interface with NEC hub issue -
|
||||||
|
* Set UTMI_IVREF from 0x4a3 to 0x4bf
|
||||||
|
*/
|
||||||
|
u2o_write(base, UTMI_IVREF, 0x4bf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* toggle VCOCAL_START bit of UTMI_PLL */
|
||||||
|
udelay(200);
|
||||||
|
u2o_set(base, UTMI_PLL, VCOCAL_START);
|
||||||
|
udelay(40);
|
||||||
|
u2o_clear(base, UTMI_PLL, VCOCAL_START);
|
||||||
|
|
||||||
|
/* toggle REG_RCAL_START bit of UTMI_TX */
|
||||||
|
udelay(400);
|
||||||
|
u2o_set(base, UTMI_TX, REG_RCAL_START);
|
||||||
|
udelay(40);
|
||||||
|
u2o_clear(base, UTMI_TX, REG_RCAL_START);
|
||||||
|
udelay(400);
|
||||||
|
|
||||||
|
/* Make sure PHY PLL is ready */
|
||||||
|
loops = 0;
|
||||||
|
while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) {
|
||||||
|
mdelay(1);
|
||||||
|
loops++;
|
||||||
|
if (loops > 100) {
|
||||||
|
dev_warn(&phy->dev, "calibrate timeout, UTMI_PLL %x\n",
|
||||||
|
u2o_get(base, UTMI_PLL));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pxa_usb_phy->version == PXA_USB_PHY_PXA168) {
|
||||||
|
u2o_set(base, UTMI_RESERVE, 1 << 5);
|
||||||
|
/* Turn on UTMI PHY OTG extension */
|
||||||
|
u2o_write(base, UTMI_OTG_ADDON, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pxa_usb_phy_exit(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct pxa_usb_phy *pxa_usb_phy = phy_get_drvdata(phy);
|
||||||
|
void __iomem *base = pxa_usb_phy->base;
|
||||||
|
|
||||||
|
dev_info(&phy->dev, "deinitializing Marvell PXA USB PHY");
|
||||||
|
|
||||||
|
if (pxa_usb_phy->version == PXA_USB_PHY_PXA168)
|
||||||
|
u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON);
|
||||||
|
|
||||||
|
u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN);
|
||||||
|
u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN);
|
||||||
|
u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN);
|
||||||
|
u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
|
||||||
|
u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct phy_ops pxa_usb_phy_ops = {
|
||||||
|
.init = pxa_usb_phy_init,
|
||||||
|
.exit = pxa_usb_phy_exit,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id pxa_usb_phy_of_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "marvell,mmp2-usb-phy",
|
||||||
|
.data = (void *)PXA_USB_PHY_MMP2,
|
||||||
|
}, {
|
||||||
|
.compatible = "marvell,pxa910-usb-phy",
|
||||||
|
.data = (void *)PXA_USB_PHY_PXA910,
|
||||||
|
}, {
|
||||||
|
.compatible = "marvell,pxa168-usb-phy",
|
||||||
|
.data = (void *)PXA_USB_PHY_PXA168,
|
||||||
|
},
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, pxa_usb_phy_of_match);
|
||||||
|
|
||||||
|
static int pxa_usb_phy_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct resource *resource;
|
||||||
|
struct pxa_usb_phy *pxa_usb_phy;
|
||||||
|
struct phy_provider *provider;
|
||||||
|
const struct of_device_id *of_id;
|
||||||
|
|
||||||
|
pxa_usb_phy = devm_kzalloc(dev, sizeof(struct pxa_usb_phy), GFP_KERNEL);
|
||||||
|
if (!pxa_usb_phy)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
of_id = of_match_node(pxa_usb_phy_of_match, dev->of_node);
|
||||||
|
if (of_id)
|
||||||
|
pxa_usb_phy->version = (enum pxa_usb_phy_version)of_id->data;
|
||||||
|
else
|
||||||
|
pxa_usb_phy->version = PXA_USB_PHY_MMP2;
|
||||||
|
|
||||||
|
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
pxa_usb_phy->base = devm_ioremap_resource(dev, resource);
|
||||||
|
if (IS_ERR(pxa_usb_phy->base)) {
|
||||||
|
dev_err(dev, "failed to remap PHY regs\n");
|
||||||
|
return PTR_ERR(pxa_usb_phy->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
pxa_usb_phy->phy = devm_phy_create(dev, NULL, &pxa_usb_phy_ops);
|
||||||
|
if (IS_ERR(pxa_usb_phy->phy)) {
|
||||||
|
dev_err(dev, "failed to create PHY\n");
|
||||||
|
return PTR_ERR(pxa_usb_phy->phy);
|
||||||
|
}
|
||||||
|
|
||||||
|
phy_set_drvdata(pxa_usb_phy->phy, pxa_usb_phy);
|
||||||
|
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||||
|
if (IS_ERR(provider)) {
|
||||||
|
dev_err(dev, "failed to register PHY provider\n");
|
||||||
|
return PTR_ERR(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dev->of_node) {
|
||||||
|
phy_create_lookup(pxa_usb_phy->phy, "usb", "mv-udc");
|
||||||
|
phy_create_lookup(pxa_usb_phy->phy, "usb", "pxa-u2oehci");
|
||||||
|
phy_create_lookup(pxa_usb_phy->phy, "usb", "mv-otg");
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info(dev, "Marvell PXA USB PHY");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver pxa_usb_phy_driver = {
|
||||||
|
.probe = pxa_usb_phy_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "pxa-usb-phy",
|
||||||
|
.of_match_table = pxa_usb_phy_of_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(pxa_usb_phy_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
|
||||||
|
MODULE_DESCRIPTION("Marvell PXA USB PHY Driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -50,6 +50,23 @@ config PHY_QCOM_UFS
|
||||||
help
|
help
|
||||||
Support for UFS PHY on QCOM chipsets.
|
Support for UFS PHY on QCOM chipsets.
|
||||||
|
|
||||||
|
if PHY_QCOM_UFS
|
||||||
|
|
||||||
|
config PHY_QCOM_UFS_14NM
|
||||||
|
tristate
|
||||||
|
default PHY_QCOM_UFS
|
||||||
|
help
|
||||||
|
Support for 14nm UFS QMP phy present on QCOM chipsets.
|
||||||
|
|
||||||
|
config PHY_QCOM_UFS_20NM
|
||||||
|
tristate
|
||||||
|
default PHY_QCOM_UFS
|
||||||
|
depends on BROKEN
|
||||||
|
help
|
||||||
|
Support for 20nm UFS QMP phy present on QCOM chipsets.
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
config PHY_QCOM_USB_HS
|
config PHY_QCOM_USB_HS
|
||||||
tristate "Qualcomm USB HS PHY module"
|
tristate "Qualcomm USB HS PHY module"
|
||||||
depends on USB_ULPI_BUS
|
depends on USB_ULPI_BUS
|
||||||
|
|
|
@ -5,7 +5,7 @@ obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
|
||||||
obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o
|
obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o
|
||||||
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
|
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
|
||||||
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
|
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
|
||||||
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
|
obj-$(CONFIG_PHY_QCOM_UFS_14NM) += phy-qcom-ufs-qmp-14nm.o
|
||||||
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
|
obj-$(CONFIG_PHY_QCOM_UFS_20NM) += phy-qcom-ufs-qmp-20nm.o
|
||||||
obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o
|
obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o
|
||||||
obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o
|
obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o
|
||||||
|
|
|
@ -156,6 +156,11 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[] = {
|
||||||
[QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170,
|
[QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const unsigned int sdm845_ufsphy_regs_layout[] = {
|
||||||
|
[QPHY_START_CTRL] = 0x00,
|
||||||
|
[QPHY_PCS_READY_STATUS] = 0x160,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = {
|
static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = {
|
||||||
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1c),
|
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1c),
|
||||||
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10),
|
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10),
|
||||||
|
@ -601,6 +606,83 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_pcs_tbl[] = {
|
||||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60),
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl sdm845_ufsphy_serdes_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0xd5),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL, 0x20),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_CTRL, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x05),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_INITVAL1, 0xff),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_INITVAL2, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xda),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0xff),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x0c),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE1, 0x98),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE1, 0x06),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE1, 0x16),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE1, 0x36),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE1, 0x3f),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE1, 0xc1),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE1, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE1, 0x32),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE1, 0x0f),
|
||||||
|
|
||||||
|
/* Rate B */
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x44),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl sdm845_ufsphy_tx_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x06),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x07),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl sdm845_ufsphy_rx_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_LVL, 0x24),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x0f),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1e),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_TERM_BW, 0x5b),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x06),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1b),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x81),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x80),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x59),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl sdm845_ufsphy_pcs_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_CTRL2, 0x6e),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_LARGE_AMP_DRV_LVL, 0x0a),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_SMALL_AMP_DRV_LVL, 0x02),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SYM_RESYNC_CTRL, 0x03),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_MID_TERM_CTRL1, 0x43),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_CTRL1, 0x0f),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_MIN_HIBERN8_TIME, 0x9a),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_MULTI_LANE_CTRL1, 0x02),
|
||||||
|
};
|
||||||
|
|
||||||
/* struct qmp_phy_cfg - per-PHY initialization config */
|
/* struct qmp_phy_cfg - per-PHY initialization config */
|
||||||
struct qmp_phy_cfg {
|
struct qmp_phy_cfg {
|
||||||
|
@ -649,9 +731,14 @@ struct qmp_phy_cfg {
|
||||||
|
|
||||||
/* true, if PHY has a separate DP_COM control block */
|
/* true, if PHY has a separate DP_COM control block */
|
||||||
bool has_phy_dp_com_ctrl;
|
bool has_phy_dp_com_ctrl;
|
||||||
|
/* true, if PHY has secondary tx/rx lanes to be configured */
|
||||||
|
bool is_dual_lane_phy;
|
||||||
/* Register offset of secondary tx/rx lanes for USB DP combo PHY */
|
/* Register offset of secondary tx/rx lanes for USB DP combo PHY */
|
||||||
unsigned int tx_b_lane_offset;
|
unsigned int tx_b_lane_offset;
|
||||||
unsigned int rx_b_lane_offset;
|
unsigned int rx_b_lane_offset;
|
||||||
|
|
||||||
|
/* true, if PCS block has no separate SW_RESET register */
|
||||||
|
bool no_pcs_sw_reset;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -748,6 +835,10 @@ static const char * const qmp_v3_phy_clk_l[] = {
|
||||||
"aux", "cfg_ahb", "ref", "com_aux",
|
"aux", "cfg_ahb", "ref", "com_aux",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char * const sdm845_ufs_phy_clk_l[] = {
|
||||||
|
"ref", "ref_aux",
|
||||||
|
};
|
||||||
|
|
||||||
/* list of resets */
|
/* list of resets */
|
||||||
static const char * const msm8996_pciephy_reset_l[] = {
|
static const char * const msm8996_pciephy_reset_l[] = {
|
||||||
"phy", "common", "cfg",
|
"phy", "common", "cfg",
|
||||||
|
@ -758,7 +849,7 @@ static const char * const msm8996_usb3phy_reset_l[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* list of regulators */
|
/* list of regulators */
|
||||||
static const char * const msm8996_phy_vreg_l[] = {
|
static const char * const qmp_phy_vreg_l[] = {
|
||||||
"vdda-phy", "vdda-pll",
|
"vdda-phy", "vdda-pll",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -778,8 +869,8 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = {
|
||||||
.num_clks = ARRAY_SIZE(msm8996_phy_clk_l),
|
.num_clks = ARRAY_SIZE(msm8996_phy_clk_l),
|
||||||
.reset_list = msm8996_pciephy_reset_l,
|
.reset_list = msm8996_pciephy_reset_l,
|
||||||
.num_resets = ARRAY_SIZE(msm8996_pciephy_reset_l),
|
.num_resets = ARRAY_SIZE(msm8996_pciephy_reset_l),
|
||||||
.vreg_list = msm8996_phy_vreg_l,
|
.vreg_list = qmp_phy_vreg_l,
|
||||||
.num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l),
|
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||||
.regs = pciephy_regs_layout,
|
.regs = pciephy_regs_layout,
|
||||||
|
|
||||||
.start_ctrl = PCS_START | PLL_READY_GATE_EN,
|
.start_ctrl = PCS_START | PLL_READY_GATE_EN,
|
||||||
|
@ -809,8 +900,8 @@ static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
|
||||||
.num_clks = ARRAY_SIZE(msm8996_phy_clk_l),
|
.num_clks = ARRAY_SIZE(msm8996_phy_clk_l),
|
||||||
.reset_list = msm8996_usb3phy_reset_l,
|
.reset_list = msm8996_usb3phy_reset_l,
|
||||||
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
|
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
|
||||||
.vreg_list = msm8996_phy_vreg_l,
|
.vreg_list = qmp_phy_vreg_l,
|
||||||
.num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l),
|
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||||
.regs = usb3phy_regs_layout,
|
.regs = usb3phy_regs_layout,
|
||||||
|
|
||||||
.start_ctrl = SERDES_START | PCS_START,
|
.start_ctrl = SERDES_START | PCS_START,
|
||||||
|
@ -870,8 +961,8 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
|
||||||
.num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l),
|
.num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l),
|
||||||
.reset_list = msm8996_usb3phy_reset_l,
|
.reset_list = msm8996_usb3phy_reset_l,
|
||||||
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
|
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
|
||||||
.vreg_list = msm8996_phy_vreg_l,
|
.vreg_list = qmp_phy_vreg_l,
|
||||||
.num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l),
|
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||||
.regs = qmp_v3_usb3phy_regs_layout,
|
.regs = qmp_v3_usb3phy_regs_layout,
|
||||||
|
|
||||||
.start_ctrl = SERDES_START | PCS_START,
|
.start_ctrl = SERDES_START | PCS_START,
|
||||||
|
@ -883,6 +974,7 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
|
||||||
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
|
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
|
||||||
|
|
||||||
.has_phy_dp_com_ctrl = true,
|
.has_phy_dp_com_ctrl = true,
|
||||||
|
.is_dual_lane_phy = true,
|
||||||
.tx_b_lane_offset = 0x400,
|
.tx_b_lane_offset = 0x400,
|
||||||
.rx_b_lane_offset = 0x400,
|
.rx_b_lane_offset = 0x400,
|
||||||
};
|
};
|
||||||
|
@ -903,8 +995,8 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = {
|
||||||
.num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l),
|
.num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l),
|
||||||
.reset_list = msm8996_usb3phy_reset_l,
|
.reset_list = msm8996_usb3phy_reset_l,
|
||||||
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
|
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
|
||||||
.vreg_list = msm8996_phy_vreg_l,
|
.vreg_list = qmp_phy_vreg_l,
|
||||||
.num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l),
|
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||||
.regs = qmp_v3_usb3phy_regs_layout,
|
.regs = qmp_v3_usb3phy_regs_layout,
|
||||||
|
|
||||||
.start_ctrl = SERDES_START | PCS_START,
|
.start_ctrl = SERDES_START | PCS_START,
|
||||||
|
@ -916,6 +1008,35 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = {
|
||||||
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
|
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
|
||||||
|
.type = PHY_TYPE_UFS,
|
||||||
|
.nlanes = 2,
|
||||||
|
|
||||||
|
.serdes_tbl = sdm845_ufsphy_serdes_tbl,
|
||||||
|
.serdes_tbl_num = ARRAY_SIZE(sdm845_ufsphy_serdes_tbl),
|
||||||
|
.tx_tbl = sdm845_ufsphy_tx_tbl,
|
||||||
|
.tx_tbl_num = ARRAY_SIZE(sdm845_ufsphy_tx_tbl),
|
||||||
|
.rx_tbl = sdm845_ufsphy_rx_tbl,
|
||||||
|
.rx_tbl_num = ARRAY_SIZE(sdm845_ufsphy_rx_tbl),
|
||||||
|
.pcs_tbl = sdm845_ufsphy_pcs_tbl,
|
||||||
|
.pcs_tbl_num = ARRAY_SIZE(sdm845_ufsphy_pcs_tbl),
|
||||||
|
.clk_list = sdm845_ufs_phy_clk_l,
|
||||||
|
.num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
|
||||||
|
.vreg_list = qmp_phy_vreg_l,
|
||||||
|
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||||
|
.regs = sdm845_ufsphy_regs_layout,
|
||||||
|
|
||||||
|
.start_ctrl = SERDES_START,
|
||||||
|
.pwrdn_ctrl = SW_PWRDN,
|
||||||
|
.mask_pcs_ready = PCS_READY,
|
||||||
|
|
||||||
|
.is_dual_lane_phy = true,
|
||||||
|
.tx_b_lane_offset = 0x400,
|
||||||
|
.rx_b_lane_offset = 0x400,
|
||||||
|
|
||||||
|
.no_pcs_sw_reset = true,
|
||||||
|
};
|
||||||
|
|
||||||
static void qcom_qmp_phy_configure(void __iomem *base,
|
static void qcom_qmp_phy_configure(void __iomem *base,
|
||||||
const unsigned int *regs,
|
const unsigned int *regs,
|
||||||
const struct qmp_phy_init_tbl tbl[],
|
const struct qmp_phy_init_tbl tbl[],
|
||||||
|
@ -935,10 +1056,12 @@ static void qcom_qmp_phy_configure(void __iomem *base,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
|
static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
|
||||||
{
|
{
|
||||||
|
struct qcom_qmp *qmp = qphy->qmp;
|
||||||
const struct qmp_phy_cfg *cfg = qmp->cfg;
|
const struct qmp_phy_cfg *cfg = qmp->cfg;
|
||||||
void __iomem *serdes = qmp->serdes;
|
void __iomem *serdes = qmp->serdes;
|
||||||
|
void __iomem *pcs = qphy->pcs;
|
||||||
void __iomem *dp_com = qmp->dp_com;
|
void __iomem *dp_com = qmp->dp_com;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
|
@ -979,10 +1102,6 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
|
||||||
goto err_rst;
|
goto err_rst;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfg->has_phy_com_ctrl)
|
|
||||||
qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL],
|
|
||||||
SW_PWRDN);
|
|
||||||
|
|
||||||
if (cfg->has_phy_dp_com_ctrl) {
|
if (cfg->has_phy_dp_com_ctrl) {
|
||||||
qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL,
|
qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL,
|
||||||
SW_PWRDN);
|
SW_PWRDN);
|
||||||
|
@ -1000,6 +1119,12 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
|
||||||
SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
|
SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cfg->has_phy_com_ctrl)
|
||||||
|
qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL],
|
||||||
|
SW_PWRDN);
|
||||||
|
else
|
||||||
|
qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
|
||||||
|
|
||||||
/* Serdes configuration */
|
/* Serdes configuration */
|
||||||
qcom_qmp_phy_configure(serdes, cfg->regs, cfg->serdes_tbl,
|
qcom_qmp_phy_configure(serdes, cfg->regs, cfg->serdes_tbl,
|
||||||
cfg->serdes_tbl_num);
|
cfg->serdes_tbl_num);
|
||||||
|
@ -1090,7 +1215,7 @@ static int qcom_qmp_phy_init(struct phy *phy)
|
||||||
|
|
||||||
dev_vdbg(qmp->dev, "Initializing QMP phy\n");
|
dev_vdbg(qmp->dev, "Initializing QMP phy\n");
|
||||||
|
|
||||||
ret = qcom_qmp_phy_com_init(qmp);
|
ret = qcom_qmp_phy_com_init(qphy);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -1112,21 +1237,30 @@ static int qcom_qmp_phy_init(struct phy *phy)
|
||||||
/* Tx, Rx, and PCS configurations */
|
/* Tx, Rx, and PCS configurations */
|
||||||
qcom_qmp_phy_configure(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num);
|
qcom_qmp_phy_configure(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num);
|
||||||
/* Configuration for other LANE for USB-DP combo PHY */
|
/* Configuration for other LANE for USB-DP combo PHY */
|
||||||
if (cfg->has_phy_dp_com_ctrl)
|
if (cfg->is_dual_lane_phy)
|
||||||
qcom_qmp_phy_configure(tx + cfg->tx_b_lane_offset, cfg->regs,
|
qcom_qmp_phy_configure(tx + cfg->tx_b_lane_offset, cfg->regs,
|
||||||
cfg->tx_tbl, cfg->tx_tbl_num);
|
cfg->tx_tbl, cfg->tx_tbl_num);
|
||||||
|
|
||||||
qcom_qmp_phy_configure(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num);
|
qcom_qmp_phy_configure(rx, cfg->regs, cfg->rx_tbl, cfg->rx_tbl_num);
|
||||||
if (cfg->has_phy_dp_com_ctrl)
|
if (cfg->is_dual_lane_phy)
|
||||||
qcom_qmp_phy_configure(rx + cfg->rx_b_lane_offset, cfg->regs,
|
qcom_qmp_phy_configure(rx + cfg->rx_b_lane_offset, cfg->regs,
|
||||||
cfg->rx_tbl, cfg->rx_tbl_num);
|
cfg->rx_tbl, cfg->rx_tbl_num);
|
||||||
|
|
||||||
qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num);
|
qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UFS PHY requires the deassert of software reset before serdes start.
|
||||||
|
* For UFS PHYs that do not have software reset control bits, defer
|
||||||
|
* starting serdes until the power on callback.
|
||||||
|
*/
|
||||||
|
if ((cfg->type == PHY_TYPE_UFS) && cfg->no_pcs_sw_reset)
|
||||||
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pull out PHY from POWER DOWN state.
|
* Pull out PHY from POWER DOWN state.
|
||||||
* This is active low enable signal to power-down PHY.
|
* This is active low enable signal to power-down PHY.
|
||||||
*/
|
*/
|
||||||
|
if(cfg->type == PHY_TYPE_PCIE)
|
||||||
qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
|
qphy_setbits(pcs, QPHY_POWER_DOWN_CONTROL, cfg->pwrdn_ctrl);
|
||||||
|
|
||||||
if (cfg->has_pwrdn_delay)
|
if (cfg->has_pwrdn_delay)
|
||||||
|
@ -1151,6 +1285,7 @@ static int qcom_qmp_phy_init(struct phy *phy)
|
||||||
}
|
}
|
||||||
qmp->phy_initialized = true;
|
qmp->phy_initialized = true;
|
||||||
|
|
||||||
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
err_pcs_ready:
|
err_pcs_ready:
|
||||||
|
@ -1173,6 +1308,7 @@ static int qcom_qmp_phy_exit(struct phy *phy)
|
||||||
clk_disable_unprepare(qphy->pipe_clk);
|
clk_disable_unprepare(qphy->pipe_clk);
|
||||||
|
|
||||||
/* PHY reset */
|
/* PHY reset */
|
||||||
|
if (!cfg->no_pcs_sw_reset)
|
||||||
qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
|
qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
|
||||||
|
|
||||||
/* stop SerDes and Phy-Coding-Sublayer */
|
/* stop SerDes and Phy-Coding-Sublayer */
|
||||||
|
@ -1191,6 +1327,44 @@ static int qcom_qmp_phy_exit(struct phy *phy)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qcom_qmp_phy_poweron(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct qmp_phy *qphy = phy_get_drvdata(phy);
|
||||||
|
struct qcom_qmp *qmp = qphy->qmp;
|
||||||
|
const struct qmp_phy_cfg *cfg = qmp->cfg;
|
||||||
|
void __iomem *pcs = qphy->pcs;
|
||||||
|
void __iomem *status;
|
||||||
|
unsigned int mask, val;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (cfg->type != PHY_TYPE_UFS)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For UFS PHY that has not software reset control, serdes start
|
||||||
|
* should only happen when UFS driver explicitly calls phy_power_on
|
||||||
|
* after it deasserts software reset.
|
||||||
|
*/
|
||||||
|
if (cfg->no_pcs_sw_reset && !qmp->phy_initialized &&
|
||||||
|
(qmp->init_count != 0)) {
|
||||||
|
/* start SerDes and Phy-Coding-Sublayer */
|
||||||
|
qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
|
||||||
|
|
||||||
|
status = pcs + cfg->regs[QPHY_PCS_READY_STATUS];
|
||||||
|
mask = cfg->mask_pcs_ready;
|
||||||
|
|
||||||
|
ret = readl_poll_timeout(status, val, !(val & mask), 1,
|
||||||
|
PHY_INIT_COMPLETE_TIMEOUT);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(qmp->dev, "phy initialization timed-out\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
qmp->phy_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int qcom_qmp_phy_set_mode(struct phy *phy, enum phy_mode mode)
|
static int qcom_qmp_phy_set_mode(struct phy *phy, enum phy_mode mode)
|
||||||
{
|
{
|
||||||
struct qmp_phy *qphy = phy_get_drvdata(phy);
|
struct qmp_phy *qphy = phy_get_drvdata(phy);
|
||||||
|
@ -1400,7 +1574,7 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np)
|
||||||
|
|
||||||
ret = of_property_read_string(np, "clock-output-names", &init.name);
|
ret = of_property_read_string(np, "clock-output-names", &init.name);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(qmp->dev, "%s: No clock-output-names\n", np->name);
|
dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1420,6 +1594,7 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np)
|
||||||
static const struct phy_ops qcom_qmp_phy_gen_ops = {
|
static const struct phy_ops qcom_qmp_phy_gen_ops = {
|
||||||
.init = qcom_qmp_phy_init,
|
.init = qcom_qmp_phy_init,
|
||||||
.exit = qcom_qmp_phy_exit,
|
.exit = qcom_qmp_phy_exit,
|
||||||
|
.power_on = qcom_qmp_phy_poweron,
|
||||||
.set_mode = qcom_qmp_phy_set_mode,
|
.set_mode = qcom_qmp_phy_set_mode,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
@ -1522,6 +1697,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
|
||||||
}, {
|
}, {
|
||||||
.compatible = "qcom,sdm845-qmp-usb3-uni-phy",
|
.compatible = "qcom,sdm845-qmp-usb3-uni-phy",
|
||||||
.data = &qmp_v3_usb3_uniphy_cfg,
|
.data = &qmp_v3_usb3_uniphy_cfg,
|
||||||
|
}, {
|
||||||
|
.compatible = "qcom,sdm845-qmp-ufs-phy",
|
||||||
|
.data = &sdm845_ufsphy_cfg,
|
||||||
},
|
},
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
@ -1586,7 +1764,9 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
ret = qcom_qmp_phy_vreg_init(dev);
|
ret = qcom_qmp_phy_vreg_init(dev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to get regulator supplies\n");
|
if (ret != -EPROBE_DEFER)
|
||||||
|
dev_err(dev, "failed to get regulator supplies: %d\n",
|
||||||
|
ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -184,6 +184,8 @@
|
||||||
#define QSERDES_V3_COM_VCO_TUNE2_MODE0 0x0f8
|
#define QSERDES_V3_COM_VCO_TUNE2_MODE0 0x0f8
|
||||||
#define QSERDES_V3_COM_VCO_TUNE1_MODE1 0x0fc
|
#define QSERDES_V3_COM_VCO_TUNE1_MODE1 0x0fc
|
||||||
#define QSERDES_V3_COM_VCO_TUNE2_MODE1 0x100
|
#define QSERDES_V3_COM_VCO_TUNE2_MODE1 0x100
|
||||||
|
#define QSERDES_V3_COM_VCO_TUNE_INITVAL1 0x104
|
||||||
|
#define QSERDES_V3_COM_VCO_TUNE_INITVAL2 0x108
|
||||||
#define QSERDES_V3_COM_VCO_TUNE_TIMER1 0x11c
|
#define QSERDES_V3_COM_VCO_TUNE_TIMER1 0x11c
|
||||||
#define QSERDES_V3_COM_VCO_TUNE_TIMER2 0x120
|
#define QSERDES_V3_COM_VCO_TUNE_TIMER2 0x120
|
||||||
#define QSERDES_V3_COM_CLK_SELECT 0x138
|
#define QSERDES_V3_COM_CLK_SELECT 0x138
|
||||||
|
@ -211,8 +213,13 @@
|
||||||
/* Only for QMP V3 PHY - RX registers */
|
/* Only for QMP V3 PHY - RX registers */
|
||||||
#define QSERDES_V3_RX_UCDR_SO_GAIN_HALF 0x00c
|
#define QSERDES_V3_RX_UCDR_SO_GAIN_HALF 0x00c
|
||||||
#define QSERDES_V3_RX_UCDR_SO_GAIN 0x014
|
#define QSERDES_V3_RX_UCDR_SO_GAIN 0x014
|
||||||
|
#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF 0x024
|
||||||
|
#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER 0x028
|
||||||
|
#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN 0x02c
|
||||||
#define QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN 0x030
|
#define QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN 0x030
|
||||||
#define QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034
|
#define QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034
|
||||||
|
#define QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c
|
||||||
|
#define QSERDES_V3_RX_UCDR_PI_CONTROLS 0x044
|
||||||
#define QSERDES_V3_RX_RX_TERM_BW 0x07c
|
#define QSERDES_V3_RX_RX_TERM_BW 0x07c
|
||||||
#define QSERDES_V3_RX_VGA_CAL_CNTRL1 0x0bc
|
#define QSERDES_V3_RX_VGA_CAL_CNTRL1 0x0bc
|
||||||
#define QSERDES_V3_RX_VGA_CAL_CNTRL2 0x0c0
|
#define QSERDES_V3_RX_VGA_CAL_CNTRL2 0x0c0
|
||||||
|
@ -239,6 +246,8 @@
|
||||||
#define QPHY_V3_PCS_TXMGN_V3 0x018
|
#define QPHY_V3_PCS_TXMGN_V3 0x018
|
||||||
#define QPHY_V3_PCS_TXMGN_V4 0x01c
|
#define QPHY_V3_PCS_TXMGN_V4 0x01c
|
||||||
#define QPHY_V3_PCS_TXMGN_LS 0x020
|
#define QPHY_V3_PCS_TXMGN_LS 0x020
|
||||||
|
#define QPHY_V3_PCS_TX_LARGE_AMP_DRV_LVL 0x02c
|
||||||
|
#define QPHY_V3_PCS_TX_SMALL_AMP_DRV_LVL 0x034
|
||||||
#define QPHY_V3_PCS_TXDEEMPH_M6DB_V0 0x024
|
#define QPHY_V3_PCS_TXDEEMPH_M6DB_V0 0x024
|
||||||
#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0 0x028
|
#define QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0 0x028
|
||||||
#define QPHY_V3_PCS_TXDEEMPH_M6DB_V1 0x02c
|
#define QPHY_V3_PCS_TXDEEMPH_M6DB_V1 0x02c
|
||||||
|
@ -275,6 +284,12 @@
|
||||||
#define QPHY_V3_PCS_FLL_CNT_VAL_L 0x0cc
|
#define QPHY_V3_PCS_FLL_CNT_VAL_L 0x0cc
|
||||||
#define QPHY_V3_PCS_FLL_CNT_VAL_H_TOL 0x0d0
|
#define QPHY_V3_PCS_FLL_CNT_VAL_H_TOL 0x0d0
|
||||||
#define QPHY_V3_PCS_FLL_MAN_CODE 0x0d4
|
#define QPHY_V3_PCS_FLL_MAN_CODE 0x0d4
|
||||||
|
#define QPHY_V3_PCS_RX_SYM_RESYNC_CTRL 0x134
|
||||||
|
#define QPHY_V3_PCS_RX_MIN_HIBERN8_TIME 0x138
|
||||||
|
#define QPHY_V3_PCS_RX_SIGDET_CTRL1 0x13c
|
||||||
|
#define QPHY_V3_PCS_RX_SIGDET_CTRL2 0x140
|
||||||
|
#define QPHY_V3_PCS_TX_MID_TERM_CTRL1 0x1bc
|
||||||
|
#define QPHY_V3_PCS_MULTI_LANE_CTRL1 0x1c4
|
||||||
#define QPHY_V3_PCS_RX_SIGDET_LVL 0x1d8
|
#define QPHY_V3_PCS_RX_SIGDET_LVL 0x1d8
|
||||||
#define QPHY_V3_PCS_REFGEN_REQ_CONFIG1 0x20c
|
#define QPHY_V3_PCS_REFGEN_REQ_CONFIG1 0x20c
|
||||||
#define QPHY_V3_PCS_REFGEN_REQ_CONFIG2 0x210
|
#define QPHY_V3_PCS_REFGEN_REQ_CONFIG2 0x210
|
||||||
|
|
|
@ -800,7 +800,9 @@ static int qusb2_phy_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
ret = devm_regulator_bulk_get(dev, num, qphy->vregs);
|
ret = devm_regulator_bulk_get(dev, num, qphy->vregs);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to get regulator supplies\n");
|
if (ret != -EPROBE_DEFER)
|
||||||
|
dev_err(dev, "failed to get regulator supplies: %d\n",
|
||||||
|
ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/phy/phy.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/phy/phy-qcom-ufs.h>
|
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
|
@ -431,56 +431,6 @@ static void ufs_qcom_phy_disable_ref_clk(struct ufs_qcom_phy *phy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define UFS_REF_CLK_EN (1 << 5)
|
|
||||||
|
|
||||||
static void ufs_qcom_phy_dev_ref_clk_ctrl(struct phy *generic_phy, bool enable)
|
|
||||||
{
|
|
||||||
struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
|
|
||||||
|
|
||||||
if (phy->dev_ref_clk_ctrl_mmio &&
|
|
||||||
(enable ^ phy->is_dev_ref_clk_enabled)) {
|
|
||||||
u32 temp = readl_relaxed(phy->dev_ref_clk_ctrl_mmio);
|
|
||||||
|
|
||||||
if (enable)
|
|
||||||
temp |= UFS_REF_CLK_EN;
|
|
||||||
else
|
|
||||||
temp &= ~UFS_REF_CLK_EN;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we are here to disable this clock immediately after
|
|
||||||
* entering into hibern8, we need to make sure that device
|
|
||||||
* ref_clk is active atleast 1us after the hibern8 enter.
|
|
||||||
*/
|
|
||||||
if (!enable)
|
|
||||||
udelay(1);
|
|
||||||
|
|
||||||
writel_relaxed(temp, phy->dev_ref_clk_ctrl_mmio);
|
|
||||||
/* ensure that ref_clk is enabled/disabled before we return */
|
|
||||||
wmb();
|
|
||||||
/*
|
|
||||||
* If we call hibern8 exit after this, we need to make sure that
|
|
||||||
* device ref_clk is stable for atleast 1us before the hibern8
|
|
||||||
* exit command.
|
|
||||||
*/
|
|
||||||
if (enable)
|
|
||||||
udelay(1);
|
|
||||||
|
|
||||||
phy->is_dev_ref_clk_enabled = enable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ufs_qcom_phy_enable_dev_ref_clk(struct phy *generic_phy)
|
|
||||||
{
|
|
||||||
ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, true);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(ufs_qcom_phy_enable_dev_ref_clk);
|
|
||||||
|
|
||||||
void ufs_qcom_phy_disable_dev_ref_clk(struct phy *generic_phy)
|
|
||||||
{
|
|
||||||
ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, false);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(ufs_qcom_phy_disable_dev_ref_clk);
|
|
||||||
|
|
||||||
/* Turn ON M-PHY RMMI interface clocks */
|
/* Turn ON M-PHY RMMI interface clocks */
|
||||||
static int ufs_qcom_phy_enable_iface_clk(struct ufs_qcom_phy *phy)
|
static int ufs_qcom_phy_enable_iface_clk(struct ufs_qcom_phy *phy)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
#
|
#
|
||||||
# Phy drivers for Renesas platforms
|
# Phy drivers for Renesas platforms
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
|
obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
|
||||||
obj-$(CONFIG_PHY_RCAR_GEN3_PCIE) += phy-rcar-gen3-pcie.o
|
obj-$(CONFIG_PHY_RCAR_GEN3_PCIE) += phy-rcar-gen3-pcie.o
|
||||||
obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o
|
obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* Renesas R-Car Gen2 PHY driver
|
* Renesas R-Car Gen2 PHY driver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Renesas Solutions Corp.
|
* Copyright (C) 2014 Renesas Solutions Corp.
|
||||||
* Copyright (C) 2014 Cogent Embedded, Inc.
|
* Copyright (C) 2014 Cogent Embedded, Inc.
|
||||||
*
|
|
||||||
* 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/clk.h>
|
#include <linux/clk.h>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* Renesas R-Car Gen3 for USB2.0 PHY driver
|
* Renesas R-Car Gen3 for USB2.0 PHY driver
|
||||||
*
|
*
|
||||||
|
@ -6,10 +7,6 @@
|
||||||
* This is based on the phy-rcar-gen2 driver:
|
* This is based on the phy-rcar-gen2 driver:
|
||||||
* Copyright (C) 2014 Renesas Solutions Corp.
|
* Copyright (C) 2014 Renesas Solutions Corp.
|
||||||
* Copyright (C) 2014 Cogent Embedded, Inc.
|
* Copyright (C) 2014 Cogent Embedded, Inc.
|
||||||
*
|
|
||||||
* 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/extcon-provider.h>
|
#include <linux/extcon-provider.h>
|
||||||
|
@ -81,18 +78,29 @@
|
||||||
#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)
|
||||||
|
|
||||||
#define RCAR_GEN3_PHY_HAS_DEDICATED_PINS 1
|
|
||||||
|
|
||||||
struct rcar_gen3_chan {
|
struct rcar_gen3_chan {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct extcon_dev *extcon;
|
struct extcon_dev *extcon;
|
||||||
struct phy *phy;
|
struct phy *phy;
|
||||||
struct regulator *vbus;
|
struct regulator *vbus;
|
||||||
struct work_struct work;
|
struct work_struct work;
|
||||||
|
enum usb_dr_mode dr_mode;
|
||||||
bool extcon_host;
|
bool extcon_host;
|
||||||
bool has_otg_pins;
|
bool is_otg_channel;
|
||||||
|
bool uses_otg_pins;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Combination about is_otg_channel and uses_otg_pins:
|
||||||
|
*
|
||||||
|
* Parameters || Behaviors
|
||||||
|
* is_otg_channel | uses_otg_pins || irqs | role sysfs
|
||||||
|
* ---------------------+---------------++--------------+------------
|
||||||
|
* true | true || enabled | enabled
|
||||||
|
* true | false || disabled | enabled
|
||||||
|
* false | any || disabled | disabled
|
||||||
|
*/
|
||||||
|
|
||||||
static void rcar_gen3_phy_usb2_work(struct work_struct *work)
|
static void rcar_gen3_phy_usb2_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan,
|
struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan,
|
||||||
|
@ -147,6 +155,18 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus)
|
||||||
writel(val, usb2_base + USB2_ADPCTRL);
|
writel(val, usb2_base + USB2_ADPCTRL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rcar_gen3_control_otg_irq(struct rcar_gen3_chan *ch, int enable)
|
||||||
|
{
|
||||||
|
void __iomem *usb2_base = ch->base;
|
||||||
|
u32 val = readl(usb2_base + USB2_OBINTEN);
|
||||||
|
|
||||||
|
if (ch->uses_otg_pins && enable)
|
||||||
|
val |= USB2_OBINT_BITS;
|
||||||
|
else
|
||||||
|
val &= ~USB2_OBINT_BITS;
|
||||||
|
writel(val, usb2_base + USB2_OBINTEN);
|
||||||
|
}
|
||||||
|
|
||||||
static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch)
|
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);
|
||||||
|
@ -192,20 +212,19 @@ static void rcar_gen3_init_for_a_peri(struct rcar_gen3_chan *ch)
|
||||||
|
|
||||||
static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch)
|
static void rcar_gen3_init_from_a_peri_to_a_host(struct rcar_gen3_chan *ch)
|
||||||
{
|
{
|
||||||
void __iomem *usb2_base = ch->base;
|
rcar_gen3_control_otg_irq(ch, 0);
|
||||||
u32 val;
|
|
||||||
|
|
||||||
val = readl(usb2_base + USB2_OBINTEN);
|
rcar_gen3_enable_vbus_ctrl(ch, 1);
|
||||||
writel(val & ~USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
|
|
||||||
|
|
||||||
rcar_gen3_enable_vbus_ctrl(ch, 0);
|
|
||||||
rcar_gen3_init_for_host(ch);
|
rcar_gen3_init_for_host(ch);
|
||||||
|
|
||||||
writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
|
rcar_gen3_control_otg_irq(ch, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
|
static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
|
||||||
{
|
{
|
||||||
|
if (!ch->uses_otg_pins)
|
||||||
|
return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true;
|
||||||
|
|
||||||
return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG);
|
return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +256,7 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr,
|
||||||
bool is_b_device;
|
bool is_b_device;
|
||||||
enum phy_mode cur_mode, new_mode;
|
enum phy_mode cur_mode, new_mode;
|
||||||
|
|
||||||
if (!ch->has_otg_pins || !ch->phy->init_count)
|
if (!ch->is_otg_channel || !ch->phy->init_count)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (!strncmp(buf, "host", strlen("host")))
|
if (!strncmp(buf, "host", strlen("host")))
|
||||||
|
@ -275,7 +294,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr,
|
||||||
{
|
{
|
||||||
struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
|
struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
|
||||||
|
|
||||||
if (!ch->has_otg_pins || !ch->phy->init_count)
|
if (!ch->is_otg_channel || !ch->phy->init_count)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" :
|
return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" :
|
||||||
|
@ -291,8 +310,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
|
||||||
val = readl(usb2_base + USB2_VBCTRL);
|
val = readl(usb2_base + USB2_VBCTRL);
|
||||||
writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL);
|
writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL);
|
||||||
writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA);
|
writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA);
|
||||||
val = readl(usb2_base + USB2_OBINTEN);
|
rcar_gen3_control_otg_irq(ch, 1);
|
||||||
writel(val | USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
|
|
||||||
val = readl(usb2_base + USB2_ADPCTRL);
|
val = readl(usb2_base + USB2_ADPCTRL);
|
||||||
writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL);
|
writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL);
|
||||||
val = readl(usb2_base + USB2_LINECTRL1);
|
val = readl(usb2_base + USB2_LINECTRL1);
|
||||||
|
@ -314,7 +332,7 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
|
||||||
writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
|
writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
|
||||||
|
|
||||||
/* Initialize otg part */
|
/* Initialize otg part */
|
||||||
if (channel->has_otg_pins)
|
if (channel->is_otg_channel)
|
||||||
rcar_gen3_init_otg(channel);
|
rcar_gen3_init_otg(channel);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -388,21 +406,10 @@ 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,usb2-phy-r8a7796" },
|
||||||
.data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS,
|
{ .compatible = "renesas,usb2-phy-r8a77965" },
|
||||||
},
|
{ .compatible = "renesas,rcar-gen3-usb2-phy" },
|
||||||
{
|
|
||||||
.compatible = "renesas,usb2-phy-r8a7796",
|
|
||||||
.data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.compatible = "renesas,usb2-phy-r8a77965",
|
|
||||||
.data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.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);
|
||||||
|
@ -445,10 +452,13 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
||||||
dev_err(dev, "No irq handler (%d)\n", irq);
|
dev_err(dev, "No irq handler (%d)\n", irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (of_usb_get_dr_mode_by_phy(dev->of_node, 0) == USB_DR_MODE_OTG) {
|
channel->dr_mode = of_usb_get_dr_mode_by_phy(dev->of_node, 0);
|
||||||
|
if (channel->dr_mode != USB_DR_MODE_UNKNOWN) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
channel->has_otg_pins = (uintptr_t)of_device_get_match_data(dev);
|
channel->is_otg_channel = true;
|
||||||
|
channel->uses_otg_pins = !of_property_read_bool(dev->of_node,
|
||||||
|
"renesas,no-otg-pins");
|
||||||
channel->extcon = devm_extcon_dev_allocate(dev,
|
channel->extcon = devm_extcon_dev_allocate(dev,
|
||||||
rcar_gen3_phy_cable);
|
rcar_gen3_phy_cable);
|
||||||
if (IS_ERR(channel->extcon))
|
if (IS_ERR(channel->extcon))
|
||||||
|
@ -490,7 +500,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
||||||
dev_err(dev, "Failed to register PHY provider\n");
|
dev_err(dev, "Failed to register PHY provider\n");
|
||||||
ret = PTR_ERR(provider);
|
ret = PTR_ERR(provider);
|
||||||
goto error;
|
goto error;
|
||||||
} else if (channel->has_otg_pins) {
|
} else if (channel->is_otg_channel) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = device_create_file(dev, &dev_attr_role);
|
ret = device_create_file(dev, &dev_attr_role);
|
||||||
|
@ -510,7 +520,7 @@ static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct rcar_gen3_chan *channel = platform_get_drvdata(pdev);
|
struct rcar_gen3_chan *channel = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
if (channel->has_otg_pins)
|
if (channel->is_otg_channel)
|
||||||
device_remove_file(&pdev->dev, &dev_attr_role);
|
device_remove_file(&pdev->dev, &dev_attr_role);
|
||||||
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* Renesas R-Car Gen3 for USB3.0 PHY driver
|
* Renesas R-Car Gen3 for USB3.0 PHY driver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2017 Renesas Electronics Corporation
|
* Copyright (C) 2017 Renesas Electronics Corporation
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
|
|
@ -15,6 +15,14 @@ config PHY_ROCKCHIP_EMMC
|
||||||
help
|
help
|
||||||
Enable this to support the Rockchip EMMC PHY.
|
Enable this to support the Rockchip EMMC PHY.
|
||||||
|
|
||||||
|
config PHY_ROCKCHIP_INNO_HDMI
|
||||||
|
tristate "Rockchip INNO HDMI PHY Driver"
|
||||||
|
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
|
||||||
|
depends on COMMON_CLK
|
||||||
|
select GENERIC_PHY
|
||||||
|
help
|
||||||
|
Enable this to support the Rockchip Innosilicon HDMI PHY.
|
||||||
|
|
||||||
config PHY_ROCKCHIP_INNO_USB2
|
config PHY_ROCKCHIP_INNO_USB2
|
||||||
tristate "Rockchip INNO USB2PHY Driver"
|
tristate "Rockchip INNO USB2PHY Driver"
|
||||||
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
|
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o
|
obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o
|
||||||
obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
|
obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
|
||||||
|
obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI) += phy-rockchip-inno-hdmi.o
|
||||||
obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o
|
obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o
|
||||||
obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o
|
obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o
|
||||||
obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
|
obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
|
||||||
|
|
|
@ -337,8 +337,8 @@ static int rockchip_emmc_phy_probe(struct platform_device *pdev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (of_property_read_u32(dev->of_node, "reg", ®_offset)) {
|
if (of_property_read_u32(dev->of_node, "reg", ®_offset)) {
|
||||||
dev_err(dev, "missing reg property in node %s\n",
|
dev_err(dev, "missing reg property in node %pOFn\n",
|
||||||
dev->of_node->name);
|
dev->of_node);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1277
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
Normal file
1277
drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1116,8 +1116,8 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (of_property_read_u32(np, "reg", ®)) {
|
if (of_property_read_u32(np, "reg", ®)) {
|
||||||
dev_err(dev, "the reg property is not assigned in %s node\n",
|
dev_err(dev, "the reg property is not assigned in %pOFn node\n",
|
||||||
np->name);
|
np);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1143,8 +1143,8 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rphy->phy_cfg) {
|
if (!rphy->phy_cfg) {
|
||||||
dev_err(dev, "no phy-config can be matched with %s node\n",
|
dev_err(dev, "no phy-config can be matched with %pOFn node\n",
|
||||||
np->name);
|
np);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1145,8 +1145,8 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tcphy->port_cfgs) {
|
if (!tcphy->port_cfgs) {
|
||||||
dev_err(dev, "no phy-config can be matched with %s node\n",
|
dev_err(dev, "no phy-config can be matched with %pOFn node\n",
|
||||||
np->name);
|
np);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1186,8 +1186,8 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (IS_ERR(phy)) {
|
if (IS_ERR(phy)) {
|
||||||
dev_err(dev, "failed to create phy: %s\n",
|
dev_err(dev, "failed to create phy: %pOFn\n",
|
||||||
child_np->name);
|
child_np);
|
||||||
pm_runtime_disable(dev);
|
pm_runtime_disable(dev);
|
||||||
return PTR_ERR(phy);
|
return PTR_ERR(phy);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,22 @@ static int enable_usb_uart;
|
||||||
#define HIWORD_UPDATE(val, mask) \
|
#define HIWORD_UPDATE(val, mask) \
|
||||||
((val) | (mask) << 16)
|
((val) | (mask) << 16)
|
||||||
|
|
||||||
|
#define UOC_CON0 0x00
|
||||||
#define UOC_CON0_SIDDQ BIT(13)
|
#define UOC_CON0_SIDDQ BIT(13)
|
||||||
|
#define UOC_CON0_DISABLE BIT(4)
|
||||||
|
#define UOC_CON0_COMMON_ON_N BIT(0)
|
||||||
|
|
||||||
|
#define UOC_CON2 0x08
|
||||||
|
#define UOC_CON2_SOFT_CON_SEL BIT(2)
|
||||||
|
|
||||||
|
#define UOC_CON3 0x0c
|
||||||
|
/* bits present on rk3188 and rk3288 phys */
|
||||||
|
#define UOC_CON3_UTMI_TERMSEL_FULLSPEED BIT(5)
|
||||||
|
#define UOC_CON3_UTMI_XCVRSEELCT_FSTRANSC (1 << 3)
|
||||||
|
#define UOC_CON3_UTMI_XCVRSEELCT_MASK (3 << 3)
|
||||||
|
#define UOC_CON3_UTMI_OPMODE_NODRIVING (1 << 1)
|
||||||
|
#define UOC_CON3_UTMI_OPMODE_MASK (3 << 1)
|
||||||
|
#define UOC_CON3_UTMI_SUSPENDN BIT(0)
|
||||||
|
|
||||||
struct rockchip_usb_phys {
|
struct rockchip_usb_phys {
|
||||||
int reg;
|
int reg;
|
||||||
|
@ -46,7 +61,8 @@ struct rockchip_usb_phys {
|
||||||
struct rockchip_usb_phy_base;
|
struct rockchip_usb_phy_base;
|
||||||
struct rockchip_usb_phy_pdata {
|
struct rockchip_usb_phy_pdata {
|
||||||
struct rockchip_usb_phys *phys;
|
struct rockchip_usb_phys *phys;
|
||||||
int (*init_usb_uart)(struct regmap *grf);
|
int (*init_usb_uart)(struct regmap *grf,
|
||||||
|
const struct rockchip_usb_phy_pdata *pdata);
|
||||||
int usb_uart_phy;
|
int usb_uart_phy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -208,8 +224,8 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
|
||||||
rk_phy->np = child;
|
rk_phy->np = child;
|
||||||
|
|
||||||
if (of_property_read_u32(child, "reg", ®_offset)) {
|
if (of_property_read_u32(child, "reg", ®_offset)) {
|
||||||
dev_err(base->dev, "missing reg property in node %s\n",
|
dev_err(base->dev, "missing reg property in node %pOFn\n",
|
||||||
child->name);
|
child);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,28 +329,88 @@ static const struct rockchip_usb_phy_pdata rk3066a_pdata = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int __init rockchip_init_usb_uart_common(struct regmap *grf,
|
||||||
|
const struct rockchip_usb_phy_pdata *pdata)
|
||||||
|
{
|
||||||
|
int regoffs = pdata->phys[pdata->usb_uart_phy].reg;
|
||||||
|
int ret;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* COMMON_ON and DISABLE settings are described in the TRM,
|
||||||
|
* but were not present in the original code.
|
||||||
|
* Also disable the analog phy components to save power.
|
||||||
|
*/
|
||||||
|
val = HIWORD_UPDATE(UOC_CON0_COMMON_ON_N
|
||||||
|
| UOC_CON0_DISABLE
|
||||||
|
| UOC_CON0_SIDDQ,
|
||||||
|
UOC_CON0_COMMON_ON_N
|
||||||
|
| UOC_CON0_DISABLE
|
||||||
|
| UOC_CON0_SIDDQ);
|
||||||
|
ret = regmap_write(grf, regoffs + UOC_CON0, val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
val = HIWORD_UPDATE(UOC_CON2_SOFT_CON_SEL,
|
||||||
|
UOC_CON2_SOFT_CON_SEL);
|
||||||
|
ret = regmap_write(grf, regoffs + UOC_CON2, val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
val = HIWORD_UPDATE(UOC_CON3_UTMI_OPMODE_NODRIVING
|
||||||
|
| UOC_CON3_UTMI_XCVRSEELCT_FSTRANSC
|
||||||
|
| UOC_CON3_UTMI_TERMSEL_FULLSPEED,
|
||||||
|
UOC_CON3_UTMI_SUSPENDN
|
||||||
|
| UOC_CON3_UTMI_OPMODE_MASK
|
||||||
|
| UOC_CON3_UTMI_XCVRSEELCT_MASK
|
||||||
|
| UOC_CON3_UTMI_TERMSEL_FULLSPEED);
|
||||||
|
ret = regmap_write(grf, UOC_CON3, val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RK3188_UOC0_CON0 0x10c
|
||||||
|
#define RK3188_UOC0_CON0_BYPASSSEL BIT(9)
|
||||||
|
#define RK3188_UOC0_CON0_BYPASSDMEN BIT(8)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable the bypass of uart2 data through the otg usb phy.
|
||||||
|
* See description of rk3288-variant for details.
|
||||||
|
*/
|
||||||
|
static int __init rk3188_init_usb_uart(struct regmap *grf,
|
||||||
|
const struct rockchip_usb_phy_pdata *pdata)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = rockchip_init_usb_uart_common(grf, pdata);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
val = HIWORD_UPDATE(RK3188_UOC0_CON0_BYPASSSEL
|
||||||
|
| RK3188_UOC0_CON0_BYPASSDMEN,
|
||||||
|
RK3188_UOC0_CON0_BYPASSSEL
|
||||||
|
| RK3188_UOC0_CON0_BYPASSDMEN);
|
||||||
|
ret = regmap_write(grf, RK3188_UOC0_CON0, val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct rockchip_usb_phy_pdata rk3188_pdata = {
|
static const struct rockchip_usb_phy_pdata rk3188_pdata = {
|
||||||
.phys = (struct rockchip_usb_phys[]){
|
.phys = (struct rockchip_usb_phys[]){
|
||||||
{ .reg = 0x10c, .pll_name = "sclk_otgphy0_480m" },
|
{ .reg = 0x10c, .pll_name = "sclk_otgphy0_480m" },
|
||||||
{ .reg = 0x11c, .pll_name = "sclk_otgphy1_480m" },
|
{ .reg = 0x11c, .pll_name = "sclk_otgphy1_480m" },
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
},
|
},
|
||||||
|
.init_usb_uart = rk3188_init_usb_uart,
|
||||||
|
.usb_uart_phy = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RK3288_UOC0_CON0 0x320
|
|
||||||
#define RK3288_UOC0_CON0_COMMON_ON_N BIT(0)
|
|
||||||
#define RK3288_UOC0_CON0_DISABLE BIT(4)
|
|
||||||
|
|
||||||
#define RK3288_UOC0_CON2 0x328
|
|
||||||
#define RK3288_UOC0_CON2_SOFT_CON_SEL BIT(2)
|
|
||||||
|
|
||||||
#define RK3288_UOC0_CON3 0x32c
|
#define RK3288_UOC0_CON3 0x32c
|
||||||
#define RK3288_UOC0_CON3_UTMI_SUSPENDN BIT(0)
|
|
||||||
#define RK3288_UOC0_CON3_UTMI_OPMODE_NODRIVING (1 << 1)
|
|
||||||
#define RK3288_UOC0_CON3_UTMI_OPMODE_MASK (3 << 1)
|
|
||||||
#define RK3288_UOC0_CON3_UTMI_XCVRSEELCT_FSTRANSC (1 << 3)
|
|
||||||
#define RK3288_UOC0_CON3_UTMI_XCVRSEELCT_MASK (3 << 3)
|
|
||||||
#define RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED BIT(5)
|
|
||||||
#define RK3288_UOC0_CON3_BYPASSDMEN BIT(6)
|
#define RK3288_UOC0_CON3_BYPASSDMEN BIT(6)
|
||||||
#define RK3288_UOC0_CON3_BYPASSSEL BIT(7)
|
#define RK3288_UOC0_CON3_BYPASSSEL BIT(7)
|
||||||
|
|
||||||
|
@ -353,40 +429,13 @@ static const struct rockchip_usb_phy_pdata rk3188_pdata = {
|
||||||
*
|
*
|
||||||
* The actual code in the vendor kernel does some things differently.
|
* The actual code in the vendor kernel does some things differently.
|
||||||
*/
|
*/
|
||||||
static int __init rk3288_init_usb_uart(struct regmap *grf)
|
static int __init rk3288_init_usb_uart(struct regmap *grf,
|
||||||
|
const struct rockchip_usb_phy_pdata *pdata)
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
ret = rockchip_init_usb_uart_common(grf, pdata);
|
||||||
* COMMON_ON and DISABLE settings are described in the TRM,
|
|
||||||
* but were not present in the original code.
|
|
||||||
* Also disable the analog phy components to save power.
|
|
||||||
*/
|
|
||||||
val = HIWORD_UPDATE(RK3288_UOC0_CON0_COMMON_ON_N
|
|
||||||
| RK3288_UOC0_CON0_DISABLE
|
|
||||||
| UOC_CON0_SIDDQ,
|
|
||||||
RK3288_UOC0_CON0_COMMON_ON_N
|
|
||||||
| RK3288_UOC0_CON0_DISABLE
|
|
||||||
| UOC_CON0_SIDDQ);
|
|
||||||
ret = regmap_write(grf, RK3288_UOC0_CON0, val);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
val = HIWORD_UPDATE(RK3288_UOC0_CON2_SOFT_CON_SEL,
|
|
||||||
RK3288_UOC0_CON2_SOFT_CON_SEL);
|
|
||||||
ret = regmap_write(grf, RK3288_UOC0_CON2, val);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
val = HIWORD_UPDATE(RK3288_UOC0_CON3_UTMI_OPMODE_NODRIVING
|
|
||||||
| RK3288_UOC0_CON3_UTMI_XCVRSEELCT_FSTRANSC
|
|
||||||
| RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED,
|
|
||||||
RK3288_UOC0_CON3_UTMI_SUSPENDN
|
|
||||||
| RK3288_UOC0_CON3_UTMI_OPMODE_MASK
|
|
||||||
| RK3288_UOC0_CON3_UTMI_XCVRSEELCT_MASK
|
|
||||||
| RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED);
|
|
||||||
ret = regmap_write(grf, RK3288_UOC0_CON3, val);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -516,7 +565,7 @@ static int __init rockchip_init_usb_uart(void)
|
||||||
return PTR_ERR(grf);
|
return PTR_ERR(grf);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = data->init_usb_uart(grf);
|
ret = data->init_usb_uart(grf, data);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("%s: could not init usb_uart, %d\n", __func__, ret);
|
pr_err("%s: could not init usb_uart, %d\n", __func__, ret);
|
||||||
enable_usb_uart = 0;
|
enable_usb_uart = 0;
|
||||||
|
|
34
drivers/phy/socionext/Kconfig
Normal file
34
drivers/phy/socionext/Kconfig
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#
|
||||||
|
# PHY drivers for Socionext platforms.
|
||||||
|
#
|
||||||
|
|
||||||
|
config PHY_UNIPHIER_USB2
|
||||||
|
tristate "UniPhier USB2 PHY driver"
|
||||||
|
depends on ARCH_UNIPHIER || COMPILE_TEST
|
||||||
|
depends on OF && HAS_IOMEM
|
||||||
|
select GENERIC_PHY
|
||||||
|
select MFD_SYSCON
|
||||||
|
help
|
||||||
|
Enable this to support USB PHY implemented on USB2 controller
|
||||||
|
on UniPhier SoCs. This driver provides interface to interact
|
||||||
|
with USB 2.0 PHY that is part of the UniPhier SoC.
|
||||||
|
In case of Pro4, it is necessary to specify this USB2 PHY instead
|
||||||
|
of USB3 HS-PHY.
|
||||||
|
|
||||||
|
config PHY_UNIPHIER_USB3
|
||||||
|
tristate "UniPhier USB3 PHY driver"
|
||||||
|
depends on ARCH_UNIPHIER || COMPILE_TEST
|
||||||
|
depends on OF && HAS_IOMEM
|
||||||
|
select GENERIC_PHY
|
||||||
|
help
|
||||||
|
Enable this to support USB PHY implemented in USB3 controller
|
||||||
|
on UniPhier SoCs. This controller supports USB3.0 and lower speed.
|
||||||
|
|
||||||
|
config PHY_UNIPHIER_PCIE
|
||||||
|
tristate "Uniphier PHY driver for PCIe controller"
|
||||||
|
depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF
|
||||||
|
default PCIE_UNIPHIER
|
||||||
|
select GENERIC_PHY
|
||||||
|
help
|
||||||
|
Enable this to support PHY implemented in PCIe controller
|
||||||
|
on UniPhier SoCs. This driver supports LD20 and PXs3 SoCs.
|
8
drivers/phy/socionext/Makefile
Normal file
8
drivers/phy/socionext/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
#
|
||||||
|
# Makefile for the phy drivers.
|
||||||
|
#
|
||||||
|
|
||||||
|
obj-$(CONFIG_PHY_UNIPHIER_USB2) += phy-uniphier-usb2.o
|
||||||
|
obj-$(CONFIG_PHY_UNIPHIER_USB3) += phy-uniphier-usb3hs.o phy-uniphier-usb3ss.o
|
||||||
|
obj-$(CONFIG_PHY_UNIPHIER_PCIE) += phy-uniphier-pcie.o
|
240
drivers/phy/socionext/phy-uniphier-pcie.c
Normal file
240
drivers/phy/socionext/phy-uniphier-pcie.c
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* phy-uniphier-pcie.c - PHY driver for UniPhier PCIe controller
|
||||||
|
* Copyright 2018, Socionext Inc.
|
||||||
|
* Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/bitfield.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/phy/phy.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/reset.h>
|
||||||
|
#include <linux/resource.h>
|
||||||
|
|
||||||
|
/* PHY */
|
||||||
|
#define PCL_PHY_TEST_I 0x2000
|
||||||
|
#define PCL_PHY_TEST_O 0x2004
|
||||||
|
#define TESTI_DAT_MASK GENMASK(13, 6)
|
||||||
|
#define TESTI_ADR_MASK GENMASK(5, 1)
|
||||||
|
#define TESTI_WR_EN BIT(0)
|
||||||
|
|
||||||
|
#define PCL_PHY_RESET 0x200c
|
||||||
|
#define PCL_PHY_RESET_N_MNMODE BIT(8) /* =1:manual */
|
||||||
|
#define PCL_PHY_RESET_N BIT(0) /* =1:deasssert */
|
||||||
|
|
||||||
|
/* SG */
|
||||||
|
#define SG_USBPCIESEL 0x590
|
||||||
|
#define SG_USBPCIESEL_PCIE BIT(0)
|
||||||
|
|
||||||
|
#define PCL_PHY_R00 0
|
||||||
|
#define RX_EQ_ADJ_EN BIT(3) /* enable for EQ adjustment */
|
||||||
|
#define PCL_PHY_R06 6
|
||||||
|
#define RX_EQ_ADJ GENMASK(5, 0) /* EQ adjustment value */
|
||||||
|
#define RX_EQ_ADJ_VAL 0
|
||||||
|
#define PCL_PHY_R26 26
|
||||||
|
#define VCO_CTRL GENMASK(7, 4) /* Tx VCO adjustment value */
|
||||||
|
#define VCO_CTRL_INIT_VAL 5
|
||||||
|
|
||||||
|
struct uniphier_pciephy_priv {
|
||||||
|
void __iomem *base;
|
||||||
|
struct device *dev;
|
||||||
|
struct clk *clk;
|
||||||
|
struct reset_control *rst;
|
||||||
|
const struct uniphier_pciephy_soc_data *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uniphier_pciephy_soc_data {
|
||||||
|
bool has_syscon;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void uniphier_pciephy_testio_write(struct uniphier_pciephy_priv *priv,
|
||||||
|
u32 data)
|
||||||
|
{
|
||||||
|
/* need to read TESTO twice after accessing TESTI */
|
||||||
|
writel(data, priv->base + PCL_PHY_TEST_I);
|
||||||
|
readl(priv->base + PCL_PHY_TEST_O);
|
||||||
|
readl(priv->base + PCL_PHY_TEST_O);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uniphier_pciephy_set_param(struct uniphier_pciephy_priv *priv,
|
||||||
|
u32 reg, u32 mask, u32 param)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
/* read previous data */
|
||||||
|
val = FIELD_PREP(TESTI_DAT_MASK, 1);
|
||||||
|
val |= FIELD_PREP(TESTI_ADR_MASK, reg);
|
||||||
|
uniphier_pciephy_testio_write(priv, val);
|
||||||
|
val = readl(priv->base + PCL_PHY_TEST_O);
|
||||||
|
|
||||||
|
/* update value */
|
||||||
|
val &= ~FIELD_PREP(TESTI_DAT_MASK, mask);
|
||||||
|
val = FIELD_PREP(TESTI_DAT_MASK, mask & param);
|
||||||
|
val |= FIELD_PREP(TESTI_ADR_MASK, reg);
|
||||||
|
uniphier_pciephy_testio_write(priv, val);
|
||||||
|
uniphier_pciephy_testio_write(priv, val | TESTI_WR_EN);
|
||||||
|
uniphier_pciephy_testio_write(priv, val);
|
||||||
|
|
||||||
|
/* read current data as dummy */
|
||||||
|
val = FIELD_PREP(TESTI_DAT_MASK, 1);
|
||||||
|
val |= FIELD_PREP(TESTI_ADR_MASK, reg);
|
||||||
|
uniphier_pciephy_testio_write(priv, val);
|
||||||
|
readl(priv->base + PCL_PHY_TEST_O);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uniphier_pciephy_assert(struct uniphier_pciephy_priv *priv)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = readl(priv->base + PCL_PHY_RESET);
|
||||||
|
val &= ~PCL_PHY_RESET_N;
|
||||||
|
val |= PCL_PHY_RESET_N_MNMODE;
|
||||||
|
writel(val, priv->base + PCL_PHY_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uniphier_pciephy_deassert(struct uniphier_pciephy_priv *priv)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = readl(priv->base + PCL_PHY_RESET);
|
||||||
|
val |= PCL_PHY_RESET_N_MNMODE | PCL_PHY_RESET_N;
|
||||||
|
writel(val, priv->base + PCL_PHY_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_pciephy_init(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(priv->clk);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = reset_control_deassert(priv->rst);
|
||||||
|
if (ret)
|
||||||
|
goto out_clk_disable;
|
||||||
|
|
||||||
|
uniphier_pciephy_set_param(priv, PCL_PHY_R00,
|
||||||
|
RX_EQ_ADJ_EN, RX_EQ_ADJ_EN);
|
||||||
|
uniphier_pciephy_set_param(priv, PCL_PHY_R06, RX_EQ_ADJ,
|
||||||
|
FIELD_PREP(RX_EQ_ADJ, RX_EQ_ADJ_VAL));
|
||||||
|
uniphier_pciephy_set_param(priv, PCL_PHY_R26, VCO_CTRL,
|
||||||
|
FIELD_PREP(VCO_CTRL, VCO_CTRL_INIT_VAL));
|
||||||
|
usleep_range(1, 10);
|
||||||
|
|
||||||
|
uniphier_pciephy_deassert(priv);
|
||||||
|
usleep_range(1, 10);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_clk_disable:
|
||||||
|
clk_disable_unprepare(priv->clk);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_pciephy_exit(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
uniphier_pciephy_assert(priv);
|
||||||
|
reset_control_assert(priv->rst);
|
||||||
|
clk_disable_unprepare(priv->clk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct phy_ops uniphier_pciephy_ops = {
|
||||||
|
.init = uniphier_pciephy_init,
|
||||||
|
.exit = uniphier_pciephy_exit,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int uniphier_pciephy_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct uniphier_pciephy_priv *priv;
|
||||||
|
struct phy_provider *phy_provider;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct regmap *regmap;
|
||||||
|
struct resource *res;
|
||||||
|
struct phy *phy;
|
||||||
|
|
||||||
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->data = of_device_get_match_data(dev);
|
||||||
|
if (WARN_ON(!priv->data))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
priv->dev = dev;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
priv->base = devm_ioremap_resource(dev, res);
|
||||||
|
if (IS_ERR(priv->base))
|
||||||
|
return PTR_ERR(priv->base);
|
||||||
|
|
||||||
|
priv->clk = devm_clk_get(dev, NULL);
|
||||||
|
if (IS_ERR(priv->clk))
|
||||||
|
return PTR_ERR(priv->clk);
|
||||||
|
|
||||||
|
priv->rst = devm_reset_control_get_shared(dev, NULL);
|
||||||
|
if (IS_ERR(priv->rst))
|
||||||
|
return PTR_ERR(priv->rst);
|
||||||
|
|
||||||
|
phy = devm_phy_create(dev, dev->of_node, &uniphier_pciephy_ops);
|
||||||
|
if (IS_ERR(phy))
|
||||||
|
return PTR_ERR(phy);
|
||||||
|
|
||||||
|
regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||||
|
"socionext,syscon");
|
||||||
|
if (!IS_ERR(regmap) && priv->data->has_syscon)
|
||||||
|
regmap_update_bits(regmap, SG_USBPCIESEL,
|
||||||
|
SG_USBPCIESEL_PCIE, SG_USBPCIESEL_PCIE);
|
||||||
|
|
||||||
|
phy_set_drvdata(phy, priv);
|
||||||
|
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||||
|
|
||||||
|
return PTR_ERR_OR_ZERO(phy_provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct uniphier_pciephy_soc_data uniphier_ld20_data = {
|
||||||
|
.has_syscon = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct uniphier_pciephy_soc_data uniphier_pxs3_data = {
|
||||||
|
.has_syscon = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id uniphier_pciephy_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "socionext,uniphier-ld20-pcie-phy",
|
||||||
|
.data = &uniphier_ld20_data,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "socionext,uniphier-pxs3-pcie-phy",
|
||||||
|
.data = &uniphier_pxs3_data,
|
||||||
|
},
|
||||||
|
{ /* sentinel */ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, uniphier_pciephy_match);
|
||||||
|
|
||||||
|
static struct platform_driver uniphier_pciephy_driver = {
|
||||||
|
.probe = uniphier_pciephy_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "uniphier-pcie-phy",
|
||||||
|
.of_match_table = uniphier_pciephy_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(uniphier_pciephy_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
|
||||||
|
MODULE_DESCRIPTION("UniPhier PHY driver for PCIe controller");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
244
drivers/phy/socionext/phy-uniphier-usb2.c
Normal file
244
drivers/phy/socionext/phy-uniphier-usb2.c
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* phy-uniphier-usb2.c - PHY driver for UniPhier USB2 controller
|
||||||
|
* Copyright 2015-2018 Socionext Inc.
|
||||||
|
* Author:
|
||||||
|
* Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/phy/phy.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
|
|
||||||
|
#define SG_USBPHY1CTRL 0x500
|
||||||
|
#define SG_USBPHY1CTRL2 0x504
|
||||||
|
#define SG_USBPHY2CTRL 0x508
|
||||||
|
#define SG_USBPHY2CTRL2 0x50c /* LD11 */
|
||||||
|
#define SG_USBPHY12PLL 0x50c /* Pro4 */
|
||||||
|
#define SG_USBPHY3CTRL 0x510
|
||||||
|
#define SG_USBPHY3CTRL2 0x514
|
||||||
|
#define SG_USBPHY4CTRL 0x518 /* Pro4 */
|
||||||
|
#define SG_USBPHY4CTRL2 0x51c /* Pro4 */
|
||||||
|
#define SG_USBPHY34PLL 0x51c /* Pro4 */
|
||||||
|
|
||||||
|
struct uniphier_u2phy_param {
|
||||||
|
u32 offset;
|
||||||
|
u32 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uniphier_u2phy_soc_data {
|
||||||
|
struct uniphier_u2phy_param config0;
|
||||||
|
struct uniphier_u2phy_param config1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uniphier_u2phy_priv {
|
||||||
|
struct regmap *regmap;
|
||||||
|
struct phy *phy;
|
||||||
|
struct regulator *vbus;
|
||||||
|
const struct uniphier_u2phy_soc_data *data;
|
||||||
|
struct uniphier_u2phy_priv *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int uniphier_u2phy_power_on(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (priv->vbus)
|
||||||
|
ret = regulator_enable(priv->vbus);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_u2phy_power_off(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
if (priv->vbus)
|
||||||
|
regulator_disable(priv->vbus);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_u2phy_init(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct uniphier_u2phy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
if (!priv->data)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
regmap_write(priv->regmap, priv->data->config0.offset,
|
||||||
|
priv->data->config0.value);
|
||||||
|
regmap_write(priv->regmap, priv->data->config1.offset,
|
||||||
|
priv->data->config1.value);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct phy *uniphier_u2phy_xlate(struct device *dev,
|
||||||
|
struct of_phandle_args *args)
|
||||||
|
{
|
||||||
|
struct uniphier_u2phy_priv *priv = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
while (priv && args->np != priv->phy->dev.of_node)
|
||||||
|
priv = priv->next;
|
||||||
|
|
||||||
|
if (!priv) {
|
||||||
|
dev_err(dev, "Failed to find appropriate phy\n");
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return priv->phy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct phy_ops uniphier_u2phy_ops = {
|
||||||
|
.init = uniphier_u2phy_init,
|
||||||
|
.power_on = uniphier_u2phy_power_on,
|
||||||
|
.power_off = uniphier_u2phy_power_off,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int uniphier_u2phy_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct device_node *parent, *child;
|
||||||
|
struct uniphier_u2phy_priv *priv = NULL, *next = NULL;
|
||||||
|
struct phy_provider *phy_provider;
|
||||||
|
struct regmap *regmap;
|
||||||
|
const struct uniphier_u2phy_soc_data *data;
|
||||||
|
int ret, data_idx, ndatas;
|
||||||
|
|
||||||
|
data = of_device_get_match_data(dev);
|
||||||
|
if (WARN_ON(!data))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* get number of data */
|
||||||
|
for (ndatas = 0; data[ndatas].config0.offset; ndatas++)
|
||||||
|
;
|
||||||
|
|
||||||
|
parent = of_get_parent(dev->of_node);
|
||||||
|
regmap = syscon_node_to_regmap(parent);
|
||||||
|
of_node_put(parent);
|
||||||
|
if (IS_ERR(regmap)) {
|
||||||
|
dev_err(dev, "Failed to get regmap\n");
|
||||||
|
return PTR_ERR(regmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child_of_node(dev->of_node, child) {
|
||||||
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_put_child;
|
||||||
|
}
|
||||||
|
priv->regmap = regmap;
|
||||||
|
|
||||||
|
priv->vbus = devm_regulator_get_optional(dev, "vbus");
|
||||||
|
if (IS_ERR(priv->vbus)) {
|
||||||
|
if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) {
|
||||||
|
ret = PTR_ERR(priv->vbus);
|
||||||
|
goto out_put_child;
|
||||||
|
}
|
||||||
|
priv->vbus = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->phy = devm_phy_create(dev, child, &uniphier_u2phy_ops);
|
||||||
|
if (IS_ERR(priv->phy)) {
|
||||||
|
dev_err(dev, "Failed to create phy\n");
|
||||||
|
ret = PTR_ERR(priv->phy);
|
||||||
|
goto out_put_child;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = of_property_read_u32(child, "reg", &data_idx);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to get reg property\n");
|
||||||
|
goto out_put_child;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data_idx < ndatas)
|
||||||
|
priv->data = &data[data_idx];
|
||||||
|
else
|
||||||
|
dev_warn(dev, "No phy configuration: %s\n",
|
||||||
|
child->full_name);
|
||||||
|
|
||||||
|
phy_set_drvdata(priv->phy, priv);
|
||||||
|
priv->next = next;
|
||||||
|
next = priv;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_set_drvdata(dev, priv);
|
||||||
|
phy_provider = devm_of_phy_provider_register(dev,
|
||||||
|
uniphier_u2phy_xlate);
|
||||||
|
return PTR_ERR_OR_ZERO(phy_provider);
|
||||||
|
|
||||||
|
out_put_child:
|
||||||
|
of_node_put(child);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct uniphier_u2phy_soc_data uniphier_pro4_data[] = {
|
||||||
|
{
|
||||||
|
.config0 = { SG_USBPHY1CTRL, 0x05142400 },
|
||||||
|
.config1 = { SG_USBPHY12PLL, 0x00010010 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.config0 = { SG_USBPHY2CTRL, 0x05142400 },
|
||||||
|
.config1 = { SG_USBPHY12PLL, 0x00010010 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.config0 = { SG_USBPHY3CTRL, 0x05142400 },
|
||||||
|
.config1 = { SG_USBPHY34PLL, 0x00010010 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.config0 = { SG_USBPHY4CTRL, 0x05142400 },
|
||||||
|
.config1 = { SG_USBPHY34PLL, 0x00010010 },
|
||||||
|
},
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct uniphier_u2phy_soc_data uniphier_ld11_data[] = {
|
||||||
|
{
|
||||||
|
.config0 = { SG_USBPHY1CTRL, 0x82280000 },
|
||||||
|
.config1 = { SG_USBPHY1CTRL2, 0x00000106 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.config0 = { SG_USBPHY2CTRL, 0x82280000 },
|
||||||
|
.config1 = { SG_USBPHY2CTRL2, 0x00000106 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.config0 = { SG_USBPHY3CTRL, 0x82280000 },
|
||||||
|
.config1 = { SG_USBPHY3CTRL2, 0x00000106 },
|
||||||
|
},
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id uniphier_u2phy_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "socionext,uniphier-pro4-usb2-phy",
|
||||||
|
.data = &uniphier_pro4_data,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "socionext,uniphier-ld11-usb2-phy",
|
||||||
|
.data = &uniphier_ld11_data,
|
||||||
|
},
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, uniphier_u2phy_match);
|
||||||
|
|
||||||
|
static struct platform_driver uniphier_u2phy_driver = {
|
||||||
|
.probe = uniphier_u2phy_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "uniphier-usb2-phy",
|
||||||
|
.of_match_table = uniphier_u2phy_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(uniphier_u2phy_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
|
||||||
|
MODULE_DESCRIPTION("UniPhier PHY driver for USB2 controller");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
422
drivers/phy/socionext/phy-uniphier-usb3hs.c
Normal file
422
drivers/phy/socionext/phy-uniphier-usb3hs.c
Normal file
|
@ -0,0 +1,422 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* phy-uniphier-usb3hs.c - HS-PHY driver for Socionext UniPhier USB3 controller
|
||||||
|
* Copyright 2015-2018 Socionext Inc.
|
||||||
|
* Author:
|
||||||
|
* Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
|
||||||
|
* Contributors:
|
||||||
|
* Motoya Tanigawa <tanigawa.motoya@socionext.com>
|
||||||
|
* Masami Hiramatsu <masami.hiramatsu@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitfield.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/nvmem-consumer.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/phy/phy.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/reset.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#define HSPHY_CFG0 0x0
|
||||||
|
#define HSPHY_CFG0_HS_I_MASK GENMASK(31, 28)
|
||||||
|
#define HSPHY_CFG0_HSDISC_MASK GENMASK(27, 26)
|
||||||
|
#define HSPHY_CFG0_SWING_MASK GENMASK(17, 16)
|
||||||
|
#define HSPHY_CFG0_SEL_T_MASK GENMASK(15, 12)
|
||||||
|
#define HSPHY_CFG0_RTERM_MASK GENMASK(7, 6)
|
||||||
|
#define HSPHY_CFG0_TRIMMASK (HSPHY_CFG0_HS_I_MASK \
|
||||||
|
| HSPHY_CFG0_SEL_T_MASK \
|
||||||
|
| HSPHY_CFG0_RTERM_MASK)
|
||||||
|
|
||||||
|
#define HSPHY_CFG1 0x4
|
||||||
|
#define HSPHY_CFG1_DAT_EN BIT(29)
|
||||||
|
#define HSPHY_CFG1_ADR_EN BIT(28)
|
||||||
|
#define HSPHY_CFG1_ADR_MASK GENMASK(27, 16)
|
||||||
|
#define HSPHY_CFG1_DAT_MASK GENMASK(23, 16)
|
||||||
|
|
||||||
|
#define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
|
||||||
|
|
||||||
|
#define LS_SLEW PHY_F(10, 6, 6) /* LS mode slew rate */
|
||||||
|
#define FS_LS_DRV PHY_F(10, 5, 5) /* FS/LS slew rate */
|
||||||
|
|
||||||
|
#define MAX_PHY_PARAMS 2
|
||||||
|
|
||||||
|
struct uniphier_u3hsphy_param {
|
||||||
|
struct {
|
||||||
|
int reg_no;
|
||||||
|
int msb;
|
||||||
|
int lsb;
|
||||||
|
} field;
|
||||||
|
u8 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uniphier_u3hsphy_trim_param {
|
||||||
|
unsigned int rterm;
|
||||||
|
unsigned int sel_t;
|
||||||
|
unsigned int hs_i;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define trim_param_is_valid(p) ((p)->rterm || (p)->sel_t || (p)->hs_i)
|
||||||
|
|
||||||
|
struct uniphier_u3hsphy_priv {
|
||||||
|
struct device *dev;
|
||||||
|
void __iomem *base;
|
||||||
|
struct clk *clk, *clk_parent, *clk_ext;
|
||||||
|
struct reset_control *rst, *rst_parent;
|
||||||
|
struct regulator *vbus;
|
||||||
|
const struct uniphier_u3hsphy_soc_data *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uniphier_u3hsphy_soc_data {
|
||||||
|
int nparams;
|
||||||
|
const struct uniphier_u3hsphy_param param[MAX_PHY_PARAMS];
|
||||||
|
u32 config0;
|
||||||
|
u32 config1;
|
||||||
|
void (*trim_func)(struct uniphier_u3hsphy_priv *priv, u32 *pconfig,
|
||||||
|
struct uniphier_u3hsphy_trim_param *pt);
|
||||||
|
};
|
||||||
|
|
||||||
|
static void uniphier_u3hsphy_trim_ld20(struct uniphier_u3hsphy_priv *priv,
|
||||||
|
u32 *pconfig,
|
||||||
|
struct uniphier_u3hsphy_trim_param *pt)
|
||||||
|
{
|
||||||
|
*pconfig &= ~HSPHY_CFG0_RTERM_MASK;
|
||||||
|
*pconfig |= FIELD_PREP(HSPHY_CFG0_RTERM_MASK, pt->rterm);
|
||||||
|
|
||||||
|
*pconfig &= ~HSPHY_CFG0_SEL_T_MASK;
|
||||||
|
*pconfig |= FIELD_PREP(HSPHY_CFG0_SEL_T_MASK, pt->sel_t);
|
||||||
|
|
||||||
|
*pconfig &= ~HSPHY_CFG0_HS_I_MASK;
|
||||||
|
*pconfig |= FIELD_PREP(HSPHY_CFG0_HS_I_MASK, pt->hs_i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_u3hsphy_get_nvparam(struct uniphier_u3hsphy_priv *priv,
|
||||||
|
const char *name, unsigned int *val)
|
||||||
|
{
|
||||||
|
struct nvmem_cell *cell;
|
||||||
|
u8 *buf;
|
||||||
|
|
||||||
|
cell = devm_nvmem_cell_get(priv->dev, name);
|
||||||
|
if (IS_ERR(cell))
|
||||||
|
return PTR_ERR(cell);
|
||||||
|
|
||||||
|
buf = nvmem_cell_read(cell, NULL);
|
||||||
|
if (IS_ERR(buf))
|
||||||
|
return PTR_ERR(buf);
|
||||||
|
|
||||||
|
*val = *buf;
|
||||||
|
|
||||||
|
kfree(buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_u3hsphy_get_nvparams(struct uniphier_u3hsphy_priv *priv,
|
||||||
|
struct uniphier_u3hsphy_trim_param *pt)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = uniphier_u3hsphy_get_nvparam(priv, "rterm", &pt->rterm);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = uniphier_u3hsphy_get_nvparam(priv, "sel_t", &pt->sel_t);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = uniphier_u3hsphy_get_nvparam(priv, "hs_i", &pt->hs_i);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_u3hsphy_update_config(struct uniphier_u3hsphy_priv *priv,
|
||||||
|
u32 *pconfig)
|
||||||
|
{
|
||||||
|
struct uniphier_u3hsphy_trim_param trim;
|
||||||
|
int ret, trimmed = 0;
|
||||||
|
|
||||||
|
if (priv->data->trim_func) {
|
||||||
|
ret = uniphier_u3hsphy_get_nvparams(priv, &trim);
|
||||||
|
if (ret == -EPROBE_DEFER)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call trim_func only when trimming parameters that aren't
|
||||||
|
* all-zero can be acquired. All-zero parameters mean nothing
|
||||||
|
* has been written to nvmem.
|
||||||
|
*/
|
||||||
|
if (!ret && trim_param_is_valid(&trim)) {
|
||||||
|
priv->data->trim_func(priv, pconfig, &trim);
|
||||||
|
trimmed = 1;
|
||||||
|
} else {
|
||||||
|
dev_dbg(priv->dev, "can't get parameter from nvmem\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* use default parameters without trimming values */
|
||||||
|
if (!trimmed) {
|
||||||
|
*pconfig &= ~HSPHY_CFG0_HSDISC_MASK;
|
||||||
|
*pconfig |= FIELD_PREP(HSPHY_CFG0_HSDISC_MASK, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uniphier_u3hsphy_set_param(struct uniphier_u3hsphy_priv *priv,
|
||||||
|
const struct uniphier_u3hsphy_param *p)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
u32 field_mask = GENMASK(p->field.msb, p->field.lsb);
|
||||||
|
u8 data;
|
||||||
|
|
||||||
|
val = readl(priv->base + HSPHY_CFG1);
|
||||||
|
val &= ~HSPHY_CFG1_ADR_MASK;
|
||||||
|
val |= FIELD_PREP(HSPHY_CFG1_ADR_MASK, p->field.reg_no)
|
||||||
|
| HSPHY_CFG1_ADR_EN;
|
||||||
|
writel(val, priv->base + HSPHY_CFG1);
|
||||||
|
|
||||||
|
val = readl(priv->base + HSPHY_CFG1);
|
||||||
|
val &= ~HSPHY_CFG1_ADR_EN;
|
||||||
|
writel(val, priv->base + HSPHY_CFG1);
|
||||||
|
|
||||||
|
val = readl(priv->base + HSPHY_CFG1);
|
||||||
|
val &= ~FIELD_PREP(HSPHY_CFG1_DAT_MASK, field_mask);
|
||||||
|
data = field_mask & (p->value << p->field.lsb);
|
||||||
|
val |= FIELD_PREP(HSPHY_CFG1_DAT_MASK, data) | HSPHY_CFG1_DAT_EN;
|
||||||
|
writel(val, priv->base + HSPHY_CFG1);
|
||||||
|
|
||||||
|
val = readl(priv->base + HSPHY_CFG1);
|
||||||
|
val &= ~HSPHY_CFG1_DAT_EN;
|
||||||
|
writel(val, priv->base + HSPHY_CFG1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_u3hsphy_power_on(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(priv->clk_ext);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(priv->clk);
|
||||||
|
if (ret)
|
||||||
|
goto out_clk_ext_disable;
|
||||||
|
|
||||||
|
ret = reset_control_deassert(priv->rst);
|
||||||
|
if (ret)
|
||||||
|
goto out_clk_disable;
|
||||||
|
|
||||||
|
if (priv->vbus) {
|
||||||
|
ret = regulator_enable(priv->vbus);
|
||||||
|
if (ret)
|
||||||
|
goto out_rst_assert;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_rst_assert:
|
||||||
|
reset_control_assert(priv->rst);
|
||||||
|
out_clk_disable:
|
||||||
|
clk_disable_unprepare(priv->clk);
|
||||||
|
out_clk_ext_disable:
|
||||||
|
clk_disable_unprepare(priv->clk_ext);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_u3hsphy_power_off(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
if (priv->vbus)
|
||||||
|
regulator_disable(priv->vbus);
|
||||||
|
|
||||||
|
reset_control_assert(priv->rst);
|
||||||
|
clk_disable_unprepare(priv->clk);
|
||||||
|
clk_disable_unprepare(priv->clk_ext);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_u3hsphy_init(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
u32 config0, config1;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(priv->clk_parent);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = reset_control_deassert(priv->rst_parent);
|
||||||
|
if (ret)
|
||||||
|
goto out_clk_disable;
|
||||||
|
|
||||||
|
if (!priv->data->config0 && !priv->data->config1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
config0 = priv->data->config0;
|
||||||
|
config1 = priv->data->config1;
|
||||||
|
|
||||||
|
ret = uniphier_u3hsphy_update_config(priv, &config0);
|
||||||
|
if (ret)
|
||||||
|
goto out_rst_assert;
|
||||||
|
|
||||||
|
writel(config0, priv->base + HSPHY_CFG0);
|
||||||
|
writel(config1, priv->base + HSPHY_CFG1);
|
||||||
|
|
||||||
|
for (i = 0; i < priv->data->nparams; i++)
|
||||||
|
uniphier_u3hsphy_set_param(priv, &priv->data->param[i]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_rst_assert:
|
||||||
|
reset_control_assert(priv->rst_parent);
|
||||||
|
out_clk_disable:
|
||||||
|
clk_disable_unprepare(priv->clk_parent);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_u3hsphy_exit(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
reset_control_assert(priv->rst_parent);
|
||||||
|
clk_disable_unprepare(priv->clk_parent);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct phy_ops uniphier_u3hsphy_ops = {
|
||||||
|
.init = uniphier_u3hsphy_init,
|
||||||
|
.exit = uniphier_u3hsphy_exit,
|
||||||
|
.power_on = uniphier_u3hsphy_power_on,
|
||||||
|
.power_off = uniphier_u3hsphy_power_off,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int uniphier_u3hsphy_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct uniphier_u3hsphy_priv *priv;
|
||||||
|
struct phy_provider *phy_provider;
|
||||||
|
struct resource *res;
|
||||||
|
struct phy *phy;
|
||||||
|
|
||||||
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->dev = dev;
|
||||||
|
priv->data = of_device_get_match_data(dev);
|
||||||
|
if (WARN_ON(!priv->data ||
|
||||||
|
priv->data->nparams > MAX_PHY_PARAMS))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
priv->base = devm_ioremap_resource(dev, res);
|
||||||
|
if (IS_ERR(priv->base))
|
||||||
|
return PTR_ERR(priv->base);
|
||||||
|
|
||||||
|
priv->clk = devm_clk_get(dev, "phy");
|
||||||
|
if (IS_ERR(priv->clk))
|
||||||
|
return PTR_ERR(priv->clk);
|
||||||
|
|
||||||
|
priv->clk_parent = devm_clk_get(dev, "link");
|
||||||
|
if (IS_ERR(priv->clk_parent))
|
||||||
|
return PTR_ERR(priv->clk_parent);
|
||||||
|
|
||||||
|
priv->clk_ext = devm_clk_get(dev, "phy-ext");
|
||||||
|
if (IS_ERR(priv->clk_ext)) {
|
||||||
|
if (PTR_ERR(priv->clk_ext) == -ENOENT)
|
||||||
|
priv->clk_ext = NULL;
|
||||||
|
else
|
||||||
|
return PTR_ERR(priv->clk_ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->rst = devm_reset_control_get_shared(dev, "phy");
|
||||||
|
if (IS_ERR(priv->rst))
|
||||||
|
return PTR_ERR(priv->rst);
|
||||||
|
|
||||||
|
priv->rst_parent = devm_reset_control_get_shared(dev, "link");
|
||||||
|
if (IS_ERR(priv->rst_parent))
|
||||||
|
return PTR_ERR(priv->rst_parent);
|
||||||
|
|
||||||
|
priv->vbus = devm_regulator_get_optional(dev, "vbus");
|
||||||
|
if (IS_ERR(priv->vbus)) {
|
||||||
|
if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
|
||||||
|
return PTR_ERR(priv->vbus);
|
||||||
|
priv->vbus = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
phy = devm_phy_create(dev, dev->of_node, &uniphier_u3hsphy_ops);
|
||||||
|
if (IS_ERR(phy))
|
||||||
|
return PTR_ERR(phy);
|
||||||
|
|
||||||
|
phy_set_drvdata(phy, priv);
|
||||||
|
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||||
|
|
||||||
|
return PTR_ERR_OR_ZERO(phy_provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = {
|
||||||
|
.nparams = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = {
|
||||||
|
.nparams = 2,
|
||||||
|
.param = {
|
||||||
|
{ LS_SLEW, 1 },
|
||||||
|
{ FS_LS_DRV, 1 },
|
||||||
|
},
|
||||||
|
.trim_func = uniphier_u3hsphy_trim_ld20,
|
||||||
|
.config0 = 0x92316680,
|
||||||
|
.config1 = 0x00000106,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = {
|
||||||
|
.nparams = 0,
|
||||||
|
.trim_func = uniphier_u3hsphy_trim_ld20,
|
||||||
|
.config0 = 0x92316680,
|
||||||
|
.config1 = 0x00000106,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id uniphier_u3hsphy_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "socionext,uniphier-pxs2-usb3-hsphy",
|
||||||
|
.data = &uniphier_pxs2_data,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "socionext,uniphier-ld20-usb3-hsphy",
|
||||||
|
.data = &uniphier_ld20_data,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "socionext,uniphier-pxs3-usb3-hsphy",
|
||||||
|
.data = &uniphier_pxs3_data,
|
||||||
|
},
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, uniphier_u3hsphy_match);
|
||||||
|
|
||||||
|
static struct platform_driver uniphier_u3hsphy_driver = {
|
||||||
|
.probe = uniphier_u3hsphy_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "uniphier-usb3-hsphy",
|
||||||
|
.of_match_table = uniphier_u3hsphy_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(uniphier_u3hsphy_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
|
||||||
|
MODULE_DESCRIPTION("UniPhier HS-PHY driver for USB3 controller");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
349
drivers/phy/socionext/phy-uniphier-usb3ss.c
Normal file
349
drivers/phy/socionext/phy-uniphier-usb3ss.c
Normal file
|
@ -0,0 +1,349 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* phy-uniphier-usb3ss.c - SS-PHY driver for Socionext UniPhier USB3 controller
|
||||||
|
* Copyright 2015-2018 Socionext Inc.
|
||||||
|
* Author:
|
||||||
|
* Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
|
||||||
|
* Contributors:
|
||||||
|
* Motoya Tanigawa <tanigawa.motoya@socionext.com>
|
||||||
|
* Masami Hiramatsu <masami.hiramatsu@linaro.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitfield.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/phy/phy.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/reset.h>
|
||||||
|
|
||||||
|
#define SSPHY_TESTI 0x0
|
||||||
|
#define SSPHY_TESTO 0x4
|
||||||
|
#define TESTI_DAT_MASK GENMASK(13, 6)
|
||||||
|
#define TESTI_ADR_MASK GENMASK(5, 1)
|
||||||
|
#define TESTI_WR_EN BIT(0)
|
||||||
|
|
||||||
|
#define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
|
||||||
|
|
||||||
|
#define CDR_CPD_TRIM PHY_F(7, 3, 0) /* RxPLL charge pump current */
|
||||||
|
#define CDR_CPF_TRIM PHY_F(8, 3, 0) /* RxPLL charge pump current 2 */
|
||||||
|
#define TX_PLL_TRIM PHY_F(9, 3, 0) /* TxPLL charge pump current */
|
||||||
|
#define BGAP_TRIM PHY_F(11, 3, 0) /* Bandgap voltage */
|
||||||
|
#define CDR_TRIM PHY_F(13, 6, 5) /* Clock Data Recovery setting */
|
||||||
|
#define VCO_CTRL PHY_F(26, 7, 4) /* VCO control */
|
||||||
|
#define VCOPLL_CTRL PHY_F(27, 2, 0) /* TxPLL VCO tuning */
|
||||||
|
#define VCOPLL_CM PHY_F(28, 1, 0) /* TxPLL voltage */
|
||||||
|
|
||||||
|
#define MAX_PHY_PARAMS 7
|
||||||
|
|
||||||
|
struct uniphier_u3ssphy_param {
|
||||||
|
struct {
|
||||||
|
int reg_no;
|
||||||
|
int msb;
|
||||||
|
int lsb;
|
||||||
|
} field;
|
||||||
|
u8 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uniphier_u3ssphy_priv {
|
||||||
|
struct device *dev;
|
||||||
|
void __iomem *base;
|
||||||
|
struct clk *clk, *clk_ext, *clk_parent, *clk_parent_gio;
|
||||||
|
struct reset_control *rst, *rst_parent, *rst_parent_gio;
|
||||||
|
struct regulator *vbus;
|
||||||
|
const struct uniphier_u3ssphy_soc_data *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uniphier_u3ssphy_soc_data {
|
||||||
|
bool is_legacy;
|
||||||
|
int nparams;
|
||||||
|
const struct uniphier_u3ssphy_param param[MAX_PHY_PARAMS];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void uniphier_u3ssphy_testio_write(struct uniphier_u3ssphy_priv *priv,
|
||||||
|
u32 data)
|
||||||
|
{
|
||||||
|
/* need to read TESTO twice after accessing TESTI */
|
||||||
|
writel(data, priv->base + SSPHY_TESTI);
|
||||||
|
readl(priv->base + SSPHY_TESTO);
|
||||||
|
readl(priv->base + SSPHY_TESTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uniphier_u3ssphy_set_param(struct uniphier_u3ssphy_priv *priv,
|
||||||
|
const struct uniphier_u3ssphy_param *p)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
u8 field_mask = GENMASK(p->field.msb, p->field.lsb);
|
||||||
|
u8 data;
|
||||||
|
|
||||||
|
/* read previous data */
|
||||||
|
val = FIELD_PREP(TESTI_DAT_MASK, 1);
|
||||||
|
val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no);
|
||||||
|
uniphier_u3ssphy_testio_write(priv, val);
|
||||||
|
val = readl(priv->base + SSPHY_TESTO);
|
||||||
|
|
||||||
|
/* update value */
|
||||||
|
val &= ~FIELD_PREP(TESTI_DAT_MASK, field_mask);
|
||||||
|
data = field_mask & (p->value << p->field.lsb);
|
||||||
|
val = FIELD_PREP(TESTI_DAT_MASK, data);
|
||||||
|
val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no);
|
||||||
|
uniphier_u3ssphy_testio_write(priv, val);
|
||||||
|
uniphier_u3ssphy_testio_write(priv, val | TESTI_WR_EN);
|
||||||
|
uniphier_u3ssphy_testio_write(priv, val);
|
||||||
|
|
||||||
|
/* read current data as dummy */
|
||||||
|
val = FIELD_PREP(TESTI_DAT_MASK, 1);
|
||||||
|
val |= FIELD_PREP(TESTI_ADR_MASK, p->field.reg_no);
|
||||||
|
uniphier_u3ssphy_testio_write(priv, val);
|
||||||
|
readl(priv->base + SSPHY_TESTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_u3ssphy_power_on(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(priv->clk_ext);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(priv->clk);
|
||||||
|
if (ret)
|
||||||
|
goto out_clk_ext_disable;
|
||||||
|
|
||||||
|
ret = reset_control_deassert(priv->rst);
|
||||||
|
if (ret)
|
||||||
|
goto out_clk_disable;
|
||||||
|
|
||||||
|
if (priv->vbus) {
|
||||||
|
ret = regulator_enable(priv->vbus);
|
||||||
|
if (ret)
|
||||||
|
goto out_rst_assert;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_rst_assert:
|
||||||
|
reset_control_assert(priv->rst);
|
||||||
|
out_clk_disable:
|
||||||
|
clk_disable_unprepare(priv->clk);
|
||||||
|
out_clk_ext_disable:
|
||||||
|
clk_disable_unprepare(priv->clk_ext);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_u3ssphy_power_off(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
if (priv->vbus)
|
||||||
|
regulator_disable(priv->vbus);
|
||||||
|
|
||||||
|
reset_control_assert(priv->rst);
|
||||||
|
clk_disable_unprepare(priv->clk);
|
||||||
|
clk_disable_unprepare(priv->clk_ext);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_u3ssphy_init(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(priv->clk_parent);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(priv->clk_parent_gio);
|
||||||
|
if (ret)
|
||||||
|
goto out_clk_disable;
|
||||||
|
|
||||||
|
ret = reset_control_deassert(priv->rst_parent);
|
||||||
|
if (ret)
|
||||||
|
goto out_clk_gio_disable;
|
||||||
|
|
||||||
|
ret = reset_control_deassert(priv->rst_parent_gio);
|
||||||
|
if (ret)
|
||||||
|
goto out_rst_assert;
|
||||||
|
|
||||||
|
if (priv->data->is_legacy)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < priv->data->nparams; i++)
|
||||||
|
uniphier_u3ssphy_set_param(priv, &priv->data->param[i]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_rst_assert:
|
||||||
|
reset_control_assert(priv->rst_parent);
|
||||||
|
out_clk_gio_disable:
|
||||||
|
clk_disable_unprepare(priv->clk_parent_gio);
|
||||||
|
out_clk_disable:
|
||||||
|
clk_disable_unprepare(priv->clk_parent);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uniphier_u3ssphy_exit(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct uniphier_u3ssphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
reset_control_assert(priv->rst_parent_gio);
|
||||||
|
reset_control_assert(priv->rst_parent);
|
||||||
|
clk_disable_unprepare(priv->clk_parent_gio);
|
||||||
|
clk_disable_unprepare(priv->clk_parent);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct phy_ops uniphier_u3ssphy_ops = {
|
||||||
|
.init = uniphier_u3ssphy_init,
|
||||||
|
.exit = uniphier_u3ssphy_exit,
|
||||||
|
.power_on = uniphier_u3ssphy_power_on,
|
||||||
|
.power_off = uniphier_u3ssphy_power_off,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int uniphier_u3ssphy_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct uniphier_u3ssphy_priv *priv;
|
||||||
|
struct phy_provider *phy_provider;
|
||||||
|
struct resource *res;
|
||||||
|
struct phy *phy;
|
||||||
|
|
||||||
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->dev = dev;
|
||||||
|
priv->data = of_device_get_match_data(dev);
|
||||||
|
if (WARN_ON(!priv->data ||
|
||||||
|
priv->data->nparams > MAX_PHY_PARAMS))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
priv->base = devm_ioremap_resource(dev, res);
|
||||||
|
if (IS_ERR(priv->base))
|
||||||
|
return PTR_ERR(priv->base);
|
||||||
|
|
||||||
|
if (!priv->data->is_legacy) {
|
||||||
|
priv->clk = devm_clk_get(dev, "phy");
|
||||||
|
if (IS_ERR(priv->clk))
|
||||||
|
return PTR_ERR(priv->clk);
|
||||||
|
|
||||||
|
priv->clk_ext = devm_clk_get(dev, "phy-ext");
|
||||||
|
if (IS_ERR(priv->clk_ext)) {
|
||||||
|
if (PTR_ERR(priv->clk_ext) == -ENOENT)
|
||||||
|
priv->clk_ext = NULL;
|
||||||
|
else
|
||||||
|
return PTR_ERR(priv->clk_ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->rst = devm_reset_control_get_shared(dev, "phy");
|
||||||
|
if (IS_ERR(priv->rst))
|
||||||
|
return PTR_ERR(priv->rst);
|
||||||
|
} else {
|
||||||
|
priv->clk_parent_gio = devm_clk_get(dev, "gio");
|
||||||
|
if (IS_ERR(priv->clk_parent_gio))
|
||||||
|
return PTR_ERR(priv->clk_parent_gio);
|
||||||
|
|
||||||
|
priv->rst_parent_gio =
|
||||||
|
devm_reset_control_get_shared(dev, "gio");
|
||||||
|
if (IS_ERR(priv->rst_parent_gio))
|
||||||
|
return PTR_ERR(priv->rst_parent_gio);
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->clk_parent = devm_clk_get(dev, "link");
|
||||||
|
if (IS_ERR(priv->clk_parent))
|
||||||
|
return PTR_ERR(priv->clk_parent);
|
||||||
|
|
||||||
|
priv->rst_parent = devm_reset_control_get_shared(dev, "link");
|
||||||
|
if (IS_ERR(priv->rst_parent))
|
||||||
|
return PTR_ERR(priv->rst_parent);
|
||||||
|
|
||||||
|
priv->vbus = devm_regulator_get_optional(dev, "vbus");
|
||||||
|
if (IS_ERR(priv->vbus)) {
|
||||||
|
if (PTR_ERR(priv->vbus) == -EPROBE_DEFER)
|
||||||
|
return PTR_ERR(priv->vbus);
|
||||||
|
priv->vbus = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
phy = devm_phy_create(dev, dev->of_node, &uniphier_u3ssphy_ops);
|
||||||
|
if (IS_ERR(phy))
|
||||||
|
return PTR_ERR(phy);
|
||||||
|
|
||||||
|
phy_set_drvdata(phy, priv);
|
||||||
|
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||||
|
|
||||||
|
return PTR_ERR_OR_ZERO(phy_provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct uniphier_u3ssphy_soc_data uniphier_pro4_data = {
|
||||||
|
.is_legacy = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct uniphier_u3ssphy_soc_data uniphier_pxs2_data = {
|
||||||
|
.is_legacy = false,
|
||||||
|
.nparams = 7,
|
||||||
|
.param = {
|
||||||
|
{ CDR_CPD_TRIM, 10 },
|
||||||
|
{ CDR_CPF_TRIM, 3 },
|
||||||
|
{ TX_PLL_TRIM, 5 },
|
||||||
|
{ BGAP_TRIM, 9 },
|
||||||
|
{ CDR_TRIM, 2 },
|
||||||
|
{ VCOPLL_CTRL, 7 },
|
||||||
|
{ VCOPLL_CM, 1 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct uniphier_u3ssphy_soc_data uniphier_ld20_data = {
|
||||||
|
.is_legacy = false,
|
||||||
|
.nparams = 3,
|
||||||
|
.param = {
|
||||||
|
{ CDR_CPD_TRIM, 6 },
|
||||||
|
{ CDR_TRIM, 2 },
|
||||||
|
{ VCO_CTRL, 5 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id uniphier_u3ssphy_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "socionext,uniphier-pro4-usb3-ssphy",
|
||||||
|
.data = &uniphier_pro4_data,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "socionext,uniphier-pxs2-usb3-ssphy",
|
||||||
|
.data = &uniphier_pxs2_data,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "socionext,uniphier-ld20-usb3-ssphy",
|
||||||
|
.data = &uniphier_ld20_data,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "socionext,uniphier-pxs3-usb3-ssphy",
|
||||||
|
.data = &uniphier_ld20_data,
|
||||||
|
},
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, uniphier_u3ssphy_match);
|
||||||
|
|
||||||
|
static struct platform_driver uniphier_u3ssphy_driver = {
|
||||||
|
.probe = uniphier_u3ssphy_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "uniphier-usb3-ssphy",
|
||||||
|
.of_match_table = uniphier_u3ssphy_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(uniphier_u3ssphy_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
|
||||||
|
MODULE_DESCRIPTION("UniPhier SS-PHY driver for USB3 controller");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -115,8 +115,8 @@ int tegra_xusb_lane_parse_dt(struct tegra_xusb_lane *lane,
|
||||||
|
|
||||||
err = match_string(lane->soc->funcs, lane->soc->num_funcs, function);
|
err = match_string(lane->soc->funcs, lane->soc->num_funcs, function);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(dev, "invalid function \"%s\" for lane \"%s\"\n",
|
dev_err(dev, "invalid function \"%s\" for lane \"%pOFn\"\n",
|
||||||
function, np->name);
|
function, np);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,7 @@
|
||||||
#define PMBR1 0x0D
|
#define PMBR1 0x0D
|
||||||
#define GPIO_USB_4PIN_ULPI_2430C (3 << 0)
|
#define GPIO_USB_4PIN_ULPI_2430C (3 << 0)
|
||||||
|
|
||||||
|
static irqreturn_t twl4030_usb_irq(int irq, void *_twl);
|
||||||
/*
|
/*
|
||||||
* If VBUS is valid or ID is ground, then we know a
|
* If VBUS is valid or ID is ground, then we know a
|
||||||
* cable is present and we need to be runtime-enabled
|
* cable is present and we need to be runtime-enabled
|
||||||
|
@ -395,6 +396,33 @@ static void __twl4030_phy_power(struct twl4030_usb *twl, int on)
|
||||||
WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
|
WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused twl4030_usb_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct twl4030_usb *twl = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we need enabled runtime on resume,
|
||||||
|
* so turn irq off here, so we do not get it early
|
||||||
|
* note: wakeup on usb plug works independently of this
|
||||||
|
*/
|
||||||
|
dev_dbg(twl->dev, "%s\n", __func__);
|
||||||
|
disable_irq(twl->irq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused twl4030_usb_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct twl4030_usb *twl = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
dev_dbg(twl->dev, "%s\n", __func__);
|
||||||
|
enable_irq(twl->irq);
|
||||||
|
/* check whether cable status changed */
|
||||||
|
twl4030_usb_irq(0, twl);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int __maybe_unused twl4030_usb_runtime_suspend(struct device *dev)
|
static int __maybe_unused twl4030_usb_runtime_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct twl4030_usb *twl = dev_get_drvdata(dev);
|
struct twl4030_usb *twl = dev_get_drvdata(dev);
|
||||||
|
@ -655,6 +683,7 @@ static const struct phy_ops ops = {
|
||||||
static const struct dev_pm_ops twl4030_usb_pm_ops = {
|
static const struct dev_pm_ops twl4030_usb_pm_ops = {
|
||||||
SET_RUNTIME_PM_OPS(twl4030_usb_runtime_suspend,
|
SET_RUNTIME_PM_OPS(twl4030_usb_runtime_suspend,
|
||||||
twl4030_usb_runtime_resume, NULL)
|
twl4030_usb_runtime_resume, NULL)
|
||||||
|
SET_SYSTEM_SLEEP_PM_OPS(twl4030_usb_suspend, twl4030_usb_resume)
|
||||||
};
|
};
|
||||||
|
|
||||||
static int twl4030_usb_probe(struct platform_device *pdev)
|
static int twl4030_usb_probe(struct platform_device *pdev)
|
||||||
|
|
|
@ -867,6 +867,8 @@ config INTEL_CHT_INT33FE
|
||||||
tristate "Intel Cherry Trail ACPI INT33FE Driver"
|
tristate "Intel Cherry Trail ACPI INT33FE Driver"
|
||||||
depends on X86 && ACPI && I2C && REGULATOR
|
depends on X86 && ACPI && I2C && REGULATOR
|
||||||
depends on CHARGER_BQ24190=y || (CHARGER_BQ24190=m && m)
|
depends on CHARGER_BQ24190=y || (CHARGER_BQ24190=m && m)
|
||||||
|
depends on USB_ROLES_INTEL_XHCI=y || (USB_ROLES_INTEL_XHCI=m && m)
|
||||||
|
depends on TYPEC_MUX_PI3USB30532=y || (TYPEC_MUX_PI3USB30532=m && m)
|
||||||
---help---
|
---help---
|
||||||
This driver add support for the INT33FE ACPI device found on
|
This driver add support for the INT33FE ACPI device found on
|
||||||
some Intel Cherry Trail devices.
|
some Intel Cherry Trail devices.
|
||||||
|
|
|
@ -35,7 +35,7 @@ struct cht_int33fe_data {
|
||||||
struct i2c_client *fusb302;
|
struct i2c_client *fusb302;
|
||||||
struct i2c_client *pi3usb30532;
|
struct i2c_client *pi3usb30532;
|
||||||
/* Contain a list-head must be per device */
|
/* Contain a list-head must be per device */
|
||||||
struct device_connection connections[3];
|
struct device_connection connections[5];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -175,19 +175,20 @@ static int cht_int33fe_probe(struct platform_device *pdev)
|
||||||
return -EPROBE_DEFER; /* Wait for i2c-adapter to load */
|
return -EPROBE_DEFER; /* Wait for i2c-adapter to load */
|
||||||
}
|
}
|
||||||
|
|
||||||
data->connections[0].endpoint[0] = "i2c-fusb302";
|
data->connections[0].endpoint[0] = "port0";
|
||||||
data->connections[0].endpoint[1] = "i2c-pi3usb30532";
|
data->connections[0].endpoint[1] = "i2c-pi3usb30532";
|
||||||
data->connections[0].id = "typec-switch";
|
data->connections[0].id = "typec-switch";
|
||||||
data->connections[1].endpoint[0] = "i2c-fusb302";
|
data->connections[1].endpoint[0] = "port0";
|
||||||
data->connections[1].endpoint[1] = "i2c-pi3usb30532";
|
data->connections[1].endpoint[1] = "i2c-pi3usb30532";
|
||||||
data->connections[1].id = "typec-mux";
|
data->connections[1].id = "typec-mux";
|
||||||
data->connections[2].endpoint[0] = "i2c-fusb302";
|
data->connections[2].endpoint[0] = "port0";
|
||||||
data->connections[2].endpoint[1] = "intel_xhci_usb_sw-role-switch";
|
data->connections[2].endpoint[1] = "i2c-pi3usb30532";
|
||||||
data->connections[2].id = "usb-role-switch";
|
data->connections[2].id = "idff01m01";
|
||||||
|
data->connections[3].endpoint[0] = "i2c-fusb302";
|
||||||
|
data->connections[3].endpoint[1] = "intel_xhci_usb_sw-role-switch";
|
||||||
|
data->connections[3].id = "usb-role-switch";
|
||||||
|
|
||||||
device_connection_add(&data->connections[0]);
|
device_connections_add(data->connections);
|
||||||
device_connection_add(&data->connections[1]);
|
|
||||||
device_connection_add(&data->connections[2]);
|
|
||||||
|
|
||||||
memset(&board_info, 0, sizeof(board_info));
|
memset(&board_info, 0, sizeof(board_info));
|
||||||
strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE);
|
strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE);
|
||||||
|
@ -218,9 +219,7 @@ out_unregister_max17047:
|
||||||
if (data->max17047)
|
if (data->max17047)
|
||||||
i2c_unregister_device(data->max17047);
|
i2c_unregister_device(data->max17047);
|
||||||
|
|
||||||
device_connection_remove(&data->connections[2]);
|
device_connections_remove(data->connections);
|
||||||
device_connection_remove(&data->connections[1]);
|
|
||||||
device_connection_remove(&data->connections[0]);
|
|
||||||
|
|
||||||
return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
|
return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
|
||||||
}
|
}
|
||||||
|
@ -234,9 +233,7 @@ static int cht_int33fe_remove(struct platform_device *pdev)
|
||||||
if (data->max17047)
|
if (data->max17047)
|
||||||
i2c_unregister_device(data->max17047);
|
i2c_unregister_device(data->max17047);
|
||||||
|
|
||||||
device_connection_remove(&data->connections[2]);
|
device_connections_remove(data->connections);
|
||||||
device_connection_remove(&data->connections[1]);
|
|
||||||
device_connection_remove(&data->connections[0]);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/phy/phy.h>
|
#include <linux/phy/phy.h>
|
||||||
#include <linux/phy/phy-qcom-ufs.h>
|
|
||||||
|
|
||||||
#include "ufshcd.h"
|
#include "ufshcd.h"
|
||||||
#include "ufshcd-pltfrm.h"
|
#include "ufshcd-pltfrm.h"
|
||||||
|
@ -191,22 +190,9 @@ out:
|
||||||
|
|
||||||
static int ufs_qcom_link_startup_post_change(struct ufs_hba *hba)
|
static int ufs_qcom_link_startup_post_change(struct ufs_hba *hba)
|
||||||
{
|
{
|
||||||
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
|
||||||
struct phy *phy = host->generic_phy;
|
|
||||||
u32 tx_lanes;
|
u32 tx_lanes;
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
err = ufs_qcom_get_connected_tx_lanes(hba, &tx_lanes);
|
return ufs_qcom_get_connected_tx_lanes(hba, &tx_lanes);
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
err = ufs_qcom_phy_set_tx_lane_enable(phy, tx_lanes);
|
|
||||||
if (err)
|
|
||||||
dev_err(hba->dev, "%s: ufs_qcom_phy_set_tx_lane_enable failed\n",
|
|
||||||
__func__);
|
|
||||||
|
|
||||||
out:
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ufs_qcom_check_hibern8(struct ufs_hba *hba)
|
static int ufs_qcom_check_hibern8(struct ufs_hba *hba)
|
||||||
|
@ -934,10 +920,8 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
struct phy *phy = host->generic_phy;
|
|
||||||
struct ufs_qcom_dev_params ufs_qcom_cap;
|
struct ufs_qcom_dev_params ufs_qcom_cap;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int res = 0;
|
|
||||||
|
|
||||||
if (!dev_req_params) {
|
if (!dev_req_params) {
|
||||||
pr_err("%s: incoming dev_req_params is NULL\n", __func__);
|
pr_err("%s: incoming dev_req_params is NULL\n", __func__);
|
||||||
|
@ -1004,12 +988,6 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
|
||||||
}
|
}
|
||||||
|
|
||||||
val = ~(MAX_U32 << dev_req_params->lane_tx);
|
val = ~(MAX_U32 << dev_req_params->lane_tx);
|
||||||
res = ufs_qcom_phy_set_tx_lane_enable(phy, val);
|
|
||||||
if (res) {
|
|
||||||
dev_err(hba->dev, "%s: ufs_qcom_phy_set_tx_lane_enable() failed res = %d\n",
|
|
||||||
__func__, res);
|
|
||||||
ret = res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* cache the power mode parameters to use internally */
|
/* cache the power mode parameters to use internally */
|
||||||
memcpy(&host->dev_req_params,
|
memcpy(&host->dev_req_params,
|
||||||
|
@ -1266,10 +1244,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update phy revision information before calling phy_init() */
|
|
||||||
ufs_qcom_phy_save_controller_version(host->generic_phy,
|
|
||||||
host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step);
|
|
||||||
|
|
||||||
err = ufs_qcom_init_lane_clks(host);
|
err = ufs_qcom_init_lane_clks(host);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_variant_clear;
|
goto out_variant_clear;
|
||||||
|
|
|
@ -129,11 +129,6 @@ enum {
|
||||||
MASK_CLK_NS_REG = 0xFFFC00,
|
MASK_CLK_NS_REG = 0xFFFC00,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ufs_qcom_phy_init_type {
|
|
||||||
UFS_PHY_INIT_FULL,
|
|
||||||
UFS_PHY_INIT_CFG_RESTORE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* QCOM UFS debug print bit mask */
|
/* QCOM UFS debug print bit mask */
|
||||||
#define UFS_QCOM_DBG_PRINT_REGS_EN BIT(0)
|
#define UFS_QCOM_DBG_PRINT_REGS_EN BIT(0)
|
||||||
#define UFS_QCOM_DBG_PRINT_ICE_REGS_EN BIT(1)
|
#define UFS_QCOM_DBG_PRINT_ICE_REGS_EN BIT(1)
|
||||||
|
|
|
@ -364,8 +364,7 @@ static void ci_hdrc_imx_shutdown(struct platform_device *pdev)
|
||||||
ci_hdrc_imx_remove(pdev);
|
ci_hdrc_imx_remove(pdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
static int __maybe_unused imx_controller_suspend(struct device *dev)
|
||||||
static int imx_controller_suspend(struct device *dev)
|
|
||||||
{
|
{
|
||||||
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
|
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
@ -377,7 +376,7 @@ static int imx_controller_suspend(struct device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int imx_controller_resume(struct device *dev)
|
static int __maybe_unused imx_controller_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
|
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -408,8 +407,7 @@ clk_disable:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
static int __maybe_unused ci_hdrc_imx_suspend(struct device *dev)
|
||||||
static int ci_hdrc_imx_suspend(struct device *dev)
|
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -431,7 +429,7 @@ static int ci_hdrc_imx_suspend(struct device *dev)
|
||||||
return imx_controller_suspend(dev);
|
return imx_controller_suspend(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ci_hdrc_imx_resume(struct device *dev)
|
static int __maybe_unused ci_hdrc_imx_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
|
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -445,9 +443,8 @@ static int ci_hdrc_imx_resume(struct device *dev)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PM_SLEEP */
|
|
||||||
|
|
||||||
static int ci_hdrc_imx_runtime_suspend(struct device *dev)
|
static int __maybe_unused ci_hdrc_imx_runtime_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
|
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -466,13 +463,11 @@ static int ci_hdrc_imx_runtime_suspend(struct device *dev)
|
||||||
return imx_controller_suspend(dev);
|
return imx_controller_suspend(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ci_hdrc_imx_runtime_resume(struct device *dev)
|
static int __maybe_unused ci_hdrc_imx_runtime_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
return imx_controller_resume(dev);
|
return imx_controller_resume(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_PM */
|
|
||||||
|
|
||||||
static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
|
static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
|
||||||
SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume)
|
SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume)
|
||||||
SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend,
|
SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend,
|
||||||
|
@ -492,7 +487,7 @@ static struct platform_driver ci_hdrc_imx_driver = {
|
||||||
module_platform_driver(ci_hdrc_imx_driver);
|
module_platform_driver(ci_hdrc_imx_driver);
|
||||||
|
|
||||||
MODULE_ALIAS("platform:imx-usb");
|
MODULE_ALIAS("platform:imx-usb");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_DESCRIPTION("CI HDRC i.MX USB binding");
|
MODULE_DESCRIPTION("CI HDRC i.MX USB binding");
|
||||||
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
|
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
|
||||||
MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
|
MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
#include <linux/pinctrl/consumer.h>
|
||||||
#include <linux/usb/ch9.h>
|
#include <linux/usb/ch9.h>
|
||||||
#include <linux/usb/gadget.h>
|
#include <linux/usb/gadget.h>
|
||||||
#include <linux/usb/otg.h>
|
#include <linux/usb/otg.h>
|
||||||
|
@ -723,6 +724,24 @@ static int ci_get_platdata(struct device *dev,
|
||||||
else
|
else
|
||||||
cable->connected = false;
|
cable->connected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
platdata->pctl = devm_pinctrl_get(dev);
|
||||||
|
if (!IS_ERR(platdata->pctl)) {
|
||||||
|
struct pinctrl_state *p;
|
||||||
|
|
||||||
|
p = pinctrl_lookup_state(platdata->pctl, "default");
|
||||||
|
if (!IS_ERR(p))
|
||||||
|
platdata->pins_default = p;
|
||||||
|
|
||||||
|
p = pinctrl_lookup_state(platdata->pctl, "host");
|
||||||
|
if (!IS_ERR(p))
|
||||||
|
platdata->pins_host = p;
|
||||||
|
|
||||||
|
p = pinctrl_lookup_state(platdata->pctl, "device");
|
||||||
|
if (!IS_ERR(p))
|
||||||
|
platdata->pins_device = p;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <linux/usb/hcd.h>
|
#include <linux/usb/hcd.h>
|
||||||
#include <linux/usb/chipidea.h>
|
#include <linux/usb/chipidea.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/pinctrl/consumer.h>
|
||||||
|
|
||||||
#include "../host/ehci.h"
|
#include "../host/ehci.h"
|
||||||
|
|
||||||
|
@ -153,6 +154,10 @@ static int host_start(struct ci_hdrc *ci)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ci->platdata->pins_host)
|
||||||
|
pinctrl_select_state(ci->platdata->pctl,
|
||||||
|
ci->platdata->pins_host);
|
||||||
|
|
||||||
ret = usb_add_hcd(hcd, 0, 0);
|
ret = usb_add_hcd(hcd, 0, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
goto disable_reg;
|
goto disable_reg;
|
||||||
|
@ -197,6 +202,10 @@ static void host_stop(struct ci_hdrc *ci)
|
||||||
}
|
}
|
||||||
ci->hcd = NULL;
|
ci->hcd = NULL;
|
||||||
ci->otg.host = NULL;
|
ci->otg.host = NULL;
|
||||||
|
|
||||||
|
if (ci->platdata->pins_host && ci->platdata->pins_default)
|
||||||
|
pinctrl_select_state(ci->platdata->pctl,
|
||||||
|
ci->platdata->pins_default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -203,14 +203,17 @@ static void ci_otg_work(struct work_struct *work)
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_runtime_get_sync(ci->dev);
|
pm_runtime_get_sync(ci->dev);
|
||||||
|
|
||||||
if (ci->id_event) {
|
if (ci->id_event) {
|
||||||
ci->id_event = false;
|
ci->id_event = false;
|
||||||
ci_handle_id_switch(ci);
|
ci_handle_id_switch(ci);
|
||||||
} else if (ci->b_sess_valid_event) {
|
}
|
||||||
|
|
||||||
|
if (ci->b_sess_valid_event) {
|
||||||
ci->b_sess_valid_event = false;
|
ci->b_sess_valid_event = false;
|
||||||
ci_handle_vbus_change(ci);
|
ci_handle_vbus_change(ci);
|
||||||
} else
|
}
|
||||||
dev_err(ci->dev, "unexpected event occurs at %s\n", __func__);
|
|
||||||
pm_runtime_put_sync(ci->dev);
|
pm_runtime_put_sync(ci->dev);
|
||||||
|
|
||||||
enable_irq(ci->irq);
|
enable_irq(ci->irq);
|
||||||
|
|
|
@ -17,7 +17,8 @@ void ci_handle_vbus_change(struct ci_hdrc *ci);
|
||||||
static inline void ci_otg_queue_work(struct ci_hdrc *ci)
|
static inline void ci_otg_queue_work(struct ci_hdrc *ci)
|
||||||
{
|
{
|
||||||
disable_irq_nosync(ci->irq);
|
disable_irq_nosync(ci->irq);
|
||||||
queue_work(ci->wq, &ci->work);
|
if (queue_work(ci->wq, &ci->work) == false)
|
||||||
|
enable_irq(ci->irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */
|
#endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
#include <linux/pinctrl/consumer.h>
|
||||||
#include <linux/usb/ch9.h>
|
#include <linux/usb/ch9.h>
|
||||||
#include <linux/usb/gadget.h>
|
#include <linux/usb/gadget.h>
|
||||||
#include <linux/usb/otg-fsm.h>
|
#include <linux/usb/otg-fsm.h>
|
||||||
|
@ -1965,6 +1966,10 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
|
||||||
|
|
||||||
static int udc_id_switch_for_device(struct ci_hdrc *ci)
|
static int udc_id_switch_for_device(struct ci_hdrc *ci)
|
||||||
{
|
{
|
||||||
|
if (ci->platdata->pins_device)
|
||||||
|
pinctrl_select_state(ci->platdata->pctl,
|
||||||
|
ci->platdata->pins_device);
|
||||||
|
|
||||||
if (ci->is_otg)
|
if (ci->is_otg)
|
||||||
/* Clear and enable BSV irq */
|
/* Clear and enable BSV irq */
|
||||||
hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
|
hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
|
||||||
|
@ -1983,6 +1988,10 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci)
|
||||||
hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS);
|
hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS);
|
||||||
|
|
||||||
ci->vbus_active = 0;
|
ci->vbus_active = 0;
|
||||||
|
|
||||||
|
if (ci->platdata->pins_device && ci->platdata->pins_default)
|
||||||
|
pinctrl_select_state(ci->platdata->pctl,
|
||||||
|
ci->platdata->pins_default);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -343,6 +343,8 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
|
||||||
} else if (data->oc_polarity == 1) {
|
} else if (data->oc_polarity == 1) {
|
||||||
/* High active */
|
/* High active */
|
||||||
reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY);
|
reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY);
|
||||||
|
} else {
|
||||||
|
reg &= ~(MX6_BM_OVER_CUR_DIS);
|
||||||
}
|
}
|
||||||
writel(reg, usbmisc->base + data->index * 4);
|
writel(reg, usbmisc->base + data->index * 4);
|
||||||
|
|
||||||
|
@ -633,6 +635,6 @@ static struct platform_driver usbmisc_imx_driver = {
|
||||||
module_platform_driver(usbmisc_imx_driver);
|
module_platform_driver(usbmisc_imx_driver);
|
||||||
|
|
||||||
MODULE_ALIAS("platform:usbmisc-imx");
|
MODULE_ALIAS("platform:usbmisc-imx");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_DESCRIPTION("driver for imx usb non-core registers");
|
MODULE_DESCRIPTION("driver for imx usb non-core registers");
|
||||||
MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
|
MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -101,14 +101,10 @@ void hcd_buffer_destroy(struct usb_hcd *hcd)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
|
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
|
||||||
struct dma_pool *pool = hcd->pool[i];
|
dma_pool_destroy(hcd->pool[i]);
|
||||||
|
|
||||||
if (pool) {
|
|
||||||
dma_pool_destroy(pool);
|
|
||||||
hcd->pool[i] = NULL;
|
hcd->pool[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* sometimes alloc/free could use kmalloc with GFP_DMA, for
|
/* sometimes alloc/free could use kmalloc with GFP_DMA, for
|
||||||
|
|
|
@ -510,7 +510,6 @@ int usb_driver_claim_interface(struct usb_driver *driver,
|
||||||
struct usb_interface *iface, void *priv)
|
struct usb_interface *iface, void *priv)
|
||||||
{
|
{
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct usb_device *udev;
|
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
if (!iface)
|
if (!iface)
|
||||||
|
@ -524,8 +523,6 @@ int usb_driver_claim_interface(struct usb_driver *driver,
|
||||||
if (!iface->authorized)
|
if (!iface->authorized)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
udev = interface_to_usbdev(iface);
|
|
||||||
|
|
||||||
dev->driver = &driver->drvwrap.driver;
|
dev->driver = &driver->drvwrap.driver;
|
||||||
usb_set_intfdata(iface, priv);
|
usb_set_intfdata(iface, priv);
|
||||||
iface->needs_binding = 0;
|
iface->needs_binding = 0;
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include <linux/usb.h>
|
#include <linux/usb.h>
|
||||||
#include <linux/usb/hcd.h>
|
#include <linux/usb/hcd.h>
|
||||||
|
#include <uapi/linux/usb/audio.h>
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
|
|
||||||
static inline const char *plural(int n)
|
static inline const char *plural(int n)
|
||||||
|
@ -42,6 +43,16 @@ static int is_activesync(struct usb_interface_descriptor *desc)
|
||||||
&& desc->bInterfaceProtocol == 1;
|
&& desc->bInterfaceProtocol == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_audio(struct usb_interface_descriptor *desc)
|
||||||
|
{
|
||||||
|
return desc->bInterfaceClass == USB_CLASS_AUDIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_uac3_config(struct usb_interface_descriptor *desc)
|
||||||
|
{
|
||||||
|
return desc->bInterfaceProtocol == UAC_VERSION_3;
|
||||||
|
}
|
||||||
|
|
||||||
int usb_choose_configuration(struct usb_device *udev)
|
int usb_choose_configuration(struct usb_device *udev)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -121,6 +132,22 @@ int usb_choose_configuration(struct usb_device *udev)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select first configuration as default for audio so that
|
||||||
|
* devices that don't comply with UAC3 protocol are supported.
|
||||||
|
* But, still iterate through other configurations and
|
||||||
|
* select UAC3 compliant config if present.
|
||||||
|
*/
|
||||||
|
if (i == 0 && num_configs > 1 && desc && is_audio(desc)) {
|
||||||
|
best = c;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i > 0 && desc && is_audio(desc) && is_uac3_config(desc)) {
|
||||||
|
best = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* From the remaining configs, choose the first one whose
|
/* From the remaining configs, choose the first one whose
|
||||||
* first interface is for a non-vendor-specific class.
|
* first interface is for a non-vendor-specific class.
|
||||||
* Reason: Linux is more likely to have a class driver
|
* Reason: Linux is more likely to have a class driver
|
||||||
|
|
|
@ -1738,7 +1738,6 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
|
||||||
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
|
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
|
||||||
struct usb_anchor *anchor = urb->anchor;
|
struct usb_anchor *anchor = urb->anchor;
|
||||||
int status = urb->unlinked;
|
int status = urb->unlinked;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
urb->hcpriv = NULL;
|
urb->hcpriv = NULL;
|
||||||
if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
|
if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
|
||||||
|
@ -1755,20 +1754,7 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
|
||||||
|
|
||||||
/* pass ownership to the completion handler */
|
/* pass ownership to the completion handler */
|
||||||
urb->status = status;
|
urb->status = status;
|
||||||
|
|
||||||
/*
|
|
||||||
* We disable local IRQs here avoid possible deadlock because
|
|
||||||
* drivers may call spin_lock() to hold lock which might be
|
|
||||||
* acquired in one hard interrupt handler.
|
|
||||||
*
|
|
||||||
* The local_irq_save()/local_irq_restore() around complete()
|
|
||||||
* will be removed if current USB drivers have been cleaned up
|
|
||||||
* and no one may trigger the above deadlock situation when
|
|
||||||
* running complete() in tasklet.
|
|
||||||
*/
|
|
||||||
local_irq_save(flags);
|
|
||||||
urb->complete(urb);
|
urb->complete(urb);
|
||||||
local_irq_restore(flags);
|
|
||||||
|
|
||||||
usb_anchor_resume_wakeups(anchor);
|
usb_anchor_resume_wakeups(anchor);
|
||||||
atomic_dec(&urb->use_count);
|
atomic_dec(&urb->use_count);
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <linux/pm_qos.h>
|
#include <linux/pm_qos.h>
|
||||||
|
#include <linux/kobject.h>
|
||||||
|
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
|
@ -2660,11 +2661,13 @@ static bool use_new_scheme(struct usb_device *udev, int retry,
|
||||||
{
|
{
|
||||||
int old_scheme_first_port =
|
int old_scheme_first_port =
|
||||||
port_dev->quirks & USB_PORT_QUIRK_OLD_SCHEME;
|
port_dev->quirks & USB_PORT_QUIRK_OLD_SCHEME;
|
||||||
|
int quick_enumeration = (udev->speed == USB_SPEED_HIGH);
|
||||||
|
|
||||||
if (udev->speed >= USB_SPEED_SUPER)
|
if (udev->speed >= USB_SPEED_SUPER)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return USE_NEW_SCHEME(retry, old_scheme_first_port || old_scheme_first);
|
return USE_NEW_SCHEME(retry, old_scheme_first_port || old_scheme_first
|
||||||
|
|| quick_enumeration);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is a USB 3.0 port in the Inactive or Compliance Mode state?
|
/* Is a USB 3.0 port in the Inactive or Compliance Mode state?
|
||||||
|
@ -5147,6 +5150,42 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||||
usb_lock_port(port_dev);
|
usb_lock_port(port_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle notifying userspace about hub over-current events */
|
||||||
|
static void port_over_current_notify(struct usb_port *port_dev)
|
||||||
|
{
|
||||||
|
static char *envp[] = { NULL, NULL, NULL };
|
||||||
|
struct device *hub_dev;
|
||||||
|
char *port_dev_path;
|
||||||
|
|
||||||
|
sysfs_notify(&port_dev->dev.kobj, NULL, "over_current_count");
|
||||||
|
|
||||||
|
hub_dev = port_dev->dev.parent;
|
||||||
|
|
||||||
|
if (!hub_dev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
port_dev_path = kobject_get_path(&port_dev->dev.kobj, GFP_KERNEL);
|
||||||
|
if (!port_dev_path)
|
||||||
|
return;
|
||||||
|
|
||||||
|
envp[0] = kasprintf(GFP_KERNEL, "OVER_CURRENT_PORT=%s", port_dev_path);
|
||||||
|
if (!envp[0])
|
||||||
|
goto exit_path;
|
||||||
|
|
||||||
|
envp[1] = kasprintf(GFP_KERNEL, "OVER_CURRENT_COUNT=%u",
|
||||||
|
port_dev->over_current_count);
|
||||||
|
if (!envp[1])
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
kobject_uevent_env(&hub_dev->kobj, KOBJ_CHANGE, envp);
|
||||||
|
|
||||||
|
kfree(envp[1]);
|
||||||
|
exit:
|
||||||
|
kfree(envp[0]);
|
||||||
|
exit_path:
|
||||||
|
kfree(port_dev_path);
|
||||||
|
}
|
||||||
|
|
||||||
static void port_event(struct usb_hub *hub, int port1)
|
static void port_event(struct usb_hub *hub, int port1)
|
||||||
__must_hold(&port_dev->status_lock)
|
__must_hold(&port_dev->status_lock)
|
||||||
{
|
{
|
||||||
|
@ -5189,6 +5228,7 @@ static void port_event(struct usb_hub *hub, int port1)
|
||||||
if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
|
if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
|
||||||
u16 status = 0, unused;
|
u16 status = 0, unused;
|
||||||
port_dev->over_current_count++;
|
port_dev->over_current_count++;
|
||||||
|
port_over_current_notify(port_dev);
|
||||||
|
|
||||||
dev_dbg(&port_dev->dev, "over-current change #%u\n",
|
dev_dbg(&port_dev->dev, "over-current change #%u\n",
|
||||||
port_dev->over_current_count);
|
port_dev->over_current_count);
|
||||||
|
|
|
@ -23,10 +23,11 @@ static int usb_phy_roothub_add_phy(struct device *dev, int index,
|
||||||
struct list_head *list)
|
struct list_head *list)
|
||||||
{
|
{
|
||||||
struct usb_phy_roothub *roothub_entry;
|
struct usb_phy_roothub *roothub_entry;
|
||||||
struct phy *phy = devm_of_phy_get_by_index(dev, dev->of_node, index);
|
struct phy *phy;
|
||||||
|
|
||||||
if (IS_ERR_OR_NULL(phy)) {
|
phy = devm_of_phy_get_by_index(dev, dev->of_node, index);
|
||||||
if (!phy || PTR_ERR(phy) == -ENODEV)
|
if (IS_ERR(phy)) {
|
||||||
|
if (PTR_ERR(phy) == -ENODEV)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return PTR_ERR(phy);
|
return PTR_ERR(phy);
|
||||||
|
|
|
@ -16,6 +16,15 @@ static int usb_port_block_power_off;
|
||||||
|
|
||||||
static const struct attribute_group *port_dev_group[];
|
static const struct attribute_group *port_dev_group[];
|
||||||
|
|
||||||
|
static ssize_t location_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct usb_port *port_dev = to_usb_port(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "0x%08x\n", port_dev->location);
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR_RO(location);
|
||||||
|
|
||||||
static ssize_t connect_type_show(struct device *dev,
|
static ssize_t connect_type_show(struct device *dev,
|
||||||
struct device_attribute *attr, char *buf)
|
struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
|
@ -140,6 +149,7 @@ static DEVICE_ATTR_RW(usb3_lpm_permit);
|
||||||
|
|
||||||
static struct attribute *port_dev_attrs[] = {
|
static struct attribute *port_dev_attrs[] = {
|
||||||
&dev_attr_connect_type.attr,
|
&dev_attr_connect_type.attr,
|
||||||
|
&dev_attr_location.attr,
|
||||||
&dev_attr_quirks.attr,
|
&dev_attr_quirks.attr,
|
||||||
&dev_attr_over_current_count.attr,
|
&dev_attr_over_current_count.attr,
|
||||||
NULL,
|
NULL,
|
||||||
|
|
|
@ -393,6 +393,20 @@ enum dwc2_ep0_state {
|
||||||
* 0 - No
|
* 0 - No
|
||||||
* 1 - Yes
|
* 1 - Yes
|
||||||
* @hird_threshold: Value of BESL or HIRD Threshold.
|
* @hird_threshold: Value of BESL or HIRD Threshold.
|
||||||
|
* @ref_clk_per: Indicates in terms of pico seconds the period
|
||||||
|
* of ref_clk.
|
||||||
|
* 62500 - 16MHz
|
||||||
|
* 58823 - 17MHz
|
||||||
|
* 52083 - 19.2MHz
|
||||||
|
* 50000 - 20MHz
|
||||||
|
* 41666 - 24MHz
|
||||||
|
* 33333 - 30MHz (default)
|
||||||
|
* 25000 - 40MHz
|
||||||
|
* @sof_cnt_wkup_alert: Indicates in term of number of SOF's after which
|
||||||
|
* the controller should generate an interrupt if the
|
||||||
|
* device had been in L1 state until that period.
|
||||||
|
* This is used by SW to initiate Remote WakeUp in the
|
||||||
|
* controller so as to sync to the uF number from the host.
|
||||||
* @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO
|
* @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO
|
||||||
* register.
|
* register.
|
||||||
* 0 - Deactivate the transceiver (default)
|
* 0 - Deactivate the transceiver (default)
|
||||||
|
@ -416,6 +430,9 @@ enum dwc2_ep0_state {
|
||||||
* back to DWC2_SPEED_PARAM_HIGH while device is gone.
|
* back to DWC2_SPEED_PARAM_HIGH while device is gone.
|
||||||
* 0 - No (default)
|
* 0 - No (default)
|
||||||
* 1 - Yes
|
* 1 - Yes
|
||||||
|
* @service_interval: Enable service interval based scheduling.
|
||||||
|
* 0 - No
|
||||||
|
* 1 - Yes
|
||||||
*
|
*
|
||||||
* The following parameters may be specified when starting the module. These
|
* The following parameters may be specified when starting the module. These
|
||||||
* parameters define how the DWC_otg controller should be configured. A
|
* parameters define how the DWC_otg controller should be configured. A
|
||||||
|
@ -461,6 +478,7 @@ struct dwc2_core_params {
|
||||||
bool lpm_clock_gating;
|
bool lpm_clock_gating;
|
||||||
bool besl;
|
bool besl;
|
||||||
bool hird_threshold_en;
|
bool hird_threshold_en;
|
||||||
|
bool service_interval;
|
||||||
u8 hird_threshold;
|
u8 hird_threshold;
|
||||||
bool activate_stm_fs_transceiver;
|
bool activate_stm_fs_transceiver;
|
||||||
bool ipg_isoc_en;
|
bool ipg_isoc_en;
|
||||||
|
@ -468,6 +486,10 @@ struct dwc2_core_params {
|
||||||
u32 max_transfer_size;
|
u32 max_transfer_size;
|
||||||
u32 ahbcfg;
|
u32 ahbcfg;
|
||||||
|
|
||||||
|
/* GREFCLK parameters */
|
||||||
|
u32 ref_clk_per;
|
||||||
|
u16 sof_cnt_wkup_alert;
|
||||||
|
|
||||||
/* Host parameters */
|
/* Host parameters */
|
||||||
bool host_dma;
|
bool host_dma;
|
||||||
bool dma_desc_enable;
|
bool dma_desc_enable;
|
||||||
|
@ -605,6 +627,10 @@ struct dwc2_core_params {
|
||||||
* FIFO sizing is enabled 16 to 32768
|
* FIFO sizing is enabled 16 to 32768
|
||||||
* Actual maximum value is autodetected and also
|
* Actual maximum value is autodetected and also
|
||||||
* the default.
|
* the default.
|
||||||
|
* @service_interval_mode: For enabling service interval based scheduling in the
|
||||||
|
* controller.
|
||||||
|
* 0 - Disable
|
||||||
|
* 1 - Enable
|
||||||
*/
|
*/
|
||||||
struct dwc2_hw_params {
|
struct dwc2_hw_params {
|
||||||
unsigned op_mode:3;
|
unsigned op_mode:3;
|
||||||
|
@ -635,6 +661,7 @@ struct dwc2_hw_params {
|
||||||
unsigned utmi_phy_data_width:2;
|
unsigned utmi_phy_data_width:2;
|
||||||
unsigned lpm_mode:1;
|
unsigned lpm_mode:1;
|
||||||
unsigned ipg_isoc_en:1;
|
unsigned ipg_isoc_en:1;
|
||||||
|
unsigned service_interval_mode:1;
|
||||||
u32 snpsid;
|
u32 snpsid;
|
||||||
u32 dev_ep_dirs;
|
u32 dev_ep_dirs;
|
||||||
u32 g_tx_fifo_size[MAX_EPS_CHANNELS];
|
u32 g_tx_fifo_size[MAX_EPS_CHANNELS];
|
||||||
|
@ -1354,6 +1381,7 @@ int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg);
|
||||||
int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);
|
int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);
|
||||||
int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
|
int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
|
||||||
void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg);
|
void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg);
|
||||||
|
void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg);
|
||||||
#else
|
#else
|
||||||
static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2)
|
static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2)
|
||||||
{ return 0; }
|
{ return 0; }
|
||||||
|
@ -1388,6 +1416,7 @@ static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg)
|
||||||
static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg)
|
static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg)
|
||||||
{ return 0; }
|
{ return 0; }
|
||||||
static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {}
|
static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {}
|
||||||
|
static inline void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
|
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
|
||||||
|
|
|
@ -701,6 +701,7 @@ static int params_show(struct seq_file *seq, void *v)
|
||||||
print_param(seq, p, besl);
|
print_param(seq, p, besl);
|
||||||
print_param(seq, p, hird_threshold_en);
|
print_param(seq, p, hird_threshold_en);
|
||||||
print_param(seq, p, hird_threshold);
|
print_param(seq, p, hird_threshold);
|
||||||
|
print_param(seq, p, service_interval);
|
||||||
print_param(seq, p, host_dma);
|
print_param(seq, p, host_dma);
|
||||||
print_param(seq, p, g_dma);
|
print_param(seq, p, g_dma);
|
||||||
print_param(seq, p, g_dma_desc);
|
print_param(seq, p, g_dma_desc);
|
||||||
|
|
|
@ -122,6 +122,24 @@ static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dwc2_gadget_dec_frame_num_by_one - Decrements the targeted frame number
|
||||||
|
* by one.
|
||||||
|
* @hs_ep: The endpoint.
|
||||||
|
*
|
||||||
|
* This function used in service interval based scheduling flow to calculate
|
||||||
|
* descriptor frame number filed value. For service interval mode frame
|
||||||
|
* number in descriptor should point to last (u)frame in the interval.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static inline void dwc2_gadget_dec_frame_num_by_one(struct dwc2_hsotg_ep *hs_ep)
|
||||||
|
{
|
||||||
|
if (hs_ep->target_frame)
|
||||||
|
hs_ep->target_frame -= 1;
|
||||||
|
else
|
||||||
|
hs_ep->target_frame = DSTS_SOFFN_LIMIT;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dwc2_hsotg_en_gsint - enable one or more of the general interrupt
|
* dwc2_hsotg_en_gsint - enable one or more of the general interrupt
|
||||||
* @hsotg: The device state
|
* @hsotg: The device state
|
||||||
|
@ -227,6 +245,27 @@ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg)
|
||||||
return tx_addr_max - addr;
|
return tx_addr_max - addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dwc2_gadget_wkup_alert_handler - Handler for WKUP_ALERT interrupt
|
||||||
|
*
|
||||||
|
* @hsotg: Programming view of the DWC_otg controller
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg)
|
||||||
|
{
|
||||||
|
u32 gintsts2;
|
||||||
|
u32 gintmsk2;
|
||||||
|
|
||||||
|
gintsts2 = dwc2_readl(hsotg, GINTSTS2);
|
||||||
|
gintmsk2 = dwc2_readl(hsotg, GINTMSK2);
|
||||||
|
|
||||||
|
if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) {
|
||||||
|
dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__);
|
||||||
|
dwc2_clear_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT);
|
||||||
|
dwc2_set_bit(hsotg, DCFG, DCTL_RMTWKUPSIG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode
|
* dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode
|
||||||
* TX FIFOs
|
* TX FIFOs
|
||||||
|
@ -2812,6 +2851,23 @@ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep)
|
||||||
if (using_desc_dma(hsotg)) {
|
if (using_desc_dma(hsotg)) {
|
||||||
hs_ep->target_frame = hsotg->frame_number;
|
hs_ep->target_frame = hsotg->frame_number;
|
||||||
dwc2_gadget_incr_frame_num(hs_ep);
|
dwc2_gadget_incr_frame_num(hs_ep);
|
||||||
|
|
||||||
|
/* In service interval mode target_frame must
|
||||||
|
* be set to last (u)frame of the service interval.
|
||||||
|
*/
|
||||||
|
if (hsotg->params.service_interval) {
|
||||||
|
/* Set target_frame to the first (u)frame of
|
||||||
|
* the service interval
|
||||||
|
*/
|
||||||
|
hs_ep->target_frame &= ~hs_ep->interval + 1;
|
||||||
|
|
||||||
|
/* Set target_frame to the last (u)frame of
|
||||||
|
* the service interval
|
||||||
|
*/
|
||||||
|
dwc2_gadget_incr_frame_num(hs_ep);
|
||||||
|
dwc2_gadget_dec_frame_num_by_one(hs_ep);
|
||||||
|
}
|
||||||
|
|
||||||
dwc2_gadget_start_isoc_ddma(hs_ep);
|
dwc2_gadget_start_isoc_ddma(hs_ep);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3109,6 +3165,8 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg,
|
||||||
dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index);
|
dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dwc2_hsotg_ep_disable(struct usb_ep *ep);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dwc2_hsotg_disconnect - disconnect service
|
* dwc2_hsotg_disconnect - disconnect service
|
||||||
* @hsotg: The device state.
|
* @hsotg: The device state.
|
||||||
|
@ -3127,13 +3185,12 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg)
|
||||||
hsotg->connected = 0;
|
hsotg->connected = 0;
|
||||||
hsotg->test_mode = 0;
|
hsotg->test_mode = 0;
|
||||||
|
|
||||||
|
/* all endpoints should be shutdown */
|
||||||
for (ep = 0; ep < hsotg->num_of_eps; ep++) {
|
for (ep = 0; ep < hsotg->num_of_eps; ep++) {
|
||||||
if (hsotg->eps_in[ep])
|
if (hsotg->eps_in[ep])
|
||||||
kill_all_requests(hsotg, hsotg->eps_in[ep],
|
dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
|
||||||
-ESHUTDOWN);
|
|
||||||
if (hsotg->eps_out[ep])
|
if (hsotg->eps_out[ep])
|
||||||
kill_all_requests(hsotg, hsotg->eps_out[ep],
|
dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
|
||||||
-ESHUTDOWN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
call_gadget(hsotg, disconnect);
|
call_gadget(hsotg, disconnect);
|
||||||
|
@ -3191,13 +3248,23 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
|
||||||
u32 val;
|
u32 val;
|
||||||
u32 usbcfg;
|
u32 usbcfg;
|
||||||
u32 dcfg = 0;
|
u32 dcfg = 0;
|
||||||
|
int ep;
|
||||||
|
|
||||||
/* Kill any ep0 requests as controller will be reinitialized */
|
/* Kill any ep0 requests as controller will be reinitialized */
|
||||||
kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET);
|
kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET);
|
||||||
|
|
||||||
if (!is_usb_reset)
|
if (!is_usb_reset) {
|
||||||
if (dwc2_core_reset(hsotg, true))
|
if (dwc2_core_reset(hsotg, true))
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
/* all endpoints should be shutdown */
|
||||||
|
for (ep = 1; ep < hsotg->num_of_eps; ep++) {
|
||||||
|
if (hsotg->eps_in[ep])
|
||||||
|
dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
|
||||||
|
if (hsotg->eps_out[ep])
|
||||||
|
dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we must now enable ep0 ready for host detection and then
|
* we must now enable ep0 ready for host detection and then
|
||||||
|
@ -3312,6 +3379,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
|
||||||
dwc2_set_bit(hsotg, DIEPMSK, DIEPMSK_BNAININTRMSK);
|
dwc2_set_bit(hsotg, DIEPMSK, DIEPMSK_BNAININTRMSK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enable Service Interval mode if supported */
|
||||||
|
if (using_desc_dma(hsotg) && hsotg->params.service_interval)
|
||||||
|
dwc2_set_bit(hsotg, DCTL, DCTL_SERVICE_INTERVAL_SUPPORTED);
|
||||||
|
|
||||||
dwc2_writel(hsotg, 0, DAINTMSK);
|
dwc2_writel(hsotg, 0, DAINTMSK);
|
||||||
|
|
||||||
dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
|
dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
|
||||||
|
@ -3368,6 +3439,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
|
||||||
/* configure the core to support LPM */
|
/* configure the core to support LPM */
|
||||||
dwc2_gadget_init_lpm(hsotg);
|
dwc2_gadget_init_lpm(hsotg);
|
||||||
|
|
||||||
|
/* program GREFCLK register if needed */
|
||||||
|
if (using_desc_dma(hsotg) && hsotg->params.service_interval)
|
||||||
|
dwc2_gadget_program_ref_clk(hsotg);
|
||||||
|
|
||||||
/* must be at-least 3ms to allow bus to see disconnect */
|
/* must be at-least 3ms to allow bus to see disconnect */
|
||||||
mdelay(3);
|
mdelay(3);
|
||||||
|
|
||||||
|
@ -3676,6 +3751,10 @@ irq_retry:
|
||||||
if (gintsts & IRQ_RETRY_MASK && --retry_count > 0)
|
if (gintsts & IRQ_RETRY_MASK && --retry_count > 0)
|
||||||
goto irq_retry;
|
goto irq_retry;
|
||||||
|
|
||||||
|
/* Check WKUP_ALERT interrupt*/
|
||||||
|
if (hsotg->params.service_interval)
|
||||||
|
dwc2_gadget_wkup_alert_handler(hsotg);
|
||||||
|
|
||||||
spin_unlock(&hsotg->lock);
|
spin_unlock(&hsotg->lock);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
@ -3993,6 +4072,7 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u32 epctrl_reg;
|
u32 epctrl_reg;
|
||||||
u32 ctrl;
|
u32 ctrl;
|
||||||
|
int locked;
|
||||||
|
|
||||||
dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep);
|
dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep);
|
||||||
|
|
||||||
|
@ -4008,6 +4088,8 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
|
||||||
|
|
||||||
epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
|
epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
|
||||||
|
|
||||||
|
locked = spin_is_locked(&hsotg->lock);
|
||||||
|
if (!locked)
|
||||||
spin_lock_irqsave(&hsotg->lock, flags);
|
spin_lock_irqsave(&hsotg->lock, flags);
|
||||||
|
|
||||||
ctrl = dwc2_readl(hsotg, epctrl_reg);
|
ctrl = dwc2_readl(hsotg, epctrl_reg);
|
||||||
|
@ -4032,7 +4114,9 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
|
||||||
hs_ep->fifo_index = 0;
|
hs_ep->fifo_index = 0;
|
||||||
hs_ep->fifo_size = 0;
|
hs_ep->fifo_size = 0;
|
||||||
|
|
||||||
|
if (!locked)
|
||||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4944,6 +5028,29 @@ void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg)
|
||||||
val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0;
|
val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0;
|
||||||
dwc2_writel(hsotg, val, GLPMCFG);
|
dwc2_writel(hsotg, val, GLPMCFG);
|
||||||
dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG));
|
dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG));
|
||||||
|
|
||||||
|
/* Unmask WKUP_ALERT Interrupt */
|
||||||
|
if (hsotg->params.service_interval)
|
||||||
|
dwc2_set_bit(hsotg, GINTMSK2, GINTMSK2_WKUP_ALERT_INT_MSK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dwc2_gadget_program_ref_clk - Program GREFCLK register in device mode
|
||||||
|
*
|
||||||
|
* @hsotg: Programming view of DWC_otg controller
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg)
|
||||||
|
{
|
||||||
|
u32 val = 0;
|
||||||
|
|
||||||
|
val |= GREFCLK_REF_CLK_MODE;
|
||||||
|
val |= hsotg->params.ref_clk_per << GREFCLK_REFCLKPER_SHIFT;
|
||||||
|
val |= hsotg->params.sof_cnt_wkup_alert <<
|
||||||
|
GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT;
|
||||||
|
|
||||||
|
dwc2_writel(hsotg, val, GREFCLK);
|
||||||
|
dev_dbg(hsotg->dev, "GREFCLK=0x%08x\n", dwc2_readl(hsotg, GREFCLK));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -358,16 +358,10 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
|
||||||
|
|
||||||
static int dwc2_vbus_supply_init(struct dwc2_hsotg *hsotg)
|
static int dwc2_vbus_supply_init(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
int ret;
|
if (hsotg->vbus_supply)
|
||||||
|
|
||||||
hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus");
|
|
||||||
if (IS_ERR(hsotg->vbus_supply)) {
|
|
||||||
ret = PTR_ERR(hsotg->vbus_supply);
|
|
||||||
hsotg->vbus_supply = NULL;
|
|
||||||
return ret == -ENODEV ? 0 : ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return regulator_enable(hsotg->vbus_supply);
|
return regulator_enable(hsotg->vbus_supply);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dwc2_vbus_supply_exit(struct dwc2_hsotg *hsotg)
|
static int dwc2_vbus_supply_exit(struct dwc2_hsotg *hsotg)
|
||||||
|
@ -1328,14 +1322,11 @@ static void dwc2_hc_write_packet(struct dwc2_hsotg *hsotg,
|
||||||
u32 remaining_count;
|
u32 remaining_count;
|
||||||
u32 byte_count;
|
u32 byte_count;
|
||||||
u32 dword_count;
|
u32 dword_count;
|
||||||
u32 __iomem *data_fifo;
|
|
||||||
u32 *data_buf = (u32 *)chan->xfer_buf;
|
u32 *data_buf = (u32 *)chan->xfer_buf;
|
||||||
|
|
||||||
if (dbg_hc(chan))
|
if (dbg_hc(chan))
|
||||||
dev_vdbg(hsotg->dev, "%s()\n", __func__);
|
dev_vdbg(hsotg->dev, "%s()\n", __func__);
|
||||||
|
|
||||||
data_fifo = (u32 __iomem *)(hsotg->regs + HCFIFO(chan->hc_num));
|
|
||||||
|
|
||||||
remaining_count = chan->xfer_len - chan->xfer_count;
|
remaining_count = chan->xfer_len - chan->xfer_count;
|
||||||
if (remaining_count > chan->max_packet)
|
if (remaining_count > chan->max_packet)
|
||||||
byte_count = chan->max_packet;
|
byte_count = chan->max_packet;
|
||||||
|
@ -3564,6 +3555,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
||||||
u32 port_status;
|
u32 port_status;
|
||||||
u32 speed;
|
u32 speed;
|
||||||
u32 pcgctl;
|
u32 pcgctl;
|
||||||
|
u32 pwr;
|
||||||
|
|
||||||
switch (typereq) {
|
switch (typereq) {
|
||||||
case ClearHubFeature:
|
case ClearHubFeature:
|
||||||
|
@ -3612,8 +3604,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
||||||
dev_dbg(hsotg->dev,
|
dev_dbg(hsotg->dev,
|
||||||
"ClearPortFeature USB_PORT_FEAT_POWER\n");
|
"ClearPortFeature USB_PORT_FEAT_POWER\n");
|
||||||
hprt0 = dwc2_read_hprt0(hsotg);
|
hprt0 = dwc2_read_hprt0(hsotg);
|
||||||
|
pwr = hprt0 & HPRT0_PWR;
|
||||||
hprt0 &= ~HPRT0_PWR;
|
hprt0 &= ~HPRT0_PWR;
|
||||||
dwc2_writel(hsotg, hprt0, HPRT0);
|
dwc2_writel(hsotg, hprt0, HPRT0);
|
||||||
|
if (pwr)
|
||||||
|
dwc2_vbus_supply_exit(hsotg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_PORT_FEAT_INDICATOR:
|
case USB_PORT_FEAT_INDICATOR:
|
||||||
|
@ -3823,8 +3818,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
||||||
dev_dbg(hsotg->dev,
|
dev_dbg(hsotg->dev,
|
||||||
"SetPortFeature - USB_PORT_FEAT_POWER\n");
|
"SetPortFeature - USB_PORT_FEAT_POWER\n");
|
||||||
hprt0 = dwc2_read_hprt0(hsotg);
|
hprt0 = dwc2_read_hprt0(hsotg);
|
||||||
|
pwr = hprt0 & HPRT0_PWR;
|
||||||
hprt0 |= HPRT0_PWR;
|
hprt0 |= HPRT0_PWR;
|
||||||
dwc2_writel(hsotg, hprt0, HPRT0);
|
dwc2_writel(hsotg, hprt0, HPRT0);
|
||||||
|
if (!pwr)
|
||||||
|
dwc2_vbus_supply_init(hsotg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_PORT_FEAT_RESET:
|
case USB_PORT_FEAT_RESET:
|
||||||
|
@ -3841,6 +3839,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
||||||
dwc2_writel(hsotg, 0, PCGCTL);
|
dwc2_writel(hsotg, 0, PCGCTL);
|
||||||
|
|
||||||
hprt0 = dwc2_read_hprt0(hsotg);
|
hprt0 = dwc2_read_hprt0(hsotg);
|
||||||
|
pwr = hprt0 & HPRT0_PWR;
|
||||||
/* Clear suspend bit if resetting from suspend state */
|
/* Clear suspend bit if resetting from suspend state */
|
||||||
hprt0 &= ~HPRT0_SUSP;
|
hprt0 &= ~HPRT0_SUSP;
|
||||||
|
|
||||||
|
@ -3854,6 +3853,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
||||||
dev_dbg(hsotg->dev,
|
dev_dbg(hsotg->dev,
|
||||||
"In host mode, hprt0=%08x\n", hprt0);
|
"In host mode, hprt0=%08x\n", hprt0);
|
||||||
dwc2_writel(hsotg, hprt0, HPRT0);
|
dwc2_writel(hsotg, hprt0, HPRT0);
|
||||||
|
if (!pwr)
|
||||||
|
dwc2_vbus_supply_init(hsotg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
|
/* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
|
||||||
|
@ -4393,6 +4394,8 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
|
||||||
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
|
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
|
||||||
struct usb_bus *bus = hcd_to_bus(hcd);
|
struct usb_bus *bus = hcd_to_bus(hcd);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
u32 hprt0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
dev_dbg(hsotg->dev, "DWC OTG HCD START\n");
|
dev_dbg(hsotg->dev, "DWC OTG HCD START\n");
|
||||||
|
|
||||||
|
@ -4408,6 +4411,17 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
|
||||||
|
|
||||||
dwc2_hcd_reinit(hsotg);
|
dwc2_hcd_reinit(hsotg);
|
||||||
|
|
||||||
|
hprt0 = dwc2_read_hprt0(hsotg);
|
||||||
|
/* Has vbus power been turned on in dwc2_core_host_init ? */
|
||||||
|
if (hprt0 & HPRT0_PWR) {
|
||||||
|
/* Enable external vbus supply before resuming root hub */
|
||||||
|
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||||
|
ret = dwc2_vbus_supply_init(hsotg);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
spin_lock_irqsave(&hsotg->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize and connect root hub if one is not already attached */
|
/* Initialize and connect root hub if one is not already attached */
|
||||||
if (bus->root_hub) {
|
if (bus->root_hub) {
|
||||||
dev_dbg(hsotg->dev, "DWC OTG HCD Has Root Hub\n");
|
dev_dbg(hsotg->dev, "DWC OTG HCD Has Root Hub\n");
|
||||||
|
@ -4417,7 +4431,7 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
|
||||||
|
|
||||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||||
|
|
||||||
return dwc2_vbus_supply_init(hsotg);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4428,6 +4442,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
|
||||||
{
|
{
|
||||||
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
|
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
u32 hprt0;
|
||||||
|
|
||||||
/* Turn off all host-specific interrupts */
|
/* Turn off all host-specific interrupts */
|
||||||
dwc2_disable_host_interrupts(hsotg);
|
dwc2_disable_host_interrupts(hsotg);
|
||||||
|
@ -4436,6 +4451,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
|
||||||
synchronize_irq(hcd->irq);
|
synchronize_irq(hcd->irq);
|
||||||
|
|
||||||
spin_lock_irqsave(&hsotg->lock, flags);
|
spin_lock_irqsave(&hsotg->lock, flags);
|
||||||
|
hprt0 = dwc2_read_hprt0(hsotg);
|
||||||
/* Ensure hcd is disconnected */
|
/* Ensure hcd is disconnected */
|
||||||
dwc2_hcd_disconnect(hsotg, true);
|
dwc2_hcd_disconnect(hsotg, true);
|
||||||
dwc2_hcd_stop(hsotg);
|
dwc2_hcd_stop(hsotg);
|
||||||
|
@ -4444,6 +4460,8 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
|
||||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||||
|
|
||||||
|
/* keep balanced supply init/exit by checking HPRT0_PWR */
|
||||||
|
if (hprt0 & HPRT0_PWR)
|
||||||
dwc2_vbus_supply_exit(hsotg);
|
dwc2_vbus_supply_exit(hsotg);
|
||||||
|
|
||||||
usleep_range(1000, 3000);
|
usleep_range(1000, 3000);
|
||||||
|
@ -4482,7 +4500,9 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
|
||||||
hprt0 |= HPRT0_SUSP;
|
hprt0 |= HPRT0_SUSP;
|
||||||
hprt0 &= ~HPRT0_PWR;
|
hprt0 &= ~HPRT0_PWR;
|
||||||
dwc2_writel(hsotg, hprt0, HPRT0);
|
dwc2_writel(hsotg, hprt0, HPRT0);
|
||||||
|
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||||
dwc2_vbus_supply_exit(hsotg);
|
dwc2_vbus_supply_exit(hsotg);
|
||||||
|
spin_lock_irqsave(&hsotg->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enter partial_power_down */
|
/* Enter partial_power_down */
|
||||||
|
|
|
@ -312,6 +312,7 @@
|
||||||
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14
|
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14
|
||||||
#define GHWCFG4_ACG_SUPPORTED BIT(12)
|
#define GHWCFG4_ACG_SUPPORTED BIT(12)
|
||||||
#define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11)
|
#define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11)
|
||||||
|
#define GHWCFG4_SERVICE_INTERVAL_SUPPORTED BIT(10)
|
||||||
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0
|
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0
|
||||||
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1
|
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1
|
||||||
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2
|
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2
|
||||||
|
@ -404,6 +405,19 @@
|
||||||
#define ADPCTL_PRB_DSCHRG_MASK (0x3 << 0)
|
#define ADPCTL_PRB_DSCHRG_MASK (0x3 << 0)
|
||||||
#define ADPCTL_PRB_DSCHRG_SHIFT 0
|
#define ADPCTL_PRB_DSCHRG_SHIFT 0
|
||||||
|
|
||||||
|
#define GREFCLK HSOTG_REG(0x0064)
|
||||||
|
#define GREFCLK_REFCLKPER_MASK (0x1ffff << 15)
|
||||||
|
#define GREFCLK_REFCLKPER_SHIFT 15
|
||||||
|
#define GREFCLK_REF_CLK_MODE BIT(14)
|
||||||
|
#define GREFCLK_SOF_CNT_WKUP_ALERT_MASK (0x3ff)
|
||||||
|
#define GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT 0
|
||||||
|
|
||||||
|
#define GINTMSK2 HSOTG_REG(0x0068)
|
||||||
|
#define GINTMSK2_WKUP_ALERT_INT_MSK BIT(0)
|
||||||
|
|
||||||
|
#define GINTSTS2 HSOTG_REG(0x006c)
|
||||||
|
#define GINTSTS2_WKUP_ALERT_INT BIT(0)
|
||||||
|
|
||||||
#define HPTXFSIZ HSOTG_REG(0x100)
|
#define HPTXFSIZ HSOTG_REG(0x100)
|
||||||
/* Use FIFOSIZE_* constants to access this register */
|
/* Use FIFOSIZE_* constants to access this register */
|
||||||
|
|
||||||
|
@ -443,6 +457,7 @@
|
||||||
#define DCFG_DEVSPD_FS48 3
|
#define DCFG_DEVSPD_FS48 3
|
||||||
|
|
||||||
#define DCTL HSOTG_REG(0x804)
|
#define DCTL HSOTG_REG(0x804)
|
||||||
|
#define DCTL_SERVICE_INTERVAL_SUPPORTED BIT(19)
|
||||||
#define DCTL_PWRONPRGDONE BIT(11)
|
#define DCTL_PWRONPRGDONE BIT(11)
|
||||||
#define DCTL_CGOUTNAK BIT(10)
|
#define DCTL_CGOUTNAK BIT(10)
|
||||||
#define DCTL_SGOUTNAK BIT(9)
|
#define DCTL_SGOUTNAK BIT(9)
|
||||||
|
|
|
@ -81,6 +81,7 @@ static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
|
||||||
p->host_perio_tx_fifo_size = 256;
|
p->host_perio_tx_fifo_size = 256;
|
||||||
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
|
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
|
||||||
GAHBCFG_HBSTLEN_SHIFT;
|
GAHBCFG_HBSTLEN_SHIFT;
|
||||||
|
p->power_down = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg)
|
static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg)
|
||||||
|
@ -299,9 +300,12 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg)
|
||||||
p->hird_threshold_en = true;
|
p->hird_threshold_en = true;
|
||||||
p->hird_threshold = 4;
|
p->hird_threshold = 4;
|
||||||
p->ipg_isoc_en = false;
|
p->ipg_isoc_en = false;
|
||||||
|
p->service_interval = false;
|
||||||
p->max_packet_count = hw->max_packet_count;
|
p->max_packet_count = hw->max_packet_count;
|
||||||
p->max_transfer_size = hw->max_transfer_size;
|
p->max_transfer_size = hw->max_transfer_size;
|
||||||
p->ahbcfg = GAHBCFG_HBSTLEN_INCR << GAHBCFG_HBSTLEN_SHIFT;
|
p->ahbcfg = GAHBCFG_HBSTLEN_INCR << GAHBCFG_HBSTLEN_SHIFT;
|
||||||
|
p->ref_clk_per = 33333;
|
||||||
|
p->sof_cnt_wkup_alert = 100;
|
||||||
|
|
||||||
if ((hsotg->dr_mode == USB_DR_MODE_HOST) ||
|
if ((hsotg->dr_mode == USB_DR_MODE_HOST) ||
|
||||||
(hsotg->dr_mode == USB_DR_MODE_OTG)) {
|
(hsotg->dr_mode == USB_DR_MODE_OTG)) {
|
||||||
|
@ -592,6 +596,7 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg)
|
||||||
CHECK_BOOL(besl, (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a));
|
CHECK_BOOL(besl, (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a));
|
||||||
CHECK_BOOL(hird_threshold_en, hsotg->params.lpm);
|
CHECK_BOOL(hird_threshold_en, hsotg->params.lpm);
|
||||||
CHECK_RANGE(hird_threshold, 0, hsotg->params.besl ? 12 : 7, 0);
|
CHECK_RANGE(hird_threshold, 0, hsotg->params.besl ? 12 : 7, 0);
|
||||||
|
CHECK_BOOL(service_interval, hw->service_interval_mode);
|
||||||
CHECK_RANGE(max_packet_count,
|
CHECK_RANGE(max_packet_count,
|
||||||
15, hw->max_packet_count,
|
15, hw->max_packet_count,
|
||||||
hw->max_packet_count);
|
hw->max_packet_count);
|
||||||
|
@ -780,6 +785,8 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
|
||||||
GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT;
|
GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT;
|
||||||
hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED);
|
hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED);
|
||||||
hw->ipg_isoc_en = !!(hwcfg4 & GHWCFG4_IPG_ISOC_SUPPORTED);
|
hw->ipg_isoc_en = !!(hwcfg4 & GHWCFG4_IPG_ISOC_SUPPORTED);
|
||||||
|
hw->service_interval_mode = !!(hwcfg4 &
|
||||||
|
GHWCFG4_SERVICE_INTERVAL_SUPPORTED);
|
||||||
|
|
||||||
/* fifo sizes */
|
/* fifo sizes */
|
||||||
hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>
|
hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>
|
||||||
|
|
|
@ -432,6 +432,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus");
|
||||||
|
if (IS_ERR(hsotg->vbus_supply)) {
|
||||||
|
retval = PTR_ERR(hsotg->vbus_supply);
|
||||||
|
hsotg->vbus_supply = NULL;
|
||||||
|
if (retval != -ENODEV)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
retval = dwc2_lowlevel_hw_enable(hsotg);
|
retval = dwc2_lowlevel_hw_enable(hsotg);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
@ -113,7 +113,7 @@ config USB_DWC3_ST
|
||||||
|
|
||||||
config USB_DWC3_QCOM
|
config USB_DWC3_QCOM
|
||||||
tristate "Qualcomm Platform"
|
tristate "Qualcomm Platform"
|
||||||
depends on ARCH_QCOM || COMPILE_TEST
|
depends on EXTCON && (ARCH_QCOM || COMPILE_TEST)
|
||||||
depends on OF
|
depends on OF
|
||||||
default USB_DWC3
|
default USB_DWC3
|
||||||
help
|
help
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue