Merge tag 'usb-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB / PHY updates from Greg KH: "Here are the big set of USB and PHY driver patches for 5.7-rc1. Nothing huge here, some new PHY drivers, loads of USB gadget fixes and updates, xhci updates, usb-serial driver updates and new device ids, and other minor things. Full details in the shortlog. All have been in linux-next for a while with no reported issues" * tag 'usb-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (239 commits) USB: cdc-acm: restore capability check order usb: cdns3: make signed 1 bit bitfields unsigned usb: gadget: fsl: remove unused variable 'driver_desc' usb: gadget: f_fs: Fix use after free issue as part of queue failure usb: typec: Correct the documentation for typec_cable_put() USB: serial: io_edgeport: fix slab-out-of-bounds read in edge_interrupt_callback USB: serial: option: add Wistron Neweb D19Q1 USB: serial: option: add BroadMobi BM806U USB: serial: option: add support for ASKEY WWHC050 usb: core: Add ACPI support for USB interface devices driver core: platform: Reimplement devm_platform_ioremap_resource usb: dwc2: convert to devm_platform_get_and_ioremap_resource usb: host: hisilicon: convert to devm_platform_get_and_ioremap_resource usb: host: xhci-plat: convert to devm_platform_get_and_ioremap_resource drivers: provide devm_platform_get_and_ioremap_resource() phy: qcom-qusb2: Add new overriding tuning parameters in QUSB2 V2 PHY phy: qcom-qusb2: Add support for overriding tuning parameters in QUSB2 V2 PHY dt-bindings: phy: qcom-qusb2: Add support for overriding Phy tuning parameters phy: qcom-qusb2: Add generic QUSB2 V2 PHY support dt-bindings: phy: qcom,qusb2: Add compatibles for QUSB2 V2 phy and SC7180 ...
This commit is contained in:
@@ -20,13 +20,13 @@ Date: April 2017
|
|||||||
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
Description:
|
Description:
|
||||||
The supported power roles. This attribute can be used to request
|
The supported power roles. This attribute can be used to request
|
||||||
power role swap on the port when the port supports USB Power
|
power role swap on the port. Swapping is supported as
|
||||||
Delivery. Swapping is supported as synchronous operation, so
|
synchronous operation, so write(2) to the attribute will not
|
||||||
write(2) to the attribute will not return until the operation
|
return until the operation has finished. The attribute is
|
||||||
has finished. The attribute is notified about role changes so
|
notified about role changes so that poll(2) on the attribute
|
||||||
that poll(2) on the attribute wakes up. Change on the role will
|
wakes up. Change on the role will also generate uevent
|
||||||
also generate uevent KOBJ_CHANGE. The current role is show in
|
KOBJ_CHANGE. The current role is show in brackets, for example
|
||||||
brackets, for example "[source] sink" when in source mode.
|
"[source] sink" when in source mode.
|
||||||
|
|
||||||
Valid values: source, sink
|
Valid values: source, sink
|
||||||
|
|
||||||
@@ -108,6 +108,15 @@ Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
|||||||
Description:
|
Description:
|
||||||
Revision number of the supported USB Type-C specification.
|
Revision number of the supported USB Type-C specification.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>/orientation
|
||||||
|
Date: February 2020
|
||||||
|
Contact: Badhri Jagan Sridharan <badhri@google.com>
|
||||||
|
Description:
|
||||||
|
Indicates the active orientation of the Type-C connector.
|
||||||
|
Valid values:
|
||||||
|
- "normal": CC1 orientation
|
||||||
|
- "reverse": CC2 orientation
|
||||||
|
- "unknown": Orientation cannot be determined.
|
||||||
|
|
||||||
USB Type-C partner devices (eg. /sys/class/typec/port0-partner/)
|
USB Type-C partner devices (eg. /sys/class/typec/port0-partner/)
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ properties:
|
|||||||
compatible:
|
compatible:
|
||||||
enum:
|
enum:
|
||||||
- amlogic,meson-g12a-usb2-phy
|
- amlogic,meson-g12a-usb2-phy
|
||||||
|
- amlogic,meson-a1-usb2-phy
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
@@ -49,6 +50,19 @@ required:
|
|||||||
- reset-names
|
- reset-names
|
||||||
- "#phy-cells"
|
- "#phy-cells"
|
||||||
|
|
||||||
|
if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- amlogic,meson-a1-usb-ctrl
|
||||||
|
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
power-domains:
|
||||||
|
maxItems: 1
|
||||||
|
required:
|
||||||
|
- power-domains
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- |
|
- |
|
||||||
phy@36000 {
|
phy@36000 {
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
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>;
|
|
||||||
};
|
|
||||||
143
Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml
Normal file
143
Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: "http://devicetree.org/schemas/phy/phy-cadence-torrent.yaml#"
|
||||||
|
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||||
|
|
||||||
|
title: Cadence Torrent SD0801 PHY binding for DisplayPort
|
||||||
|
|
||||||
|
description:
|
||||||
|
This binding describes the Cadence SD0801 PHY (also known as Torrent PHY)
|
||||||
|
hardware included with the Cadence MHDP DisplayPort controller.
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Swapnil Jakhade <sjakhade@cadence.com>
|
||||||
|
- Yuti Amonkar <yamonkar@cadence.com>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- cdns,torrent-phy
|
||||||
|
- ti,j721e-serdes-10g
|
||||||
|
|
||||||
|
'#address-cells':
|
||||||
|
const: 1
|
||||||
|
|
||||||
|
'#size-cells':
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
description:
|
||||||
|
PHY reference clock. Must contain an entry in clock-names.
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
const: refclk
|
||||||
|
|
||||||
|
reg:
|
||||||
|
minItems: 1
|
||||||
|
maxItems: 2
|
||||||
|
items:
|
||||||
|
- description: Offset of the Torrent PHY configuration registers.
|
||||||
|
- description: Offset of the DPTX PHY configuration registers.
|
||||||
|
|
||||||
|
reg-names:
|
||||||
|
minItems: 1
|
||||||
|
maxItems: 2
|
||||||
|
items:
|
||||||
|
- const: torrent_phy
|
||||||
|
- const: dptx_phy
|
||||||
|
|
||||||
|
resets:
|
||||||
|
maxItems: 1
|
||||||
|
description:
|
||||||
|
Torrent PHY reset.
|
||||||
|
See Documentation/devicetree/bindings/reset/reset.txt
|
||||||
|
|
||||||
|
patternProperties:
|
||||||
|
'^phy@[0-7]+$':
|
||||||
|
type: object
|
||||||
|
description:
|
||||||
|
Each group of PHY lanes with a single master lane should be represented as a sub-node.
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
description:
|
||||||
|
The master lane number. This is the lowest numbered lane in the lane group.
|
||||||
|
|
||||||
|
resets:
|
||||||
|
minItems: 1
|
||||||
|
maxItems: 4
|
||||||
|
description:
|
||||||
|
Contains list of resets, one per lane, to get all the link lanes out of reset.
|
||||||
|
|
||||||
|
"#phy-cells":
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
cdns,phy-type:
|
||||||
|
description:
|
||||||
|
Specifies the type of PHY for which the group of PHY lanes is used.
|
||||||
|
Refer include/dt-bindings/phy/phy.h. Constants from the header should be used.
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [1, 2, 3, 4, 5, 6]
|
||||||
|
|
||||||
|
cdns,num-lanes:
|
||||||
|
description:
|
||||||
|
Number of DisplayPort lanes.
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [1, 2, 4]
|
||||||
|
default: 4
|
||||||
|
|
||||||
|
cdns,max-bit-rate:
|
||||||
|
description:
|
||||||
|
Maximum DisplayPort link bit rate to use, in Mbps
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [2160, 2430, 2700, 3240, 4320, 5400, 8100]
|
||||||
|
default: 8100
|
||||||
|
|
||||||
|
required:
|
||||||
|
- reg
|
||||||
|
- resets
|
||||||
|
- "#phy-cells"
|
||||||
|
- cdns,phy-type
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- "#address-cells"
|
||||||
|
- "#size-cells"
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
- reg
|
||||||
|
- reg-names
|
||||||
|
- resets
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/phy/phy.h>
|
||||||
|
torrent_phy: torrent-phy@f0fb500000 {
|
||||||
|
compatible = "cdns,torrent-phy";
|
||||||
|
reg = <0xf0 0xfb500000 0x0 0x00100000>,
|
||||||
|
<0xf0 0xfb030a00 0x0 0x00000040>;
|
||||||
|
reg-names = "torrent_phy", "dptx_phy";
|
||||||
|
resets = <&phyrst 0>;
|
||||||
|
clocks = <&ref_clk>;
|
||||||
|
clock-names = "refclk";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
torrent_phy_dp: phy@0 {
|
||||||
|
reg = <0>;
|
||||||
|
resets = <&phyrst 1>, <&phyrst 2>,
|
||||||
|
<&phyrst 3>, <&phyrst 4>;
|
||||||
|
#phy-cells = <0>;
|
||||||
|
cdns,phy-type = <PHY_TYPE_DP>;
|
||||||
|
cdns,num-lanes = <4>;
|
||||||
|
cdns,max-bit-rate = <8100>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
...
|
||||||
@@ -13,10 +13,16 @@ Required properties (controller (parent) node):
|
|||||||
"mediatek,mt8173-u3phy";
|
"mediatek,mt8173-u3phy";
|
||||||
make use of "mediatek,generic-tphy-v1" on mt2701 instead and
|
make use of "mediatek,generic-tphy-v1" on mt2701 instead and
|
||||||
"mediatek,generic-tphy-v2" on mt2712 instead.
|
"mediatek,generic-tphy-v2" on mt2712 instead.
|
||||||
- clocks : (deprecated, use port's clocks instead) a list of phandle +
|
|
||||||
clock-specifier pairs, one for each entry in clock-names
|
- #address-cells: the number of cells used to represent physical
|
||||||
- clock-names : (deprecated, use port's one instead) must contain
|
base addresses.
|
||||||
"u3phya_ref": for reference clock of usb3.0 analog phy.
|
- #size-cells: the number of cells used to represent the size of an address.
|
||||||
|
- ranges: the address mapping relationship to the parent, defined with
|
||||||
|
- empty value: if optional 'reg' is used.
|
||||||
|
- non-empty value: if optional 'reg' is not used. should set
|
||||||
|
the child's base address to 0, the physical address
|
||||||
|
within parent's address space, and the length of
|
||||||
|
the address map.
|
||||||
|
|
||||||
Required nodes : a sub-node is required for each port the controller
|
Required nodes : a sub-node is required for each port the controller
|
||||||
provides. Address range information including the usual
|
provides. Address range information including the usual
|
||||||
@@ -34,12 +40,6 @@ Optional properties (controller (parent) node):
|
|||||||
|
|
||||||
Required properties (port (child) node):
|
Required properties (port (child) node):
|
||||||
- reg : address and length of the register set for the port.
|
- reg : address and length of the register set for the port.
|
||||||
- clocks : a list of phandle + clock-specifier pairs, one for each
|
|
||||||
entry in clock-names
|
|
||||||
- clock-names : must contain
|
|
||||||
"ref": 48M reference clock for HighSpeed analog phy; and 26M
|
|
||||||
reference clock for SuperSpeed analog phy, sometimes is
|
|
||||||
24M, 25M or 27M, depended on platform.
|
|
||||||
- #phy-cells : should be 1 (See second example)
|
- #phy-cells : should be 1 (See second example)
|
||||||
cell after port phandle is phy type from:
|
cell after port phandle is phy type from:
|
||||||
- PHY_TYPE_USB2
|
- PHY_TYPE_USB2
|
||||||
@@ -48,10 +48,22 @@ Required properties (port (child) node):
|
|||||||
- PHY_TYPE_SATA
|
- PHY_TYPE_SATA
|
||||||
|
|
||||||
Optional properties (PHY_TYPE_USB2 port (child) node):
|
Optional properties (PHY_TYPE_USB2 port (child) node):
|
||||||
|
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||||
|
entry in clock-names
|
||||||
|
- clock-names : may contain
|
||||||
|
"ref": 48M reference clock for HighSpeed (digital) phy; and 26M
|
||||||
|
reference clock for SuperSpeed (digital) phy, sometimes is
|
||||||
|
24M, 25M or 27M, depended on platform.
|
||||||
|
"da_ref": the reference clock of analog phy, used if the clocks
|
||||||
|
of analog and digital phys are separated, otherwise uses
|
||||||
|
"ref" clock only if needed.
|
||||||
|
|
||||||
- mediatek,eye-src : u32, the value of slew rate calibrate
|
- mediatek,eye-src : u32, the value of slew rate calibrate
|
||||||
- mediatek,eye-vrt : u32, the selection of VRT reference voltage
|
- mediatek,eye-vrt : u32, the selection of VRT reference voltage
|
||||||
- mediatek,eye-term : u32, the selection of HS_TX TERM reference voltage
|
- mediatek,eye-term : u32, the selection of HS_TX TERM reference voltage
|
||||||
- mediatek,bc12 : bool, enable BC12 of u2phy if support it
|
- mediatek,bc12 : bool, enable BC12 of u2phy if support it
|
||||||
|
- mediatek,discth : u32, the selection of disconnect threshold
|
||||||
|
- mediatek,intr : u32, the selection of internal R (resistance)
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|||||||
185
Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml
Normal file
185
Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: "http://devicetree.org/schemas/phy/qcom,qusb2-phy.yaml#"
|
||||||
|
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||||
|
|
||||||
|
title: Qualcomm QUSB2 phy controller
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Manu Gautam <mgautam@codeaurora.org>
|
||||||
|
|
||||||
|
description:
|
||||||
|
QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- qcom,msm8996-qusb2-phy
|
||||||
|
- qcom,msm8998-qusb2-phy
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- qcom,sc7180-qusb2-phy
|
||||||
|
- qcom,sdm845-qusb2-phy
|
||||||
|
- const: qcom,qusb2-v2-phy
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
"#phy-cells":
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
minItems: 2
|
||||||
|
maxItems: 3
|
||||||
|
items:
|
||||||
|
- description: phy config clock
|
||||||
|
- description: 19.2 MHz ref clk
|
||||||
|
- description: phy interface clock (Optional)
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
minItems: 2
|
||||||
|
maxItems: 3
|
||||||
|
items:
|
||||||
|
- const: cfg_ahb
|
||||||
|
- const: ref
|
||||||
|
- const: iface
|
||||||
|
|
||||||
|
vdda-pll-supply:
|
||||||
|
description:
|
||||||
|
Phandle to 1.8V regulator supply to PHY refclk pll block.
|
||||||
|
|
||||||
|
vdda-phy-dpdm-supply:
|
||||||
|
description:
|
||||||
|
Phandle to 3.1V regulator supply to Dp/Dm port signals.
|
||||||
|
|
||||||
|
resets:
|
||||||
|
maxItems: 1
|
||||||
|
description:
|
||||||
|
Phandle to reset to phy block.
|
||||||
|
|
||||||
|
nvmem-cells:
|
||||||
|
maxItems: 1
|
||||||
|
description:
|
||||||
|
Phandle to nvmem cell that contains 'HS Tx trim'
|
||||||
|
tuning parameter value for qusb2 phy.
|
||||||
|
|
||||||
|
qcom,tcsr-syscon:
|
||||||
|
description:
|
||||||
|
Phandle to TCSR syscon register region.
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
|
||||||
|
if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
const: qcom,qusb2-v2-phy
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
qcom,imp-res-offset-value:
|
||||||
|
description:
|
||||||
|
It is a 6 bit value that specifies offset to be
|
||||||
|
added to PHY refgen RESCODE via IMP_CTRL1 register. It is a PHY
|
||||||
|
tuning parameter that may vary for different boards of same SOC.
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 63
|
||||||
|
default: 0
|
||||||
|
|
||||||
|
qcom,bias-ctrl-value:
|
||||||
|
description:
|
||||||
|
It is a 6 bit value that specifies bias-ctrl-value. It is a PHY
|
||||||
|
tuning parameter that may vary for different boards of same SOC.
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 63
|
||||||
|
default: 0
|
||||||
|
|
||||||
|
qcom,charge-ctrl-value:
|
||||||
|
description:
|
||||||
|
It is a 2 bit value that specifies charge-ctrl-value. It is a PHY
|
||||||
|
tuning parameter that may vary for different boards of same SOC.
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 3
|
||||||
|
default: 0
|
||||||
|
|
||||||
|
qcom,hstx-trim-value:
|
||||||
|
description:
|
||||||
|
It is a 4 bit value that specifies tuning for HSTX
|
||||||
|
output current.
|
||||||
|
Possible range is - 15mA to 24mA (stepsize of 600 uA).
|
||||||
|
See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 15
|
||||||
|
default: 3
|
||||||
|
|
||||||
|
qcom,preemphasis-level:
|
||||||
|
description:
|
||||||
|
It is a 2 bit value that specifies pre-emphasis level.
|
||||||
|
Possible range is 0 to 15% (stepsize of 5%).
|
||||||
|
See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 3
|
||||||
|
default: 2
|
||||||
|
|
||||||
|
qcom,preemphasis-width:
|
||||||
|
description:
|
||||||
|
It is a 1 bit value that specifies how long the HSTX
|
||||||
|
pre-emphasis (specified using qcom,preemphasis-level) must be in
|
||||||
|
effect. Duration could be half-bit of full-bit.
|
||||||
|
See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 1
|
||||||
|
default: 0
|
||||||
|
|
||||||
|
qcom,hsdisc-trim-value:
|
||||||
|
description:
|
||||||
|
It is a 2 bit value tuning parameter that control disconnect
|
||||||
|
threshold and may vary for different boards of same SOC.
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 3
|
||||||
|
default: 0
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- "#phy-cells"
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
- vdda-pll-supply
|
||||||
|
- vdda-phy-dpdm-supply
|
||||||
|
- resets
|
||||||
|
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/clock/qcom,gcc-msm8996.h>
|
||||||
|
hsusb_phy: phy@7411000 {
|
||||||
|
compatible = "qcom,msm8996-qusb2-phy";
|
||||||
|
reg = <0x7411000 0x180>;
|
||||||
|
#phy-cells = <0>;
|
||||||
|
|
||||||
|
clocks = <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
|
||||||
|
<&gcc GCC_RX1_USB2_CLKREF_CLK>;
|
||||||
|
clock-names = "cfg_ahb", "ref";
|
||||||
|
|
||||||
|
vdda-pll-supply = <&pm8994_l12>;
|
||||||
|
vdda-phy-dpdm-supply = <&pm8994_l24>;
|
||||||
|
|
||||||
|
resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>;
|
||||||
|
nvmem-cells = <&qusb2p_hstx_trim>;
|
||||||
|
};
|
||||||
90
Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml
Normal file
90
Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: "http://devicetree.org/schemas/phy/qcom,usb-hs-28nm.yaml#"
|
||||||
|
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||||
|
|
||||||
|
title: Qualcomm Synopsys DesignWare Core 28nm High-Speed PHY
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Bryan O'Donoghue <bryan.odonoghue@linaro.org>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
Qualcomm Low-Speed, Full-Speed, Hi-Speed 28nm USB PHY
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- qcom,usb-hs-28nm-femtophy
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
"#phy-cells":
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
items:
|
||||||
|
- description: rpmcc ref clock
|
||||||
|
- description: PHY AHB clock
|
||||||
|
- description: Rentention clock
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
items:
|
||||||
|
- const: ref
|
||||||
|
- const: ahb
|
||||||
|
- const: sleep
|
||||||
|
|
||||||
|
resets:
|
||||||
|
items:
|
||||||
|
- description: PHY core reset
|
||||||
|
- description: POR reset
|
||||||
|
|
||||||
|
reset-names:
|
||||||
|
items:
|
||||||
|
- const: phy
|
||||||
|
- const: por
|
||||||
|
|
||||||
|
vdd-supply:
|
||||||
|
description: phandle to the regulator VDD supply node.
|
||||||
|
|
||||||
|
vdda1p8-supply:
|
||||||
|
description: phandle to the regulator 1.8V supply node.
|
||||||
|
|
||||||
|
vdda3p3-supply:
|
||||||
|
description: phandle to the regulator 3.3V supply node.
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- "#phy-cells"
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
- resets
|
||||||
|
- reset-names
|
||||||
|
- vdd-supply
|
||||||
|
- vdda1p8-supply
|
||||||
|
- vdda3p3-supply
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/clock/qcom,gcc-qcs404.h>
|
||||||
|
#include <dt-bindings/clock/qcom,rpmcc.h>
|
||||||
|
usb2_phy_prim: phy@7a000 {
|
||||||
|
compatible = "qcom,usb-hs-28nm-femtophy";
|
||||||
|
reg = <0x0007a000 0x200>;
|
||||||
|
#phy-cells = <0>;
|
||||||
|
clocks = <&rpmcc RPM_SMD_LN_BB_CLK>,
|
||||||
|
<&gcc GCC_USB_HS_PHY_CFG_AHB_CLK>,
|
||||||
|
<&gcc GCC_USB2A_PHY_SLEEP_CLK>;
|
||||||
|
clock-names = "ref", "ahb", "sleep";
|
||||||
|
resets = <&gcc GCC_USB_HS_PHY_CFG_AHB_BCR>,
|
||||||
|
<&gcc GCC_USB2A_PHY_BCR>;
|
||||||
|
reset-names = "phy", "por";
|
||||||
|
vdd-supply = <&vreg_l4_1p2>;
|
||||||
|
vdda1p8-supply = <&vreg_l5_1p8>;
|
||||||
|
vdda3p3-supply = <&vreg_l12_3p3>;
|
||||||
|
};
|
||||||
|
...
|
||||||
83
Documentation/devicetree/bindings/phy/qcom,usb-ss.yaml
Normal file
83
Documentation/devicetree/bindings/phy/qcom,usb-ss.yaml
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: "http://devicetree.org/schemas/phy/qcom,usb-ss.yaml#"
|
||||||
|
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||||
|
|
||||||
|
title: Qualcomm Synopsys 1.0.0 SuperSpeed USB PHY
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Bryan O'Donoghue <bryan.odonoghue@linaro.org>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
Qualcomm Synopsys 1.0.0 SuperSpeed USB PHY
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- qcom,usb-ss-28nm-phy
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
"#phy-cells":
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
items:
|
||||||
|
- description: rpmcc clock
|
||||||
|
- description: PHY AHB clock
|
||||||
|
- description: SuperSpeed pipe clock
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
items:
|
||||||
|
- const: ref
|
||||||
|
- const: ahb
|
||||||
|
- const: pipe
|
||||||
|
|
||||||
|
vdd-supply:
|
||||||
|
description: phandle to the regulator VDD supply node.
|
||||||
|
|
||||||
|
vdda1p8-supply:
|
||||||
|
description: phandle to the regulator 1.8V supply node.
|
||||||
|
|
||||||
|
resets:
|
||||||
|
items:
|
||||||
|
- description: COM reset
|
||||||
|
- description: PHY reset line
|
||||||
|
|
||||||
|
reset-names:
|
||||||
|
items:
|
||||||
|
- const: com
|
||||||
|
- const: phy
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- "#phy-cells"
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
- vdd-supply
|
||||||
|
- vdda1p8-supply
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/clock/qcom,gcc-qcs404.h>
|
||||||
|
#include <dt-bindings/clock/qcom,rpmcc.h>
|
||||||
|
usb3_phy: usb3-phy@78000 {
|
||||||
|
compatible = "qcom,usb-ss-28nm-phy";
|
||||||
|
reg = <0x78000 0x400>;
|
||||||
|
#phy-cells = <0>;
|
||||||
|
clocks = <&rpmcc RPM_SMD_LN_BB_CLK>,
|
||||||
|
<&gcc GCC_USB_HS_PHY_CFG_AHB_CLK>,
|
||||||
|
<&gcc GCC_USB3_PHY_PIPE_CLK>;
|
||||||
|
clock-names = "ref", "ahb", "pipe";
|
||||||
|
resets = <&gcc GCC_USB3_PHY_BCR>,
|
||||||
|
<&gcc GCC_USB3PHY_PHY_BCR>;
|
||||||
|
reset-names = "com", "phy";
|
||||||
|
vdd-supply = <&vreg_l3_1p05>;
|
||||||
|
vdda1p8-supply = <&vreg_l5_1p8>;
|
||||||
|
};
|
||||||
|
...
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
Qualcomm DWC3 HS AND SS PHY CONTROLLER
|
|
||||||
--------------------------------------
|
|
||||||
|
|
||||||
DWC3 PHY nodes are defined to describe on-chip Synopsis Physical layer
|
|
||||||
controllers. Each DWC3 PHY controller should have its own node.
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: should contain one of the following:
|
|
||||||
- "qcom,dwc3-hs-usb-phy" for High Speed Synopsis PHY controller
|
|
||||||
- "qcom,dwc3-ss-usb-phy" for Super Speed Synopsis PHY controller
|
|
||||||
- reg: offset and length of the DWC3 PHY controller register set
|
|
||||||
- #phy-cells: must be zero
|
|
||||||
- clocks: a list of phandles and clock-specifier pairs, one for each entry in
|
|
||||||
clock-names.
|
|
||||||
- clock-names: Should contain "ref" for the PHY reference clock
|
|
||||||
|
|
||||||
Optional clocks:
|
|
||||||
"xo" External reference clock
|
|
||||||
|
|
||||||
Example:
|
|
||||||
phy@100f8800 {
|
|
||||||
compatible = "qcom,dwc3-hs-usb-phy";
|
|
||||||
reg = <0x100f8800 0x30>;
|
|
||||||
clocks = <&gcc USB30_0_UTMI_CLK>;
|
|
||||||
clock-names = "ref";
|
|
||||||
#phy-cells = <0>;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
phy@100f8830 {
|
|
||||||
compatible = "qcom,dwc3-ss-usb-phy";
|
|
||||||
reg = <0x100f8830 0x30>;
|
|
||||||
clocks = <&gcc USB30_0_MASTER_CLK>;
|
|
||||||
clock-names = "ref";
|
|
||||||
#phy-cells = <0>;
|
|
||||||
|
|
||||||
};
|
|
||||||
@@ -8,10 +8,13 @@ Required properties:
|
|||||||
- compatible: compatible list, contains:
|
- compatible: compatible list, contains:
|
||||||
"qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074
|
"qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074
|
||||||
"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-ufs-phy" for 14nm UFS 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,msm8998-qmp-usb3-phy" for USB3 QMP V3 phy on msm8998,
|
"qcom,msm8998-qmp-usb3-phy" for USB3 QMP V3 phy on msm8998,
|
||||||
"qcom,msm8998-qmp-ufs-phy" for UFS QMP phy on msm8998,
|
"qcom,msm8998-qmp-ufs-phy" for UFS QMP phy on msm8998,
|
||||||
"qcom,msm8998-qmp-pcie-phy" for PCIe QMP phy on msm8998,
|
"qcom,msm8998-qmp-pcie-phy" for PCIe QMP phy on msm8998,
|
||||||
|
"qcom,sdm845-qhp-pcie-phy" for QHP PCIe phy on sdm845,
|
||||||
|
"qcom,sdm845-qmp-pcie-phy" for QMP PCIe phy on sdm845,
|
||||||
"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,
|
"qcom,sdm845-qmp-ufs-phy" for UFS QMP phy on sdm845,
|
||||||
@@ -44,6 +47,8 @@ Required properties:
|
|||||||
For "qcom,ipq8074-qmp-pcie-phy": no clocks are listed.
|
For "qcom,ipq8074-qmp-pcie-phy": no clocks are listed.
|
||||||
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-ufs-phy" must contain:
|
||||||
|
"ref".
|
||||||
For "qcom,msm8996-qmp-usb3-phy" must contain:
|
For "qcom,msm8996-qmp-usb3-phy" must contain:
|
||||||
"aux", "cfg_ahb", "ref".
|
"aux", "cfg_ahb", "ref".
|
||||||
For "qcom,msm8998-qmp-usb3-phy" must contain:
|
For "qcom,msm8998-qmp-usb3-phy" must contain:
|
||||||
@@ -52,6 +57,10 @@ Required properties:
|
|||||||
"ref", "ref_aux".
|
"ref", "ref_aux".
|
||||||
For "qcom,msm8998-qmp-pcie-phy" must contain:
|
For "qcom,msm8998-qmp-pcie-phy" must contain:
|
||||||
"aux", "cfg_ahb", "ref".
|
"aux", "cfg_ahb", "ref".
|
||||||
|
For "qcom,sdm845-qhp-pcie-phy" must contain:
|
||||||
|
"aux", "cfg_ahb", "ref", "refgen".
|
||||||
|
For "qcom,sdm845-qmp-pcie-phy" must contain:
|
||||||
|
"aux", "cfg_ahb", "ref", "refgen".
|
||||||
For "qcom,sdm845-qmp-usb3-phy" must contain:
|
For "qcom,sdm845-qmp-usb3-phy" must contain:
|
||||||
"aux", "cfg_ahb", "ref", "com_aux".
|
"aux", "cfg_ahb", "ref", "com_aux".
|
||||||
For "qcom,sdm845-qmp-usb3-uni-phy" must contain:
|
For "qcom,sdm845-qmp-usb3-uni-phy" must contain:
|
||||||
@@ -72,6 +81,8 @@ Required properties:
|
|||||||
"phy", "common".
|
"phy", "common".
|
||||||
For "qcom,msm8996-qmp-pcie-phy" must contain:
|
For "qcom,msm8996-qmp-pcie-phy" must contain:
|
||||||
"phy", "common", "cfg".
|
"phy", "common", "cfg".
|
||||||
|
For "qcom,msm8996-qmp-ufs-phy": must contain:
|
||||||
|
"ufsphy".
|
||||||
For "qcom,msm8996-qmp-usb3-phy" must contain
|
For "qcom,msm8996-qmp-usb3-phy" must contain
|
||||||
"phy", "common".
|
"phy", "common".
|
||||||
For "qcom,msm8998-qmp-usb3-phy" must contain
|
For "qcom,msm8998-qmp-usb3-phy" must contain
|
||||||
@@ -80,6 +91,10 @@ Required properties:
|
|||||||
"ufsphy".
|
"ufsphy".
|
||||||
For "qcom,msm8998-qmp-pcie-phy" must contain:
|
For "qcom,msm8998-qmp-pcie-phy" must contain:
|
||||||
"phy", "common".
|
"phy", "common".
|
||||||
|
For "qcom,sdm845-qhp-pcie-phy" must contain:
|
||||||
|
"phy".
|
||||||
|
For "qcom,sdm845-qmp-pcie-phy" must contain:
|
||||||
|
"phy".
|
||||||
For "qcom,sdm845-qmp-usb3-phy" must contain:
|
For "qcom,sdm845-qmp-usb3-phy" must contain:
|
||||||
"phy", "common".
|
"phy", "common".
|
||||||
For "qcom,sdm845-qmp-usb3-uni-phy" must contain:
|
For "qcom,sdm845-qmp-usb3-uni-phy" must contain:
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
Qualcomm QUSB2 phy controller
|
|
||||||
=============================
|
|
||||||
|
|
||||||
QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: compatible list, contains
|
|
||||||
"qcom,msm8996-qusb2-phy" for 14nm PHY on msm8996,
|
|
||||||
"qcom,msm8998-qusb2-phy" for 10nm PHY on msm8998,
|
|
||||||
"qcom,sdm845-qusb2-phy" for 10nm PHY on sdm845.
|
|
||||||
|
|
||||||
- reg: offset and length of the PHY register set.
|
|
||||||
- #phy-cells: must be 0.
|
|
||||||
|
|
||||||
- clocks: a list of phandles and clock-specifier pairs,
|
|
||||||
one for each entry in clock-names.
|
|
||||||
- clock-names: must be "cfg_ahb" for phy config clock,
|
|
||||||
"ref" for 19.2 MHz ref clk,
|
|
||||||
"iface" for phy interface clock (Optional).
|
|
||||||
|
|
||||||
- vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block.
|
|
||||||
- vdda-phy-dpdm-supply: Phandle to 3.1V regulator supply to Dp/Dm port signals.
|
|
||||||
|
|
||||||
- resets: Phandle to reset to phy block.
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- nvmem-cells: Phandle to nvmem cell that contains 'HS Tx trim'
|
|
||||||
tuning parameter value for qusb2 phy.
|
|
||||||
|
|
||||||
- qcom,tcsr-syscon: Phandle to TCSR syscon register region.
|
|
||||||
- qcom,imp-res-offset-value: It is a 6 bit value that specifies offset to be
|
|
||||||
added to PHY refgen RESCODE via IMP_CTRL1 register. It is a PHY
|
|
||||||
tuning parameter that may vary for different boards of same SOC.
|
|
||||||
This property is applicable to only QUSB2 v2 PHY (sdm845).
|
|
||||||
- qcom,hstx-trim-value: It is a 4 bit value that specifies tuning for HSTX
|
|
||||||
output current.
|
|
||||||
Possible range is - 15mA to 24mA (stepsize of 600 uA).
|
|
||||||
See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
|
|
||||||
This property is applicable to only QUSB2 v2 PHY (sdm845).
|
|
||||||
Default value is 22.2mA for sdm845.
|
|
||||||
- qcom,preemphasis-level: It is a 2 bit value that specifies pre-emphasis level.
|
|
||||||
Possible range is 0 to 15% (stepsize of 5%).
|
|
||||||
See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
|
|
||||||
This property is applicable to only QUSB2 v2 PHY (sdm845).
|
|
||||||
Default value is 10% for sdm845.
|
|
||||||
- qcom,preemphasis-width: It is a 1 bit value that specifies how long the HSTX
|
|
||||||
pre-emphasis (specified using qcom,preemphasis-level) must be in
|
|
||||||
effect. Duration could be half-bit of full-bit.
|
|
||||||
See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
|
|
||||||
This property is applicable to only QUSB2 v2 PHY (sdm845).
|
|
||||||
Default value is full-bit width for sdm845.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
hsusb_phy: phy@7411000 {
|
|
||||||
compatible = "qcom,msm8996-qusb2-phy";
|
|
||||||
reg = <0x7411000 0x180>;
|
|
||||||
#phy-cells = <0>;
|
|
||||||
|
|
||||||
clocks = <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
|
|
||||||
<&gcc GCC_RX1_USB2_CLKREF_CLK>,
|
|
||||||
clock-names = "cfg_ahb", "ref";
|
|
||||||
|
|
||||||
vdda-pll-supply = <&pm8994_l12>;
|
|
||||||
vdda-phy-dpdm-supply = <&pm8994_l24>;
|
|
||||||
|
|
||||||
resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>;
|
|
||||||
nvmem-cells = <&qusb2p_hstx_trim>;
|
|
||||||
};
|
|
||||||
@@ -40,6 +40,7 @@ Required properties:
|
|||||||
"ti,dra7xx-phy-gmii-sel" for dra7xx/am57xx platform
|
"ti,dra7xx-phy-gmii-sel" for dra7xx/am57xx platform
|
||||||
"ti,am43xx-phy-gmii-sel" for am43xx platform
|
"ti,am43xx-phy-gmii-sel" for am43xx platform
|
||||||
"ti,dm814-phy-gmii-sel" for dm814x platform
|
"ti,dm814-phy-gmii-sel" for dm814x platform
|
||||||
|
"ti,am654-phy-gmii-sel" for AM654x/J721E platform
|
||||||
- reg : Address and length of the register set for the device
|
- reg : Address and length of the register set for the device
|
||||||
- #phy-cells : must be 2.
|
- #phy-cells : must be 2.
|
||||||
cell 1 - CPSW port number (starting from 1)
|
cell 1 - CPSW port number (starting from 1)
|
||||||
|
|||||||
@@ -5,14 +5,19 @@ PCIe controller implemented on Socionext UniPhier SoCs.
|
|||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: Should contain one of the following:
|
- compatible: Should contain one of the following:
|
||||||
|
"socionext,uniphier-pro5-pcie-phy" - for Pro5 PHY
|
||||||
"socionext,uniphier-ld20-pcie-phy" - for LD20 PHY
|
"socionext,uniphier-ld20-pcie-phy" - for LD20 PHY
|
||||||
"socionext,uniphier-pxs3-pcie-phy" - for PXs3 PHY
|
"socionext,uniphier-pxs3-pcie-phy" - for PXs3 PHY
|
||||||
- reg: Specifies offset and length of the register set for the device.
|
- reg: Specifies offset and length of the register set for the device.
|
||||||
- #phy-cells: Must be zero.
|
- #phy-cells: Must be zero.
|
||||||
- clocks: A phandle to the clock gate for PCIe glue layer including
|
- clocks: A list of phandles to the clock gate for PCIe glue layer
|
||||||
this phy.
|
including this phy.
|
||||||
- resets: A phandle to the reset line for PCIe glue layer including
|
- clock-names: For Pro5 only, should contain the following:
|
||||||
this phy.
|
"gio", "link" - for Pro5 SoC
|
||||||
|
- resets: A list of phandles to the reset line for PCIe glue layer
|
||||||
|
including this phy.
|
||||||
|
- reset-names: For Pro5 only, should contain the following:
|
||||||
|
"gio", "link" - for Pro5 SoC
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
- socionext,syscon: A phandle to system control to set configurations
|
- socionext,syscon: A phandle to system control to set configurations
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ this describes about High-Speed PHY.
|
|||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: Should contain one of the following:
|
- compatible: Should contain one of the following:
|
||||||
"socionext,uniphier-pro4-usb3-hsphy" - for Pro4 SoC
|
"socionext,uniphier-pro5-usb3-hsphy" - for Pro5 SoC
|
||||||
"socionext,uniphier-pxs2-usb3-hsphy" - for PXs2 SoC
|
"socionext,uniphier-pxs2-usb3-hsphy" - for PXs2 SoC
|
||||||
"socionext,uniphier-ld20-usb3-hsphy" - for LD20 SoC
|
"socionext,uniphier-ld20-usb3-hsphy" - for LD20 SoC
|
||||||
"socionext,uniphier-pxs3-usb3-hsphy" - for PXs3 SoC
|
"socionext,uniphier-pxs3-usb3-hsphy" - for PXs3 SoC
|
||||||
@@ -16,13 +16,13 @@ Required properties:
|
|||||||
- clocks: A list of phandles to the clock gate for USB3 glue layer.
|
- clocks: A list of phandles to the clock gate for USB3 glue layer.
|
||||||
According to the clock-names, appropriate clocks are required.
|
According to the clock-names, appropriate clocks are required.
|
||||||
- clock-names: Should contain the following:
|
- clock-names: Should contain the following:
|
||||||
"gio", "link" - for Pro4 SoC
|
"gio", "link" - for Pro5 SoC
|
||||||
"phy", "phy-ext", "link" - for PXs3 SoC, "phy-ext" is optional.
|
"phy", "phy-ext", "link" - for PXs3 SoC, "phy-ext" is optional.
|
||||||
"phy", "link" - for others
|
"phy", "link" - for others
|
||||||
- resets: A list of phandles to the reset control for USB3 glue layer.
|
- resets: A list of phandles to the reset control for USB3 glue layer.
|
||||||
According to the reset-names, appropriate resets are required.
|
According to the reset-names, appropriate resets are required.
|
||||||
- reset-names: Should contain the following:
|
- reset-names: Should contain the following:
|
||||||
"gio", "link" - for Pro4 SoC
|
"gio", "link" - for Pro5 SoC
|
||||||
"phy", "link" - for others
|
"phy", "link" - for others
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ this describes about Super-Speed PHY.
|
|||||||
Required properties:
|
Required properties:
|
||||||
- compatible: Should contain one of the following:
|
- compatible: Should contain one of the following:
|
||||||
"socionext,uniphier-pro4-usb3-ssphy" - for Pro4 SoC
|
"socionext,uniphier-pro4-usb3-ssphy" - for Pro4 SoC
|
||||||
|
"socionext,uniphier-pro5-usb3-ssphy" - for Pro5 SoC
|
||||||
"socionext,uniphier-pxs2-usb3-ssphy" - for PXs2 SoC
|
"socionext,uniphier-pxs2-usb3-ssphy" - for PXs2 SoC
|
||||||
"socionext,uniphier-ld20-usb3-ssphy" - for LD20 SoC
|
"socionext,uniphier-ld20-usb3-ssphy" - for LD20 SoC
|
||||||
"socionext,uniphier-pxs3-usb3-ssphy" - for PXs3 SoC
|
"socionext,uniphier-pxs3-usb3-ssphy" - for PXs3 SoC
|
||||||
@@ -16,13 +17,13 @@ Required properties:
|
|||||||
- clocks: A list of phandles to the clock gate for USB3 glue layer.
|
- clocks: A list of phandles to the clock gate for USB3 glue layer.
|
||||||
According to the clock-names, appropriate clocks are required.
|
According to the clock-names, appropriate clocks are required.
|
||||||
- clock-names:
|
- clock-names:
|
||||||
"gio", "link" - for Pro4 SoC
|
"gio", "link" - for Pro4 and Pro5 SoC
|
||||||
"phy", "phy-ext", "link" - for PXs3 SoC, "phy-ext" is optional.
|
"phy", "phy-ext", "link" - for PXs3 SoC, "phy-ext" is optional.
|
||||||
"phy", "link" - for others
|
"phy", "link" - for others
|
||||||
- resets: A list of phandles to the reset control for USB3 glue layer.
|
- resets: A list of phandles to the reset control for USB3 glue layer.
|
||||||
According to the reset-names, appropriate resets are required.
|
According to the reset-names, appropriate resets are required.
|
||||||
- reset-names:
|
- reset-names:
|
||||||
"gio", "link" - for Pro4 SoC
|
"gio", "link" - for Pro4 and Pro5 SoC
|
||||||
"phy", "link" - for others
|
"phy", "link" - for others
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
|
|||||||
@@ -22,10 +22,14 @@ description: |
|
|||||||
The DWC3 Glue controls the PHY routing and power, an interrupt line is
|
The DWC3 Glue controls the PHY routing and power, an interrupt line is
|
||||||
connected to the Glue to serve as OTG ID change detection.
|
connected to the Glue to serve as OTG ID change detection.
|
||||||
|
|
||||||
|
The Amlogic A1 embeds a DWC3 USB IP Core configured for USB2 in
|
||||||
|
host-only mode.
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
enum:
|
enum:
|
||||||
- amlogic,meson-g12a-usb-ctrl
|
- amlogic,meson-g12a-usb-ctrl
|
||||||
|
- amlogic,meson-a1-usb-ctrl
|
||||||
|
|
||||||
ranges: true
|
ranges: true
|
||||||
|
|
||||||
@@ -84,6 +88,25 @@ required:
|
|||||||
- phys
|
- phys
|
||||||
- dr_mode
|
- dr_mode
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- amlogic,meson-a1-usb-ctrl
|
||||||
|
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
clocks:
|
||||||
|
minItems: 3
|
||||||
|
clock-names:
|
||||||
|
items:
|
||||||
|
- const: usb_ctrl
|
||||||
|
- const: usb_bus
|
||||||
|
- const: xtal_usb_ctrl
|
||||||
|
required:
|
||||||
|
- clock-names
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- |
|
- |
|
||||||
usb: usb@ffe09000 {
|
usb: usb@ffe09000 {
|
||||||
|
|||||||
77
Documentation/devicetree/bindings/usb/aspeed,usb-vhub.yaml
Normal file
77
Documentation/devicetree/bindings/usb/aspeed,usb-vhub.yaml
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
# Copyright (c) 2020 Facebook Inc.
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/usb/aspeed,usb-vhub.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: ASPEED USB 2.0 Virtual Hub Controller
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Benjamin Herrenschmidt <benh@kernel.crashing.org>
|
||||||
|
|
||||||
|
description: |+
|
||||||
|
The ASPEED USB 2.0 Virtual Hub Controller implements 1 set of USB Hub
|
||||||
|
register and several sets of Device and Endpoint registers to support
|
||||||
|
the Virtual Hub's downstream USB devices.
|
||||||
|
|
||||||
|
Supported number of devices and endpoints vary depending on hardware
|
||||||
|
revisions. AST2400 and AST2500 Virtual Hub supports 5 downstream devices
|
||||||
|
and 15 generic endpoints, while AST2600 Virtual Hub supports 7 downstream
|
||||||
|
devices and 21 generic endpoints.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- aspeed,ast2400-usb-vhub
|
||||||
|
- aspeed,ast2500-usb-vhub
|
||||||
|
- aspeed,ast2600-usb-vhub
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
aspeed,vhub-downstream-ports:
|
||||||
|
description: Number of downstream ports supported by the Virtual Hub
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- default: 5
|
||||||
|
minimum: 1
|
||||||
|
maximum: 7
|
||||||
|
|
||||||
|
aspeed,vhub-generic-endpoints:
|
||||||
|
description: Number of generic endpoints supported by the Virtual Hub
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- default: 15
|
||||||
|
minimum: 1
|
||||||
|
maximum: 21
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- clocks
|
||||||
|
- interrupts
|
||||||
|
- aspeed,vhub-downstream-ports
|
||||||
|
- aspeed,vhub-generic-endpoints
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/clock/aspeed-clock.h>
|
||||||
|
vhub: usb-vhub@1e6a0000 {
|
||||||
|
compatible = "aspeed,ast2500-usb-vhub";
|
||||||
|
reg = <0x1e6a0000 0x300>;
|
||||||
|
interrupts = <5>;
|
||||||
|
clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
|
||||||
|
aspeed,vhub-downstream-ports = <5>;
|
||||||
|
aspeed,vhub-generic-endpoints = <15>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&pinctrl_usb2ad_default>;
|
||||||
|
};
|
||||||
@@ -18,27 +18,15 @@ properties:
|
|||||||
- const: rockchip,rk3066-usb
|
- const: rockchip,rk3066-usb
|
||||||
- const: snps,dwc2
|
- const: snps,dwc2
|
||||||
- items:
|
- items:
|
||||||
- const: rockchip,px30-usb
|
- enum:
|
||||||
- const: rockchip,rk3066-usb
|
- rockchip,px30-usb
|
||||||
- const: snps,dwc2
|
- rockchip,rk3036-usb
|
||||||
- items:
|
- rockchip,rk3188-usb
|
||||||
- const: rockchip,rk3036-usb
|
- rockchip,rk3228-usb
|
||||||
- const: rockchip,rk3066-usb
|
- rockchip,rk3288-usb
|
||||||
- const: snps,dwc2
|
- rockchip,rk3328-usb
|
||||||
- items:
|
- rockchip,rk3368-usb
|
||||||
- const: rockchip,rv1108-usb
|
- rockchip,rv1108-usb
|
||||||
- const: rockchip,rk3066-usb
|
|
||||||
- const: snps,dwc2
|
|
||||||
- items:
|
|
||||||
- const: rockchip,rk3188-usb
|
|
||||||
- const: rockchip,rk3066-usb
|
|
||||||
- const: snps,dwc2
|
|
||||||
- items:
|
|
||||||
- const: rockchip,rk3228-usb
|
|
||||||
- const: rockchip,rk3066-usb
|
|
||||||
- const: snps,dwc2
|
|
||||||
- items:
|
|
||||||
- const: rockchip,rk3288-usb
|
|
||||||
- const: rockchip,rk3066-usb
|
- const: rockchip,rk3066-usb
|
||||||
- const: snps,dwc2
|
- const: snps,dwc2
|
||||||
- const: lantiq,arx100-usb
|
- const: lantiq,arx100-usb
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ Required properties:
|
|||||||
- compatible: must be "snps,dwc3"
|
- compatible: must be "snps,dwc3"
|
||||||
- reg : Address and length of the register set for the device
|
- reg : Address and length of the register set for the device
|
||||||
- interrupts: Interrupts used by the dwc3 controller.
|
- interrupts: Interrupts used by the dwc3 controller.
|
||||||
- clock-names: should contain "ref", "bus_early", "suspend"
|
- clock-names: list of clock names. Ideally should be "ref",
|
||||||
|
"bus_early", "suspend" but may be less or more.
|
||||||
- clocks: list of phandle and clock specifier pairs corresponding to
|
- clocks: list of phandle and clock specifier pairs corresponding to
|
||||||
entries in the clock-names property.
|
entries in the clock-names property.
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ Optional properties:
|
|||||||
- phys: from the *Generic PHY* bindings
|
- phys: from the *Generic PHY* bindings
|
||||||
- phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy"
|
- phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy"
|
||||||
or "usb3-phy".
|
or "usb3-phy".
|
||||||
- resets: a single pair of phandle and reset specifier
|
- resets: set of phandle and reset specifier pairs
|
||||||
- snps,usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM
|
- snps,usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM
|
||||||
- snps,usb3_lpm_capable: determines if platform is USB3 LPM capable
|
- snps,usb3_lpm_capable: determines if platform is USB3 LPM capable
|
||||||
- snps,dis-start-transfer-quirk: when set, disable isoc START TRANSFER command
|
- snps,dis-start-transfer-quirk: when set, disable isoc START TRANSFER command
|
||||||
@@ -75,6 +76,8 @@ Optional properties:
|
|||||||
from P0 to P1/P2/P3 without delay.
|
from P0 to P1/P2/P3 without delay.
|
||||||
- snps,dis-tx-ipgap-linecheck-quirk: when set, disable u2mac linestate check
|
- snps,dis-tx-ipgap-linecheck-quirk: when set, disable u2mac linestate check
|
||||||
during HS transmit.
|
during HS transmit.
|
||||||
|
- snps,parkmode-disable-ss-quirk: when set, all SuperSpeed bus instances in
|
||||||
|
park mode are disabled.
|
||||||
- snps,dis_metastability_quirk: when set, disable metastability workaround.
|
- snps,dis_metastability_quirk: when set, disable metastability workaround.
|
||||||
CAUTION: use only if you are absolutely sure of it.
|
CAUTION: use only if you are absolutely sure of it.
|
||||||
- snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
|
- snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ Optional properties:
|
|||||||
the USB data role (USB host or USB device) for a given
|
the USB data role (USB host or USB device) for a given
|
||||||
USB connector, such as Type-C, Type-B(micro).
|
USB connector, such as Type-C, Type-B(micro).
|
||||||
see connector/usb-connector.txt.
|
see connector/usb-connector.txt.
|
||||||
|
- role-switch-default-mode: indicating if usb-role-switch is enabled, the
|
||||||
|
device default operation mode of controller while usb
|
||||||
|
role is USB_ROLE_NONE. Valid arguments are "host" and
|
||||||
|
"peripheral". Defaults to "peripheral" if not
|
||||||
|
specified.
|
||||||
|
|
||||||
|
|
||||||
This is an attribute to a USB controller such as:
|
This is an attribute to a USB controller such as:
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
Ingenic JZ4740 MUSB driver
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
|
|
||||||
- compatible: Must be "ingenic,jz4740-musb"
|
|
||||||
- reg: Address range of the UDC register set
|
|
||||||
- interrupts: IRQ number related to the UDC hardware
|
|
||||||
- interrupt-names: must be "mc"
|
|
||||||
- clocks: phandle to the "udc" clock
|
|
||||||
- clock-names: must be "udc"
|
|
||||||
- phys: phandle to the USB PHY
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
usb_phy: usb-phy@0 {
|
|
||||||
compatible = "usb-nop-xceiv";
|
|
||||||
#phy-cells = <0>;
|
|
||||||
};
|
|
||||||
|
|
||||||
udc: usb@13040000 {
|
|
||||||
compatible = "ingenic,jz4740-musb";
|
|
||||||
reg = <0x13040000 0x10000>;
|
|
||||||
|
|
||||||
interrupt-parent = <&intc>;
|
|
||||||
interrupts = <24>;
|
|
||||||
interrupt-names = "mc";
|
|
||||||
|
|
||||||
clocks = <&cgu JZ4740_CLK_UDC>;
|
|
||||||
clock-names = "udc";
|
|
||||||
|
|
||||||
phys = <&usb_phy>;
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/usb/ingenic,jz4770-phy.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Ingenic JZ4770 USB PHY devicetree bindings
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Paul Cercueil <paul@crapouillou.net>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
$nodename:
|
||||||
|
pattern: '^usb-phy@.*'
|
||||||
|
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- ingenic,jz4770-phy
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
vcc-supply:
|
||||||
|
description: VCC power supply
|
||||||
|
|
||||||
|
'#phy-cells':
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- clocks
|
||||||
|
- vcc-supply
|
||||||
|
- '#phy-cells'
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/clock/jz4770-cgu.h>
|
||||||
|
otg_phy: usb-phy@3c {
|
||||||
|
compatible = "ingenic,jz4770-phy";
|
||||||
|
reg = <0x3c 0x10>;
|
||||||
|
|
||||||
|
vcc-supply = <&vcc>;
|
||||||
|
clocks = <&cgu JZ4770_CLK_OTG_PHY>;
|
||||||
|
|
||||||
|
#phy-cells = <0>;
|
||||||
|
};
|
||||||
76
Documentation/devicetree/bindings/usb/ingenic,musb.yaml
Normal file
76
Documentation/devicetree/bindings/usb/ingenic,musb.yaml
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/usb/ingenic,musb.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Ingenic JZ47xx USB IP DT bindings
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Paul Cercueil <paul@crapouillou.net>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
$nodename:
|
||||||
|
pattern: '^usb@.*'
|
||||||
|
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
- enum:
|
||||||
|
- ingenic,jz4770-musb
|
||||||
|
- ingenic,jz4740-musb
|
||||||
|
- items:
|
||||||
|
- const: ingenic,jz4725b-musb
|
||||||
|
- const: ingenic,jz4740-musb
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
items:
|
||||||
|
- const: udc
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupt-names:
|
||||||
|
items:
|
||||||
|
- const: mc
|
||||||
|
|
||||||
|
phys:
|
||||||
|
description: PHY specifier for the USB PHY
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
- interrupts
|
||||||
|
- interrupt-names
|
||||||
|
- phys
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/clock/jz4740-cgu.h>
|
||||||
|
usb_phy: usb-phy@0 {
|
||||||
|
compatible = "usb-nop-xceiv";
|
||||||
|
#phy-cells = <0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
udc: usb@13040000 {
|
||||||
|
compatible = "ingenic,jz4740-musb";
|
||||||
|
reg = <0x13040000 0x10000>;
|
||||||
|
|
||||||
|
interrupt-parent = <&intc>;
|
||||||
|
interrupts = <24>;
|
||||||
|
interrupt-names = "mc";
|
||||||
|
|
||||||
|
clocks = <&cgu JZ4740_CLK_UDC>;
|
||||||
|
clock-names = "udc";
|
||||||
|
|
||||||
|
phys = <&usb_phy>;
|
||||||
|
};
|
||||||
69
Documentation/devicetree/bindings/usb/maxim,max3420-udc.yaml
Normal file
69
Documentation/devicetree/bindings/usb/maxim,max3420-udc.yaml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/usb/maxim,max3420-udc.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: MAXIM MAX3420/1 USB Peripheral Controller
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Jassi Brar <jaswinder.singh@linaro.org>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
The controller provices USB2.0 compliant FullSpeed peripheral
|
||||||
|
implementation over the SPI interface.
|
||||||
|
|
||||||
|
Specifications about the part can be found at:
|
||||||
|
http://datasheets.maximintegrated.com/en/ds/MAX3420E.pdf
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- maxim,max3420-udc
|
||||||
|
- maxim,max3421-udc
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
items:
|
||||||
|
- description: usb irq from max3420
|
||||||
|
- description: vbus detection irq
|
||||||
|
minItems: 1
|
||||||
|
maxItems: 2
|
||||||
|
|
||||||
|
interrupt-names:
|
||||||
|
items:
|
||||||
|
- const: udc
|
||||||
|
- const: vbus
|
||||||
|
minItems: 1
|
||||||
|
maxItems: 2
|
||||||
|
|
||||||
|
spi-max-frequency:
|
||||||
|
maximum: 26000000
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- interrupt-names
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/gpio/gpio.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
spi0 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
udc@0 {
|
||||||
|
compatible = "maxim,max3420-udc";
|
||||||
|
reg = <0>;
|
||||||
|
interrupt-parent = <&gpio>;
|
||||||
|
interrupts = <0 IRQ_TYPE_EDGE_FALLING>, <10 IRQ_TYPE_EDGE_BOTH>;
|
||||||
|
interrupt-names = "udc", "vbus";
|
||||||
|
spi-max-frequency = <12500000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -53,9 +53,7 @@ in need to reconfigure the pins on the connector, the alternate mode driver
|
|||||||
needs to notify the bus using :c:func:`typec_altmode_notify()`. The driver
|
needs to notify the bus using :c:func:`typec_altmode_notify()`. The driver
|
||||||
passes the negotiated SVID specific pin configuration value to the function as
|
passes the negotiated SVID specific pin configuration value to the function as
|
||||||
parameter. The bus driver will then configure the mux behind the connector using
|
parameter. The bus driver will then configure the mux behind the connector using
|
||||||
that value as the state value for the mux, and also call blocking notification
|
that value as the state value for the mux.
|
||||||
chain to notify the external drivers about the state of the connector that need
|
|
||||||
to know it.
|
|
||||||
|
|
||||||
NOTE: The SVID specific pin configuration values must always start from
|
NOTE: The SVID specific pin configuration values must always start from
|
||||||
``TYPEC_STATE_MODAL``. USB Type-C specification defines two default states for
|
``TYPEC_STATE_MODAL``. USB Type-C specification defines two default states for
|
||||||
@@ -80,19 +78,6 @@ Helper macro ``TYPEC_MODAL_STATE()`` can also be used::
|
|||||||
#define ALTMODEX_CONF_A = TYPEC_MODAL_STATE(0);
|
#define ALTMODEX_CONF_A = TYPEC_MODAL_STATE(0);
|
||||||
#define ALTMODEX_CONF_B = TYPEC_MODAL_STATE(1);
|
#define ALTMODEX_CONF_B = TYPEC_MODAL_STATE(1);
|
||||||
|
|
||||||
Notification chain
|
|
||||||
~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The drivers for the components that the alternate modes are designed for need to
|
|
||||||
get details regarding the results of the negotiation with the partner, and the
|
|
||||||
pin configuration of the connector. In case of DisplayPort alternate mode for
|
|
||||||
example, the GPU drivers will need to know those details. In case of
|
|
||||||
Thunderbolt alternate mode, the thunderbolt drivers will need to know them, and
|
|
||||||
so on.
|
|
||||||
|
|
||||||
The notification chain is designed for this purpose. The drivers can register
|
|
||||||
notifiers with :c:func:`typec_altmode_register_notifier()`.
|
|
||||||
|
|
||||||
Cable plug alternate modes
|
Cable plug alternate modes
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@@ -129,8 +114,3 @@ Cable Plug operations
|
|||||||
|
|
||||||
.. kernel-doc:: drivers/usb/typec/bus.c
|
.. kernel-doc:: drivers/usb/typec/bus.c
|
||||||
:functions: typec_altmode_get_plug typec_altmode_put_plug
|
:functions: typec_altmode_get_plug typec_altmode_put_plug
|
||||||
|
|
||||||
Notifications
|
|
||||||
~~~~~~~~~~~~~
|
|
||||||
.. kernel-doc:: drivers/usb/typec/class.c
|
|
||||||
:functions: typec_altmode_register_notifier typec_altmode_unregister_notifier
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ USB support
|
|||||||
misc_usbsevseg
|
misc_usbsevseg
|
||||||
mtouchusb
|
mtouchusb
|
||||||
ohci
|
ohci
|
||||||
|
raw-gadget
|
||||||
usbip_protocol
|
usbip_protocol
|
||||||
usbmon
|
usbmon
|
||||||
usb-serial
|
usb-serial
|
||||||
|
|||||||
61
Documentation/usb/raw-gadget.rst
Normal file
61
Documentation/usb/raw-gadget.rst
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
==============
|
||||||
|
USB Raw Gadget
|
||||||
|
==============
|
||||||
|
|
||||||
|
USB Raw Gadget is a kernel module that provides a userspace interface for
|
||||||
|
the USB Gadget subsystem. Essentially it allows to emulate USB devices
|
||||||
|
from userspace. Enabled with CONFIG_USB_RAW_GADGET. Raw Gadget is
|
||||||
|
currently a strictly debugging feature and shouldn't be used in
|
||||||
|
production, use GadgetFS instead.
|
||||||
|
|
||||||
|
Comparison to GadgetFS
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Raw Gadget is similar to GadgetFS, but provides a more low-level and
|
||||||
|
direct access to the USB Gadget layer for the userspace. The key
|
||||||
|
differences are:
|
||||||
|
|
||||||
|
1. Every USB request is passed to the userspace to get a response, while
|
||||||
|
GadgetFS responds to some USB requests internally based on the provided
|
||||||
|
descriptors. However note, that the UDC driver might respond to some
|
||||||
|
requests on its own and never forward them to the Gadget layer.
|
||||||
|
|
||||||
|
2. GadgetFS performs some sanity checks on the provided USB descriptors,
|
||||||
|
while Raw Gadget allows you to provide arbitrary data as responses to
|
||||||
|
USB requests.
|
||||||
|
|
||||||
|
3. Raw Gadget provides a way to select a UDC device/driver to bind to,
|
||||||
|
while GadgetFS currently binds to the first available UDC.
|
||||||
|
|
||||||
|
4. Raw Gadget uses predictable endpoint names (handles) across different
|
||||||
|
UDCs (as long as UDCs have enough endpoints of each required transfer
|
||||||
|
type).
|
||||||
|
|
||||||
|
5. Raw Gadget has ioctl-based interface instead of a filesystem-based one.
|
||||||
|
|
||||||
|
Userspace interface
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
To create a Raw Gadget instance open /dev/raw-gadget. Multiple raw-gadget
|
||||||
|
instances (bound to different UDCs) can be used at the same time. The
|
||||||
|
interaction with the opened file happens through the ioctl() calls, see
|
||||||
|
comments in include/uapi/linux/usb/raw_gadget.h for details.
|
||||||
|
|
||||||
|
The typical usage of Raw Gadget looks like:
|
||||||
|
|
||||||
|
1. Open Raw Gadget instance via /dev/raw-gadget.
|
||||||
|
2. Initialize the instance via USB_RAW_IOCTL_INIT.
|
||||||
|
3. Launch the instance with USB_RAW_IOCTL_RUN.
|
||||||
|
4. In a loop issue USB_RAW_IOCTL_EVENT_FETCH calls to receive events from
|
||||||
|
Raw Gadget and react to those depending on what kind of USB device
|
||||||
|
needs to be emulated.
|
||||||
|
|
||||||
|
Potential future improvements
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
- Implement ioctl's for setting/clearing halt status on endpoints.
|
||||||
|
|
||||||
|
- Reporting more events (suspend, resume, etc.) through
|
||||||
|
USB_RAW_IOCTL_EVENT_FETCH.
|
||||||
|
|
||||||
|
- Support O_NONBLOCK I/O.
|
||||||
@@ -17218,6 +17218,12 @@ S: Maintained
|
|||||||
F: Documentation/usb/acm.rst
|
F: Documentation/usb/acm.rst
|
||||||
F: drivers/usb/class/cdc-acm.*
|
F: drivers/usb/class/cdc-acm.*
|
||||||
|
|
||||||
|
USB APPLE MFI FASTCHARGE DRIVER
|
||||||
|
M: Bastien Nocera <hadess@hadess.net>
|
||||||
|
L: linux-usb@vger.kernel.org
|
||||||
|
S: Maintained
|
||||||
|
F: drivers/usb/misc/apple-mfi-fastcharge.c
|
||||||
|
|
||||||
USB AR5523 WIRELESS DRIVER
|
USB AR5523 WIRELESS DRIVER
|
||||||
M: Pontus Fuchs <pontus.fuchs@gmail.com>
|
M: Pontus Fuchs <pontus.fuchs@gmail.com>
|
||||||
L: linux-wireless@vger.kernel.org
|
L: linux-wireless@vger.kernel.org
|
||||||
|
|||||||
@@ -164,6 +164,8 @@
|
|||||||
reg = <0x1e6a0000 0x300>;
|
reg = <0x1e6a0000 0x300>;
|
||||||
interrupts = <5>;
|
interrupts = <5>;
|
||||||
clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
|
clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
|
||||||
|
aspeed,vhub-downstream-ports = <5>;
|
||||||
|
aspeed,vhub-generic-endpoints = <15>;
|
||||||
pinctrl-names = "default";
|
pinctrl-names = "default";
|
||||||
pinctrl-0 = <&pinctrl_usb2d_default>;
|
pinctrl-0 = <&pinctrl_usb2d_default>;
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -195,6 +195,8 @@
|
|||||||
reg = <0x1e6a0000 0x300>;
|
reg = <0x1e6a0000 0x300>;
|
||||||
interrupts = <5>;
|
interrupts = <5>;
|
||||||
clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
|
clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
|
||||||
|
aspeed,vhub-downstream-ports = <5>;
|
||||||
|
aspeed,vhub-generic-endpoints = <15>;
|
||||||
pinctrl-names = "default";
|
pinctrl-names = "default";
|
||||||
pinctrl-0 = <&pinctrl_usb2ad_default>;
|
pinctrl-0 = <&pinctrl_usb2ad_default>;
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
|||||||
@@ -1112,6 +1112,31 @@
|
|||||||
groups = "UART9";
|
groups = "UART9";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pinctrl_usb2ah_default: usb2ah_default {
|
||||||
|
function = "USB2AH";
|
||||||
|
groups = "USBA";
|
||||||
|
};
|
||||||
|
|
||||||
|
pinctrl_usb2ad_default: usb2ad_default {
|
||||||
|
function = "USB2AD";
|
||||||
|
groups = "USBA";
|
||||||
|
};
|
||||||
|
|
||||||
|
pinctrl_usb2bh_default: usb2bh_default {
|
||||||
|
function = "USB2BH";
|
||||||
|
groups = "USBB";
|
||||||
|
};
|
||||||
|
|
||||||
|
pinctrl_usb2bd_default: usb2bd_default {
|
||||||
|
function = "USB2BD";
|
||||||
|
groups = "USBB";
|
||||||
|
};
|
||||||
|
|
||||||
|
pinctrl_usb11bhid_default: usb11bhid_default {
|
||||||
|
function = "USB11BHID";
|
||||||
|
groups = "USBB";
|
||||||
|
};
|
||||||
|
|
||||||
pinctrl_vb_default: vb_default {
|
pinctrl_vb_default: vb_default {
|
||||||
function = "VB";
|
function = "VB";
|
||||||
groups = "VB";
|
groups = "VB";
|
||||||
|
|||||||
@@ -245,6 +245,51 @@
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ehci0: usb@1e6a1000 {
|
||||||
|
compatible = "aspeed,ast2600-ehci", "generic-ehci";
|
||||||
|
reg = <0x1e6a1000 0x100>;
|
||||||
|
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&pinctrl_usb2ah_default>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
ehci1: usb@1e6a3000 {
|
||||||
|
compatible = "aspeed,ast2600-ehci", "generic-ehci";
|
||||||
|
reg = <0x1e6a3000 0x100>;
|
||||||
|
interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
clocks = <&syscon ASPEED_CLK_GATE_USBPORT2CLK>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&pinctrl_usb2bh_default>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
uhci: usb@1e6b0000 {
|
||||||
|
compatible = "aspeed,ast2600-uhci", "generic-uhci";
|
||||||
|
reg = <0x1e6b0000 0x100>;
|
||||||
|
interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
#ports = <2>;
|
||||||
|
clocks = <&syscon ASPEED_CLK_GATE_USBUHCICLK>;
|
||||||
|
status = "disabled";
|
||||||
|
/*
|
||||||
|
* No default pinmux, it will follow EHCI, use an
|
||||||
|
* explicit pinmux override if EHCI is not enabled.
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
vhub: usb-vhub@1e6a0000 {
|
||||||
|
compatible = "aspeed,ast2600-usb-vhub";
|
||||||
|
reg = <0x1e6a0000 0x350>;
|
||||||
|
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
|
||||||
|
aspeed,vhub-downstream-ports = <7>;
|
||||||
|
aspeed,vhub-generic-endpoints = <21>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
pinctrl-0 = <&pinctrl_usb2ad_default>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
apb {
|
apb {
|
||||||
compatible = "simple-bus";
|
compatible = "simple-bus";
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
|
|||||||
@@ -62,6 +62,28 @@ struct resource *platform_get_resource(struct platform_device *dev,
|
|||||||
EXPORT_SYMBOL_GPL(platform_get_resource);
|
EXPORT_SYMBOL_GPL(platform_get_resource);
|
||||||
|
|
||||||
#ifdef CONFIG_HAS_IOMEM
|
#ifdef CONFIG_HAS_IOMEM
|
||||||
|
/**
|
||||||
|
* devm_platform_get_and_ioremap_resource - call devm_ioremap_resource() for a
|
||||||
|
* platform device and get resource
|
||||||
|
*
|
||||||
|
* @pdev: platform device to use both for memory resource lookup as well as
|
||||||
|
* resource management
|
||||||
|
* @index: resource index
|
||||||
|
* @res: optional output parameter to store a pointer to the obtained resource.
|
||||||
|
*/
|
||||||
|
void __iomem *
|
||||||
|
devm_platform_get_and_ioremap_resource(struct platform_device *pdev,
|
||||||
|
unsigned int index, struct resource **res)
|
||||||
|
{
|
||||||
|
struct resource *r;
|
||||||
|
|
||||||
|
r = platform_get_resource(pdev, IORESOURCE_MEM, index);
|
||||||
|
if (res)
|
||||||
|
*res = r;
|
||||||
|
return devm_ioremap_resource(&pdev->dev, r);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(devm_platform_get_and_ioremap_resource);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* devm_platform_ioremap_resource - call devm_ioremap_resource() for a platform
|
* devm_platform_ioremap_resource - call devm_ioremap_resource() for a platform
|
||||||
* device
|
* device
|
||||||
@@ -73,10 +95,7 @@ EXPORT_SYMBOL_GPL(platform_get_resource);
|
|||||||
void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev,
|
void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev,
|
||||||
unsigned int index)
|
unsigned int index)
|
||||||
{
|
{
|
||||||
struct resource *res;
|
return devm_platform_get_and_ioremap_resource(pdev, index, NULL);
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, index);
|
|
||||||
return devm_ioremap_resource(&pdev->dev, res);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource);
|
EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource);
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@
|
|||||||
#define PHY_CTRL_R14 0x38
|
#define PHY_CTRL_R14 0x38
|
||||||
#define PHY_CTRL_R14_I_RDP_EN BIT(0)
|
#define PHY_CTRL_R14_I_RDP_EN BIT(0)
|
||||||
#define PHY_CTRL_R14_I_RPU_SW1_EN BIT(1)
|
#define PHY_CTRL_R14_I_RPU_SW1_EN BIT(1)
|
||||||
#define PHY_CTRL_R14_I_RPU_SW2_EN GENMASK(2, 3)
|
#define PHY_CTRL_R14_I_RPU_SW2_EN GENMASK(3, 2)
|
||||||
#define PHY_CTRL_R14_PG_RSTN BIT(4)
|
#define PHY_CTRL_R14_PG_RSTN BIT(4)
|
||||||
#define PHY_CTRL_R14_I_C2L_DATA_16_8 BIT(5)
|
#define PHY_CTRL_R14_I_C2L_DATA_16_8 BIT(5)
|
||||||
#define PHY_CTRL_R14_I_C2L_ASSERT_SINGLE_EN_ZERO BIT(6)
|
#define PHY_CTRL_R14_I_C2L_ASSERT_SINGLE_EN_ZERO BIT(6)
|
||||||
@@ -146,11 +146,17 @@
|
|||||||
#define RESET_COMPLETE_TIME 1000
|
#define RESET_COMPLETE_TIME 1000
|
||||||
#define PLL_RESET_COMPLETE_TIME 100
|
#define PLL_RESET_COMPLETE_TIME 100
|
||||||
|
|
||||||
|
enum meson_soc_id {
|
||||||
|
MESON_SOC_G12A = 0,
|
||||||
|
MESON_SOC_A1,
|
||||||
|
};
|
||||||
|
|
||||||
struct phy_meson_g12a_usb2_priv {
|
struct phy_meson_g12a_usb2_priv {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
struct reset_control *reset;
|
struct reset_control *reset;
|
||||||
|
int soc_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct regmap_config phy_meson_g12a_usb2_regmap_conf = {
|
static const struct regmap_config phy_meson_g12a_usb2_regmap_conf = {
|
||||||
@@ -164,6 +170,7 @@ static int phy_meson_g12a_usb2_init(struct phy *phy)
|
|||||||
{
|
{
|
||||||
struct phy_meson_g12a_usb2_priv *priv = phy_get_drvdata(phy);
|
struct phy_meson_g12a_usb2_priv *priv = phy_get_drvdata(phy);
|
||||||
int ret;
|
int ret;
|
||||||
|
unsigned int value;
|
||||||
|
|
||||||
ret = reset_control_reset(priv->reset);
|
ret = reset_control_reset(priv->reset);
|
||||||
if (ret)
|
if (ret)
|
||||||
@@ -192,18 +199,22 @@ static int phy_meson_g12a_usb2_init(struct phy *phy)
|
|||||||
FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) |
|
FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) |
|
||||||
FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9));
|
FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9));
|
||||||
|
|
||||||
regmap_write(priv->regmap, PHY_CTRL_R18,
|
value = FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) |
|
||||||
FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) |
|
FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) |
|
||||||
FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) |
|
FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) |
|
||||||
FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) |
|
FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) |
|
||||||
FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) |
|
FIELD_PREP(PHY_CTRL_R18_MPLL_ROU, 7) |
|
||||||
FIELD_PREP(PHY_CTRL_R18_MPLL_ROU, 7) |
|
FIELD_PREP(PHY_CTRL_R18_MPLL_DATA_SEL, 3) |
|
||||||
FIELD_PREP(PHY_CTRL_R18_MPLL_DATA_SEL, 3) |
|
FIELD_PREP(PHY_CTRL_R18_MPLL_BIAS_ADJ, 1) |
|
||||||
FIELD_PREP(PHY_CTRL_R18_MPLL_BIAS_ADJ, 1) |
|
FIELD_PREP(PHY_CTRL_R18_MPLL_BB_MODE, 0) |
|
||||||
FIELD_PREP(PHY_CTRL_R18_MPLL_BB_MODE, 0) |
|
FIELD_PREP(PHY_CTRL_R18_MPLL_ALPHA, 3) |
|
||||||
FIELD_PREP(PHY_CTRL_R18_MPLL_ALPHA, 3) |
|
FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) |
|
||||||
FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) |
|
PHY_CTRL_R18_MPLL_ACG_RANGE;
|
||||||
PHY_CTRL_R18_MPLL_ACG_RANGE);
|
|
||||||
|
if (priv->soc_id == MESON_SOC_A1)
|
||||||
|
value |= PHY_CTRL_R18_MPLL_DCO_CLK_SEL;
|
||||||
|
|
||||||
|
regmap_write(priv->regmap, PHY_CTRL_R18, value);
|
||||||
|
|
||||||
udelay(PLL_RESET_COMPLETE_TIME);
|
udelay(PLL_RESET_COMPLETE_TIME);
|
||||||
|
|
||||||
@@ -227,13 +238,24 @@ static int phy_meson_g12a_usb2_init(struct phy *phy)
|
|||||||
FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) |
|
FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) |
|
||||||
FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0));
|
FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0));
|
||||||
|
|
||||||
regmap_write(priv->regmap, PHY_CTRL_R4,
|
if (priv->soc_id == MESON_SOC_G12A)
|
||||||
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) |
|
regmap_write(priv->regmap, PHY_CTRL_R4,
|
||||||
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) |
|
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) |
|
||||||
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) |
|
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) |
|
||||||
PHY_CTRL_R4_TEST_BYPASS_MODE_EN |
|
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) |
|
||||||
FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) |
|
PHY_CTRL_R4_TEST_BYPASS_MODE_EN |
|
||||||
FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0));
|
FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) |
|
||||||
|
FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0));
|
||||||
|
else if (priv->soc_id == MESON_SOC_A1) {
|
||||||
|
regmap_write(priv->regmap, PHY_CTRL_R21,
|
||||||
|
PHY_CTRL_R21_USB2_CAL_ACK_EN |
|
||||||
|
PHY_CTRL_R21_USB2_TX_STRG_PD |
|
||||||
|
FIELD_PREP(PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0, 2));
|
||||||
|
|
||||||
|
/* Analog Settings */
|
||||||
|
regmap_write(priv->regmap, PHY_CTRL_R13,
|
||||||
|
FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7));
|
||||||
|
}
|
||||||
|
|
||||||
/* Tuning Disconnect Threshold */
|
/* Tuning Disconnect Threshold */
|
||||||
regmap_write(priv->regmap, PHY_CTRL_R3,
|
regmap_write(priv->regmap, PHY_CTRL_R3,
|
||||||
@@ -241,11 +263,13 @@ static int phy_meson_g12a_usb2_init(struct phy *phy)
|
|||||||
FIELD_PREP(PHY_CTRL_R3_HSDIC_REF, 1) |
|
FIELD_PREP(PHY_CTRL_R3_HSDIC_REF, 1) |
|
||||||
FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3));
|
FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3));
|
||||||
|
|
||||||
/* Analog Settings */
|
if (priv->soc_id == MESON_SOC_G12A) {
|
||||||
regmap_write(priv->regmap, PHY_CTRL_R14, 0);
|
/* Analog Settings */
|
||||||
regmap_write(priv->regmap, PHY_CTRL_R13,
|
regmap_write(priv->regmap, PHY_CTRL_R14, 0);
|
||||||
PHY_CTRL_R13_UPDATE_PMA_SIGNALS |
|
regmap_write(priv->regmap, PHY_CTRL_R13,
|
||||||
FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7));
|
PHY_CTRL_R13_UPDATE_PMA_SIGNALS |
|
||||||
|
FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7));
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -286,6 +310,8 @@ static int phy_meson_g12a_usb2_probe(struct platform_device *pdev)
|
|||||||
if (IS_ERR(base))
|
if (IS_ERR(base))
|
||||||
return PTR_ERR(base);
|
return PTR_ERR(base);
|
||||||
|
|
||||||
|
priv->soc_id = (enum meson_soc_id)of_device_get_match_data(&pdev->dev);
|
||||||
|
|
||||||
priv->regmap = devm_regmap_init_mmio(dev, base,
|
priv->regmap = devm_regmap_init_mmio(dev, base,
|
||||||
&phy_meson_g12a_usb2_regmap_conf);
|
&phy_meson_g12a_usb2_regmap_conf);
|
||||||
if (IS_ERR(priv->regmap))
|
if (IS_ERR(priv->regmap))
|
||||||
@@ -321,8 +347,15 @@ static int phy_meson_g12a_usb2_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id phy_meson_g12a_usb2_of_match[] = {
|
static const struct of_device_id phy_meson_g12a_usb2_of_match[] = {
|
||||||
{ .compatible = "amlogic,g12a-usb2-phy", },
|
{
|
||||||
{ },
|
.compatible = "amlogic,g12a-usb2-phy",
|
||||||
|
.data = (void *)MESON_SOC_G12A,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "amlogic,a1-usb2-phy",
|
||||||
|
.data = (void *)MESON_SOC_A1,
|
||||||
|
},
|
||||||
|
{ /* Sentinel */ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, phy_meson_g12a_usb2_of_match);
|
MODULE_DEVICE_TABLE(of, phy_meson_g12a_usb2_of_match);
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
# Phy drivers for Cadence PHYs
|
# Phy drivers for Cadence PHYs
|
||||||
#
|
#
|
||||||
|
|
||||||
config PHY_CADENCE_DP
|
config PHY_CADENCE_TORRENT
|
||||||
tristate "Cadence MHDP DisplayPort PHY driver"
|
tristate "Cadence Torrent PHY driver"
|
||||||
depends on OF
|
depends on OF
|
||||||
depends on HAS_IOMEM
|
depends on HAS_IOMEM
|
||||||
select GENERIC_PHY
|
select GENERIC_PHY
|
||||||
help
|
help
|
||||||
Support for Cadence MHDP DisplayPort PHY.
|
Support for Cadence Torrent PHY.
|
||||||
|
|
||||||
config PHY_CADENCE_DPHY
|
config PHY_CADENCE_DPHY
|
||||||
tristate "Cadence D-PHY Support"
|
tristate "Cadence D-PHY Support"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
obj-$(CONFIG_PHY_CADENCE_DP) += phy-cadence-dp.o
|
obj-$(CONFIG_PHY_CADENCE_TORRENT) += phy-cadence-torrent.o
|
||||||
obj-$(CONFIG_PHY_CADENCE_DPHY) += cdns-dphy.o
|
obj-$(CONFIG_PHY_CADENCE_DPHY) += cdns-dphy.o
|
||||||
obj-$(CONFIG_PHY_CADENCE_SIERRA) += phy-cadence-sierra.o
|
obj-$(CONFIG_PHY_CADENCE_SIERRA) += phy-cadence-sierra.o
|
||||||
|
|||||||
@@ -1,541 +0,0 @@
|
|||||||
// 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");
|
|
||||||
1944
drivers/phy/cadence/phy-cadence-torrent.c
Normal file
1944
drivers/phy/cadence/phy-cadence-torrent.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -43,6 +43,8 @@
|
|||||||
#define PA0_RG_USB20_INTR_EN BIT(5)
|
#define PA0_RG_USB20_INTR_EN BIT(5)
|
||||||
|
|
||||||
#define U3P_USBPHYACR1 0x004
|
#define U3P_USBPHYACR1 0x004
|
||||||
|
#define PA1_RG_INTR_CAL GENMASK(23, 19)
|
||||||
|
#define PA1_RG_INTR_CAL_VAL(x) ((0x1f & (x)) << 19)
|
||||||
#define PA1_RG_VRT_SEL GENMASK(14, 12)
|
#define PA1_RG_VRT_SEL GENMASK(14, 12)
|
||||||
#define PA1_RG_VRT_SEL_VAL(x) ((0x7 & (x)) << 12)
|
#define PA1_RG_VRT_SEL_VAL(x) ((0x7 & (x)) << 12)
|
||||||
#define PA1_RG_TERM_SEL GENMASK(10, 8)
|
#define PA1_RG_TERM_SEL GENMASK(10, 8)
|
||||||
@@ -60,6 +62,8 @@
|
|||||||
#define U3P_USBPHYACR6 0x018
|
#define U3P_USBPHYACR6 0x018
|
||||||
#define PA6_RG_U2_BC11_SW_EN BIT(23)
|
#define PA6_RG_U2_BC11_SW_EN BIT(23)
|
||||||
#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20)
|
#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20)
|
||||||
|
#define PA6_RG_U2_DISCTH GENMASK(7, 4)
|
||||||
|
#define PA6_RG_U2_DISCTH_VAL(x) ((0xf & (x)) << 4)
|
||||||
#define PA6_RG_U2_SQTH GENMASK(3, 0)
|
#define PA6_RG_U2_SQTH GENMASK(3, 0)
|
||||||
#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x))
|
#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x))
|
||||||
|
|
||||||
@@ -294,20 +298,21 @@ struct mtk_phy_instance {
|
|||||||
struct u2phy_banks u2_banks;
|
struct u2phy_banks u2_banks;
|
||||||
struct u3phy_banks u3_banks;
|
struct u3phy_banks u3_banks;
|
||||||
};
|
};
|
||||||
struct clk *ref_clk; /* reference clock of anolog phy */
|
struct clk *ref_clk; /* reference clock of (digital) phy */
|
||||||
|
struct clk *da_ref_clk; /* reference clock of analog phy */
|
||||||
u32 index;
|
u32 index;
|
||||||
u8 type;
|
u8 type;
|
||||||
int eye_src;
|
int eye_src;
|
||||||
int eye_vrt;
|
int eye_vrt;
|
||||||
int eye_term;
|
int eye_term;
|
||||||
|
int intr;
|
||||||
|
int discth;
|
||||||
bool bc12_en;
|
bool bc12_en;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mtk_tphy {
|
struct mtk_tphy {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
void __iomem *sif_base; /* only shared sif */
|
void __iomem *sif_base; /* only shared sif */
|
||||||
/* deprecated, use @ref_clk instead in phy instance */
|
|
||||||
struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */
|
|
||||||
const struct mtk_phy_pdata *pdata;
|
const struct mtk_phy_pdata *pdata;
|
||||||
struct mtk_phy_instance **phys;
|
struct mtk_phy_instance **phys;
|
||||||
int nphys;
|
int nphys;
|
||||||
@@ -850,9 +855,14 @@ static void phy_parse_property(struct mtk_tphy *tphy,
|
|||||||
&instance->eye_vrt);
|
&instance->eye_vrt);
|
||||||
device_property_read_u32(dev, "mediatek,eye-term",
|
device_property_read_u32(dev, "mediatek,eye-term",
|
||||||
&instance->eye_term);
|
&instance->eye_term);
|
||||||
dev_dbg(dev, "bc12:%d, src:%d, vrt:%d, term:%d\n",
|
device_property_read_u32(dev, "mediatek,intr",
|
||||||
|
&instance->intr);
|
||||||
|
device_property_read_u32(dev, "mediatek,discth",
|
||||||
|
&instance->discth);
|
||||||
|
dev_dbg(dev, "bc12:%d, src:%d, vrt:%d, term:%d, intr:%d, disc:%d\n",
|
||||||
instance->bc12_en, instance->eye_src,
|
instance->bc12_en, instance->eye_src,
|
||||||
instance->eye_vrt, instance->eye_term);
|
instance->eye_vrt, instance->eye_term,
|
||||||
|
instance->intr, instance->discth);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void u2_phy_props_set(struct mtk_tphy *tphy,
|
static void u2_phy_props_set(struct mtk_tphy *tphy,
|
||||||
@@ -888,6 +898,20 @@ static void u2_phy_props_set(struct mtk_tphy *tphy,
|
|||||||
tmp |= PA1_RG_TERM_SEL_VAL(instance->eye_term);
|
tmp |= PA1_RG_TERM_SEL_VAL(instance->eye_term);
|
||||||
writel(tmp, com + U3P_USBPHYACR1);
|
writel(tmp, com + U3P_USBPHYACR1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (instance->intr) {
|
||||||
|
tmp = readl(com + U3P_USBPHYACR1);
|
||||||
|
tmp &= ~PA1_RG_INTR_CAL;
|
||||||
|
tmp |= PA1_RG_INTR_CAL_VAL(instance->intr);
|
||||||
|
writel(tmp, com + U3P_USBPHYACR1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance->discth) {
|
||||||
|
tmp = readl(com + U3P_USBPHYACR6);
|
||||||
|
tmp &= ~PA6_RG_U2_DISCTH;
|
||||||
|
tmp |= PA6_RG_U2_DISCTH_VAL(instance->discth);
|
||||||
|
writel(tmp, com + U3P_USBPHYACR6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mtk_phy_init(struct phy *phy)
|
static int mtk_phy_init(struct phy *phy)
|
||||||
@@ -896,18 +920,19 @@ static int mtk_phy_init(struct phy *phy)
|
|||||||
struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
|
struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = clk_prepare_enable(tphy->u3phya_ref);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(tphy->dev, "failed to enable u3phya_ref\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = clk_prepare_enable(instance->ref_clk);
|
ret = clk_prepare_enable(instance->ref_clk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(tphy->dev, "failed to enable ref_clk\n");
|
dev_err(tphy->dev, "failed to enable ref_clk\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(instance->da_ref_clk);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(tphy->dev, "failed to enable da_ref\n");
|
||||||
|
clk_disable_unprepare(instance->ref_clk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
switch (instance->type) {
|
switch (instance->type) {
|
||||||
case PHY_TYPE_USB2:
|
case PHY_TYPE_USB2:
|
||||||
u2_phy_instance_init(tphy, instance);
|
u2_phy_instance_init(tphy, instance);
|
||||||
@@ -967,7 +992,7 @@ static int mtk_phy_exit(struct phy *phy)
|
|||||||
u2_phy_instance_exit(tphy, instance);
|
u2_phy_instance_exit(tphy, instance);
|
||||||
|
|
||||||
clk_disable_unprepare(instance->ref_clk);
|
clk_disable_unprepare(instance->ref_clk);
|
||||||
clk_disable_unprepare(tphy->u3phya_ref);
|
clk_disable_unprepare(instance->da_ref_clk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1102,11 +1127,6 @@ static int mtk_tphy_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* it's deprecated, make it optional for backward compatibility */
|
|
||||||
tphy->u3phya_ref = devm_clk_get_optional(dev, "u3phya_ref");
|
|
||||||
if (IS_ERR(tphy->u3phya_ref))
|
|
||||||
return PTR_ERR(tphy->u3phya_ref);
|
|
||||||
|
|
||||||
tphy->src_ref_clk = U3P_REF_CLK;
|
tphy->src_ref_clk = U3P_REF_CLK;
|
||||||
tphy->src_coef = U3P_SLEW_RATE_COEF;
|
tphy->src_coef = U3P_SLEW_RATE_COEF;
|
||||||
/* update parameters of slew rate calibrate if exist */
|
/* update parameters of slew rate calibrate if exist */
|
||||||
@@ -1153,16 +1173,20 @@ static int mtk_tphy_probe(struct platform_device *pdev)
|
|||||||
phy_set_drvdata(phy, instance);
|
phy_set_drvdata(phy, instance);
|
||||||
port++;
|
port++;
|
||||||
|
|
||||||
/* if deprecated clock is provided, ignore instance's one */
|
instance->ref_clk = devm_clk_get_optional(&phy->dev, "ref");
|
||||||
if (tphy->u3phya_ref)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
instance->ref_clk = devm_clk_get(&phy->dev, "ref");
|
|
||||||
if (IS_ERR(instance->ref_clk)) {
|
if (IS_ERR(instance->ref_clk)) {
|
||||||
dev_err(dev, "failed to get ref_clk(id-%d)\n", port);
|
dev_err(dev, "failed to get ref_clk(id-%d)\n", port);
|
||||||
retval = PTR_ERR(instance->ref_clk);
|
retval = PTR_ERR(instance->ref_clk);
|
||||||
goto put_child;
|
goto put_child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instance->da_ref_clk =
|
||||||
|
devm_clk_get_optional(&phy->dev, "da_ref");
|
||||||
|
if (IS_ERR(instance->da_ref_clk)) {
|
||||||
|
dev_err(dev, "failed to get da_ref_clk(id-%d)\n", port);
|
||||||
|
retval = PTR_ERR(instance->da_ref_clk);
|
||||||
|
goto put_child;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);
|
provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);
|
||||||
|
|||||||
@@ -91,3 +91,23 @@ config PHY_QCOM_USB_HSIC
|
|||||||
select GENERIC_PHY
|
select GENERIC_PHY
|
||||||
help
|
help
|
||||||
Support for the USB HSIC ULPI compliant PHY on QCOM chipsets.
|
Support for the USB HSIC ULPI compliant PHY on QCOM chipsets.
|
||||||
|
|
||||||
|
config PHY_QCOM_USB_HS_28NM
|
||||||
|
tristate "Qualcomm 28nm High-Speed PHY"
|
||||||
|
depends on ARCH_QCOM || COMPILE_TEST
|
||||||
|
depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in
|
||||||
|
select GENERIC_PHY
|
||||||
|
help
|
||||||
|
Enable this to support the Qualcomm Synopsys DesignWare Core 28nm
|
||||||
|
High-Speed PHY driver. This driver supports the Hi-Speed PHY which
|
||||||
|
is usually paired with either the ChipIdea or Synopsys DWC3 USB
|
||||||
|
IPs on MSM SOCs.
|
||||||
|
|
||||||
|
config PHY_QCOM_USB_SS
|
||||||
|
tristate "Qualcomm USB Super-Speed PHY driver"
|
||||||
|
depends on ARCH_QCOM || COMPILE_TEST
|
||||||
|
depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in
|
||||||
|
select GENERIC_PHY
|
||||||
|
help
|
||||||
|
Enable this to support the Super-Speed USB transceiver on various
|
||||||
|
Qualcomm chipsets.
|
||||||
|
|||||||
@@ -10,3 +10,5 @@ obj-$(CONFIG_PHY_QCOM_UFS_14NM) += phy-qcom-ufs-qmp-14nm.o
|
|||||||
obj-$(CONFIG_PHY_QCOM_UFS_20NM) += 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
|
||||||
|
obj-$(CONFIG_PHY_QCOM_USB_HS_28NM) += phy-qcom-usb-hs-28nm.o
|
||||||
|
obj-$(CONFIG_PHY_QCOM_USB_SS) += phy-qcom-usb-ss.o
|
||||||
|
|||||||
@@ -121,6 +121,11 @@ enum qphy_reg_layout {
|
|||||||
QPHY_PCS_LFPS_RXTERM_IRQ_STATUS,
|
QPHY_PCS_LFPS_RXTERM_IRQ_STATUS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const unsigned int msm8996_ufsphy_regs_layout[] = {
|
||||||
|
[QPHY_START_CTRL] = 0x00,
|
||||||
|
[QPHY_PCS_READY_STATUS] = 0x168,
|
||||||
|
};
|
||||||
|
|
||||||
static const unsigned int pciephy_regs_layout[] = {
|
static const unsigned int pciephy_regs_layout[] = {
|
||||||
[QPHY_COM_SW_RESET] = 0x400,
|
[QPHY_COM_SW_RESET] = 0x400,
|
||||||
[QPHY_COM_POWER_DOWN_CONTROL] = 0x404,
|
[QPHY_COM_POWER_DOWN_CONTROL] = 0x404,
|
||||||
@@ -160,6 +165,18 @@ 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_qmp_pciephy_regs_layout[] = {
|
||||||
|
[QPHY_SW_RESET] = 0x00,
|
||||||
|
[QPHY_START_CTRL] = 0x08,
|
||||||
|
[QPHY_PCS_STATUS] = 0x174,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned int sdm845_qhp_pciephy_regs_layout[] = {
|
||||||
|
[QPHY_SW_RESET] = 0x00,
|
||||||
|
[QPHY_START_CTRL] = 0x08,
|
||||||
|
[QPHY_PCS_STATUS] = 0x2ac,
|
||||||
|
};
|
||||||
|
|
||||||
static const unsigned int sdm845_ufsphy_regs_layout[] = {
|
static const unsigned int sdm845_ufsphy_regs_layout[] = {
|
||||||
[QPHY_START_CTRL] = 0x00,
|
[QPHY_START_CTRL] = 0x00,
|
||||||
[QPHY_PCS_READY_STATUS] = 0x160,
|
[QPHY_PCS_READY_STATUS] = 0x160,
|
||||||
@@ -331,6 +348,75 @@ static const struct qmp_phy_init_tbl msm8998_pcie_pcs_tbl[] = {
|
|||||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_SIGDET_CNTRL, 0x03),
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_SIGDET_CNTRL, 0x03),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl msm8996_ufs_serdes_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_POWER_DOWN_CONTROL, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x0e),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0xd7),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x05),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x10),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x20),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x54),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x28),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x02),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xff),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE1, 0x98),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE1, 0x0b),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE1, 0x16),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE1, 0x28),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE1, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE1, 0x32),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE1, 0x00),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl msm8996_ufs_tx_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x02),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl msm8996_ufs_rx_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x24),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x02),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_RX_RX_INTERFACE_MODE, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x18),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_RX_RX_TERM_BW, 0x5b),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xff),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3f),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xff),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x0f),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0E),
|
||||||
|
};
|
||||||
|
|
||||||
static const struct qmp_phy_init_tbl msm8996_usb3_serdes_tbl[] = {
|
static const struct qmp_phy_init_tbl msm8996_usb3_serdes_tbl[] = {
|
||||||
QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14),
|
QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14),
|
||||||
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
|
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
|
||||||
@@ -481,6 +567,229 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_pcs_tbl[] = {
|
|||||||
QMP_PHY_INIT_CFG_L(QPHY_START_CTRL, 0x3),
|
QMP_PHY_INIT_CFG_L(QPHY_START_CTRL, 0x3),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl sdm845_qmp_pcie_serdes_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x14),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x007),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL, 0x20),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_TIMER1, 0xff),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_TIMER2, 0x3f),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_EP_DIV, 0x19),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_ENABLE1, 0x90),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x0d),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x00),
|
||||||
|
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_CMN_MODE, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x33),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_BUF_ENABLE, 0x06),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x09),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x40),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x02),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x7e),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x15),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl sdm845_qmp_pcie_tx_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x02),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x06),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl sdm845_qmp_pcie_rx_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x10),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x14),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0e),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1a),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN_HALF, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x71),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x59),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_01, 0x59),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x71),
|
||||||
|
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x40),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl sdm845_qmp_pcie_pcs_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_ENDPOINT_REFCLK_DRIVE, 0x04),
|
||||||
|
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02),
|
||||||
|
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_OSC_DTCT_ACTIONS, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB, 0x20),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK_MSB, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_PLL_LOCK_CHK_DLY_TIME, 0x73),
|
||||||
|
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0xbb),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_SIGDET_CNTRL, 0x03),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG1, 0x0d),
|
||||||
|
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG4, 0x00),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl sdm845_qmp_pcie_pcs_misc_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_OSC_DTCT_CONFIG2, 0x52),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG2, 0x10),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG4, 0x1a),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG5, 0x06),
|
||||||
|
QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_PCIE_INT_AUX_CLK_CONFIG1, 0x00),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl sdm845_qhp_pcie_serdes_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SYSCLK_EN_SEL, 0x27),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_EN_CENTER, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_PER1, 0x31),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_PER2, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_STEP_SIZE1, 0xde),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_STEP_SIZE2, 0x07),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_STEP_SIZE1_MODE1, 0x4c),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_STEP_SIZE2_MODE1, 0x06),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_BIAS_EN_CKBUFLR_EN, 0x18),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CLK_ENABLE1, 0xb0),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP1_MODE0, 0x8c),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP2_MODE0, 0x20),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP1_MODE1, 0x14),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP2_MODE1, 0x34),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CP_CTRL_MODE0, 0x06),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CP_CTRL_MODE1, 0x06),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_PLL_RCTRL_MODE0, 0x16),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_PLL_RCTRL_MODE1, 0x16),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_PLL_CCTRL_MODE0, 0x36),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_PLL_CCTRL_MODE1, 0x36),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_RESTRIM_CTRL2, 0x05),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP_EN, 0x42),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DEC_START_MODE0, 0x82),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DEC_START_MODE1, 0x68),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START1_MODE0, 0x55),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START2_MODE0, 0x55),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START3_MODE0, 0x03),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START1_MODE1, 0xab),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START2_MODE1, 0xaa),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START3_MODE1, 0x02),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_INTEGLOOP_GAIN0_MODE1, 0x3f),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_VCO_TUNE_MAP, 0x10),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CLK_SELECT, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_HSCLK_SEL1, 0x30),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CORECLK_DIV, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CORE_CLK_EN, 0x73),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CMN_CONFIG, 0x0c),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SVS_MODE_CLK_SEL, 0x15),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CORECLK_DIV_MODE1, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CMN_MODE, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_VREGCLK_DIV1, 0x22),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_VREGCLK_DIV2, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_BGV_TRIM, 0x20),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_BG_CTRL, 0x07),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl sdm845_qhp_pcie_tx_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DRVR_CTRL0, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DRVR_TAP_EN, 0x0d),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_TX_BAND_MODE, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_LANE_MODE, 0x1a),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PARALLEL_RATE, 0x2f),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CML_CTRL_MODE0, 0x09),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CML_CTRL_MODE1, 0x09),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CML_CTRL_MODE2, 0x1b),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PREAMP_CTRL_MODE1, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PREAMP_CTRL_MODE2, 0x07),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE0, 0x31),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE1, 0x31),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE2, 0x03),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CTLE_THRESH_DFE, 0x02),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CGA_THRESH_DFE, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RXENGINE_EN0, 0x12),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CTLE_TRAIN_TIME, 0x25),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CTLE_DFE_OVRLP_TIME, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DFE_REFRESH_TIME, 0x05),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DFE_ENABLE_TIME, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_VGA_GAIN, 0x26),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DFE_GAIN, 0x12),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_EQ_GAIN, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_OFFSET_GAIN, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PRE_GAIN, 0x09),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_EQ_INTVAL, 0x15),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_EDAC_INITVAL, 0x28),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RXEQ_INITB0, 0x7f),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RXEQ_INITB1, 0x07),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RCVRDONE_THRESH1, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RXEQ_CTRL, 0x70),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE0, 0x8b),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE1, 0x08),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE2, 0x0a),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE0, 0x03),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE1, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE2, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_SO_CONFIG, 0x0c),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_BAND, 0x02),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE0, 0x5c),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE1, 0x3e),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE2, 0x3f),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_SIGDET_ENABLES, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_SIGDET_CNTRL, 0xa0),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_SIGDET_DEGLITCH_CNTRL, 0x08),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DCC_GAIN, 0x01),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_EN_SIGNAL, 0xc3),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PSM_RX_EN_CAL, 0x00),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_MISC_CNTRL0, 0xbc),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_TS0_TIMER, 0x7f),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DLL_HIGHDATARATE, 0x15),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DRVR_CTRL1, 0x0c),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DRVR_CTRL2, 0x0f),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_RESETCODE_OFFSET, 0x04),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_VGA_INITVAL, 0x20),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RSM_START, 0x01),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl sdm845_qhp_pcie_rx_tbl[] = {
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_init_tbl sdm845_qhp_pcie_pcs_tbl[] = {
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG, 0x3f),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_PCS_TX_RX_CONFIG, 0x50),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_TXMGN_MAIN_V0_M3P5DB, 0x19),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_TXMGN_POST_V0_M3P5DB, 0x07),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_TXMGN_MAIN_V0_M6DB, 0x17),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_TXMGN_POST_V0_M6DB, 0x09),
|
||||||
|
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG5, 0x9f),
|
||||||
|
};
|
||||||
|
|
||||||
static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = {
|
static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = {
|
||||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07),
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07),
|
||||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14),
|
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14),
|
||||||
@@ -988,6 +1297,8 @@ struct qmp_phy_cfg {
|
|||||||
int rx_tbl_num;
|
int rx_tbl_num;
|
||||||
const struct qmp_phy_init_tbl *pcs_tbl;
|
const struct qmp_phy_init_tbl *pcs_tbl;
|
||||||
int pcs_tbl_num;
|
int pcs_tbl_num;
|
||||||
|
const struct qmp_phy_init_tbl *pcs_misc_tbl;
|
||||||
|
int pcs_misc_tbl_num;
|
||||||
|
|
||||||
/* clock ids to be requested */
|
/* clock ids to be requested */
|
||||||
const char * const *clk_list;
|
const char * const *clk_list;
|
||||||
@@ -1122,10 +1433,18 @@ static const char * const msm8996_phy_clk_l[] = {
|
|||||||
"aux", "cfg_ahb", "ref",
|
"aux", "cfg_ahb", "ref",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char * const msm8996_ufs_phy_clk_l[] = {
|
||||||
|
"ref",
|
||||||
|
};
|
||||||
|
|
||||||
static const char * const qmp_v3_phy_clk_l[] = {
|
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_pciephy_clk_l[] = {
|
||||||
|
"aux", "cfg_ahb", "ref", "refgen",
|
||||||
|
};
|
||||||
|
|
||||||
static const char * const sdm845_ufs_phy_clk_l[] = {
|
static const char * const sdm845_ufs_phy_clk_l[] = {
|
||||||
"ref", "ref_aux",
|
"ref", "ref_aux",
|
||||||
};
|
};
|
||||||
@@ -1139,6 +1458,10 @@ static const char * const msm8996_usb3phy_reset_l[] = {
|
|||||||
"phy", "common",
|
"phy", "common",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char * const sdm845_pciephy_reset_l[] = {
|
||||||
|
"phy",
|
||||||
|
};
|
||||||
|
|
||||||
/* list of regulators */
|
/* list of regulators */
|
||||||
static const char * const qmp_phy_vreg_l[] = {
|
static const char * const qmp_phy_vreg_l[] = {
|
||||||
"vdda-phy", "vdda-pll",
|
"vdda-phy", "vdda-pll",
|
||||||
@@ -1175,6 +1498,31 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = {
|
|||||||
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
|
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_cfg msm8996_ufs_cfg = {
|
||||||
|
.type = PHY_TYPE_UFS,
|
||||||
|
.nlanes = 1,
|
||||||
|
|
||||||
|
.serdes_tbl = msm8996_ufs_serdes_tbl,
|
||||||
|
.serdes_tbl_num = ARRAY_SIZE(msm8996_ufs_serdes_tbl),
|
||||||
|
.tx_tbl = msm8996_ufs_tx_tbl,
|
||||||
|
.tx_tbl_num = ARRAY_SIZE(msm8996_ufs_tx_tbl),
|
||||||
|
.rx_tbl = msm8996_ufs_rx_tbl,
|
||||||
|
.rx_tbl_num = ARRAY_SIZE(msm8996_ufs_rx_tbl),
|
||||||
|
|
||||||
|
.clk_list = msm8996_ufs_phy_clk_l,
|
||||||
|
.num_clks = ARRAY_SIZE(msm8996_ufs_phy_clk_l),
|
||||||
|
|
||||||
|
.vreg_list = qmp_phy_vreg_l,
|
||||||
|
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||||
|
|
||||||
|
.regs = msm8996_ufsphy_regs_layout,
|
||||||
|
|
||||||
|
.start_ctrl = SERDES_START,
|
||||||
|
.pwrdn_ctrl = SW_PWRDN,
|
||||||
|
|
||||||
|
.no_pcs_sw_reset = true,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
|
static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
|
||||||
.type = PHY_TYPE_USB3,
|
.type = PHY_TYPE_USB3,
|
||||||
.nlanes = 1,
|
.nlanes = 1,
|
||||||
@@ -1234,6 +1582,64 @@ static const struct qmp_phy_cfg ipq8074_pciephy_cfg = {
|
|||||||
.pwrdn_delay_max = 1005, /* us */
|
.pwrdn_delay_max = 1005, /* us */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_cfg sdm845_qmp_pciephy_cfg = {
|
||||||
|
.type = PHY_TYPE_PCIE,
|
||||||
|
.nlanes = 1,
|
||||||
|
|
||||||
|
.serdes_tbl = sdm845_qmp_pcie_serdes_tbl,
|
||||||
|
.serdes_tbl_num = ARRAY_SIZE(sdm845_qmp_pcie_serdes_tbl),
|
||||||
|
.tx_tbl = sdm845_qmp_pcie_tx_tbl,
|
||||||
|
.tx_tbl_num = ARRAY_SIZE(sdm845_qmp_pcie_tx_tbl),
|
||||||
|
.rx_tbl = sdm845_qmp_pcie_rx_tbl,
|
||||||
|
.rx_tbl_num = ARRAY_SIZE(sdm845_qmp_pcie_rx_tbl),
|
||||||
|
.pcs_tbl = sdm845_qmp_pcie_pcs_tbl,
|
||||||
|
.pcs_tbl_num = ARRAY_SIZE(sdm845_qmp_pcie_pcs_tbl),
|
||||||
|
.pcs_misc_tbl = sdm845_qmp_pcie_pcs_misc_tbl,
|
||||||
|
.pcs_misc_tbl_num = ARRAY_SIZE(sdm845_qmp_pcie_pcs_misc_tbl),
|
||||||
|
.clk_list = sdm845_pciephy_clk_l,
|
||||||
|
.num_clks = ARRAY_SIZE(sdm845_pciephy_clk_l),
|
||||||
|
.reset_list = sdm845_pciephy_reset_l,
|
||||||
|
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
|
||||||
|
.vreg_list = qmp_phy_vreg_l,
|
||||||
|
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||||
|
.regs = sdm845_qmp_pciephy_regs_layout,
|
||||||
|
|
||||||
|
.start_ctrl = PCS_START | SERDES_START,
|
||||||
|
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
|
||||||
|
|
||||||
|
.has_pwrdn_delay = true,
|
||||||
|
.pwrdn_delay_min = 995, /* us */
|
||||||
|
.pwrdn_delay_max = 1005, /* us */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qmp_phy_cfg sdm845_qhp_pciephy_cfg = {
|
||||||
|
.type = PHY_TYPE_PCIE,
|
||||||
|
.nlanes = 1,
|
||||||
|
|
||||||
|
.serdes_tbl = sdm845_qhp_pcie_serdes_tbl,
|
||||||
|
.serdes_tbl_num = ARRAY_SIZE(sdm845_qhp_pcie_serdes_tbl),
|
||||||
|
.tx_tbl = sdm845_qhp_pcie_tx_tbl,
|
||||||
|
.tx_tbl_num = ARRAY_SIZE(sdm845_qhp_pcie_tx_tbl),
|
||||||
|
.rx_tbl = sdm845_qhp_pcie_rx_tbl,
|
||||||
|
.rx_tbl_num = ARRAY_SIZE(sdm845_qhp_pcie_rx_tbl),
|
||||||
|
.pcs_tbl = sdm845_qhp_pcie_pcs_tbl,
|
||||||
|
.pcs_tbl_num = ARRAY_SIZE(sdm845_qhp_pcie_pcs_tbl),
|
||||||
|
.clk_list = sdm845_pciephy_clk_l,
|
||||||
|
.num_clks = ARRAY_SIZE(sdm845_pciephy_clk_l),
|
||||||
|
.reset_list = sdm845_pciephy_reset_l,
|
||||||
|
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
|
||||||
|
.vreg_list = qmp_phy_vreg_l,
|
||||||
|
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||||
|
.regs = sdm845_qhp_pciephy_regs_layout,
|
||||||
|
|
||||||
|
.start_ctrl = PCS_START | SERDES_START,
|
||||||
|
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
|
||||||
|
|
||||||
|
.has_pwrdn_delay = true,
|
||||||
|
.pwrdn_delay_min = 995, /* us */
|
||||||
|
.pwrdn_delay_max = 1005, /* us */
|
||||||
|
};
|
||||||
|
|
||||||
static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
|
static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
|
||||||
.type = PHY_TYPE_USB3,
|
.type = PHY_TYPE_USB3,
|
||||||
.nlanes = 1,
|
.nlanes = 1,
|
||||||
@@ -1563,6 +1969,7 @@ static int qcom_qmp_phy_enable(struct phy *phy)
|
|||||||
void __iomem *tx = qphy->tx;
|
void __iomem *tx = qphy->tx;
|
||||||
void __iomem *rx = qphy->rx;
|
void __iomem *rx = qphy->rx;
|
||||||
void __iomem *pcs = qphy->pcs;
|
void __iomem *pcs = qphy->pcs;
|
||||||
|
void __iomem *pcs_misc = qphy->pcs_misc;
|
||||||
void __iomem *dp_com = qmp->dp_com;
|
void __iomem *dp_com = qmp->dp_com;
|
||||||
void __iomem *status;
|
void __iomem *status;
|
||||||
unsigned int mask, val, ready;
|
unsigned int mask, val, ready;
|
||||||
@@ -1633,6 +2040,9 @@ static int qcom_qmp_phy_enable(struct phy *phy)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_lane_rst;
|
goto err_lane_rst;
|
||||||
|
|
||||||
|
qcom_qmp_phy_configure(pcs_misc, cfg->regs, cfg->pcs_misc_tbl,
|
||||||
|
cfg->pcs_misc_tbl_num);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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.
|
||||||
@@ -1967,7 +2377,7 @@ static const struct phy_ops qcom_qmp_phy_gen_ops = {
|
|||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct phy_ops qcom_qmp_ufs_ops = {
|
static const struct phy_ops qcom_qmp_pcie_ufs_ops = {
|
||||||
.power_on = qcom_qmp_phy_enable,
|
.power_on = qcom_qmp_phy_enable,
|
||||||
.power_off = qcom_qmp_phy_disable,
|
.power_off = qcom_qmp_phy_disable,
|
||||||
.set_mode = qcom_qmp_phy_set_mode,
|
.set_mode = qcom_qmp_phy_set_mode,
|
||||||
@@ -2067,8 +2477,8 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qmp->cfg->type == PHY_TYPE_UFS)
|
if (qmp->cfg->type == PHY_TYPE_UFS || qmp->cfg->type == PHY_TYPE_PCIE)
|
||||||
ops = &qcom_qmp_ufs_ops;
|
ops = &qcom_qmp_pcie_ufs_ops;
|
||||||
|
|
||||||
generic_phy = devm_phy_create(dev, np, ops);
|
generic_phy = devm_phy_create(dev, np, ops);
|
||||||
if (IS_ERR(generic_phy)) {
|
if (IS_ERR(generic_phy)) {
|
||||||
@@ -2090,6 +2500,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
|
|||||||
{
|
{
|
||||||
.compatible = "qcom,msm8996-qmp-pcie-phy",
|
.compatible = "qcom,msm8996-qmp-pcie-phy",
|
||||||
.data = &msm8996_pciephy_cfg,
|
.data = &msm8996_pciephy_cfg,
|
||||||
|
}, {
|
||||||
|
.compatible = "qcom,msm8996-qmp-ufs-phy",
|
||||||
|
.data = &msm8996_ufs_cfg,
|
||||||
}, {
|
}, {
|
||||||
.compatible = "qcom,msm8996-qmp-usb3-phy",
|
.compatible = "qcom,msm8996-qmp-usb3-phy",
|
||||||
.data = &msm8996_usb3phy_cfg,
|
.data = &msm8996_usb3phy_cfg,
|
||||||
@@ -2102,6 +2515,12 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
|
|||||||
}, {
|
}, {
|
||||||
.compatible = "qcom,ipq8074-qmp-pcie-phy",
|
.compatible = "qcom,ipq8074-qmp-pcie-phy",
|
||||||
.data = &ipq8074_pciephy_cfg,
|
.data = &ipq8074_pciephy_cfg,
|
||||||
|
}, {
|
||||||
|
.compatible = "qcom,sdm845-qhp-pcie-phy",
|
||||||
|
.data = &sdm845_qhp_pciephy_cfg,
|
||||||
|
}, {
|
||||||
|
.compatible = "qcom,sdm845-qmp-pcie-phy",
|
||||||
|
.data = &sdm845_qmp_pciephy_cfg,
|
||||||
}, {
|
}, {
|
||||||
.compatible = "qcom,sdm845-qmp-usb3-phy",
|
.compatible = "qcom,sdm845-qmp-usb3-phy",
|
||||||
.data = &qmp_v3_usb3phy_cfg,
|
.data = &qmp_v3_usb3phy_cfg,
|
||||||
|
|||||||
@@ -409,4 +409,118 @@
|
|||||||
#define QPHY_V4_TX_MID_TERM_CTRL1 0x1d8
|
#define QPHY_V4_TX_MID_TERM_CTRL1 0x1d8
|
||||||
#define QPHY_V4_MULTI_LANE_CTRL1 0x1e0
|
#define QPHY_V4_MULTI_LANE_CTRL1 0x1e0
|
||||||
|
|
||||||
|
/* PCIE GEN3 COM registers */
|
||||||
|
#define PCIE_GEN3_QHP_COM_SSC_EN_CENTER 0x14
|
||||||
|
#define PCIE_GEN3_QHP_COM_SSC_PER1 0x20
|
||||||
|
#define PCIE_GEN3_QHP_COM_SSC_PER2 0x24
|
||||||
|
#define PCIE_GEN3_QHP_COM_SSC_STEP_SIZE1 0x28
|
||||||
|
#define PCIE_GEN3_QHP_COM_SSC_STEP_SIZE2 0x2c
|
||||||
|
#define PCIE_GEN3_QHP_COM_SSC_STEP_SIZE1_MODE1 0x34
|
||||||
|
#define PCIE_GEN3_QHP_COM_SSC_STEP_SIZE2_MODE1 0x38
|
||||||
|
#define PCIE_GEN3_QHP_COM_BIAS_EN_CKBUFLR_EN 0x54
|
||||||
|
#define PCIE_GEN3_QHP_COM_CLK_ENABLE1 0x58
|
||||||
|
#define PCIE_GEN3_QHP_COM_LOCK_CMP1_MODE0 0x6c
|
||||||
|
#define PCIE_GEN3_QHP_COM_LOCK_CMP2_MODE0 0x70
|
||||||
|
#define PCIE_GEN3_QHP_COM_LOCK_CMP1_MODE1 0x78
|
||||||
|
#define PCIE_GEN3_QHP_COM_LOCK_CMP2_MODE1 0x7c
|
||||||
|
#define PCIE_GEN3_QHP_COM_BGV_TRIM 0x98
|
||||||
|
#define PCIE_GEN3_QHP_COM_CP_CTRL_MODE0 0xb4
|
||||||
|
#define PCIE_GEN3_QHP_COM_CP_CTRL_MODE1 0xb8
|
||||||
|
#define PCIE_GEN3_QHP_COM_PLL_RCTRL_MODE0 0xc0
|
||||||
|
#define PCIE_GEN3_QHP_COM_PLL_RCTRL_MODE1 0xc4
|
||||||
|
#define PCIE_GEN3_QHP_COM_PLL_CCTRL_MODE0 0xcc
|
||||||
|
#define PCIE_GEN3_QHP_COM_PLL_CCTRL_MODE1 0xd0
|
||||||
|
#define PCIE_GEN3_QHP_COM_SYSCLK_EN_SEL 0xdc
|
||||||
|
#define PCIE_GEN3_QHP_COM_RESTRIM_CTRL2 0xf0
|
||||||
|
#define PCIE_GEN3_QHP_COM_LOCK_CMP_EN 0xf8
|
||||||
|
#define PCIE_GEN3_QHP_COM_DEC_START_MODE0 0x100
|
||||||
|
#define PCIE_GEN3_QHP_COM_DEC_START_MODE1 0x108
|
||||||
|
#define PCIE_GEN3_QHP_COM_DIV_FRAC_START1_MODE0 0x11c
|
||||||
|
#define PCIE_GEN3_QHP_COM_DIV_FRAC_START2_MODE0 0x120
|
||||||
|
#define PCIE_GEN3_QHP_COM_DIV_FRAC_START3_MODE0 0x124
|
||||||
|
#define PCIE_GEN3_QHP_COM_DIV_FRAC_START1_MODE1 0x128
|
||||||
|
#define PCIE_GEN3_QHP_COM_DIV_FRAC_START2_MODE1 0x12c
|
||||||
|
#define PCIE_GEN3_QHP_COM_DIV_FRAC_START3_MODE1 0x130
|
||||||
|
#define PCIE_GEN3_QHP_COM_INTEGLOOP_GAIN0_MODE0 0x150
|
||||||
|
#define PCIE_GEN3_QHP_COM_INTEGLOOP_GAIN0_MODE1 0x158
|
||||||
|
#define PCIE_GEN3_QHP_COM_VCO_TUNE_MAP 0x178
|
||||||
|
#define PCIE_GEN3_QHP_COM_BG_CTRL 0x1c8
|
||||||
|
#define PCIE_GEN3_QHP_COM_CLK_SELECT 0x1cc
|
||||||
|
#define PCIE_GEN3_QHP_COM_HSCLK_SEL1 0x1d0
|
||||||
|
#define PCIE_GEN3_QHP_COM_CORECLK_DIV 0x1e0
|
||||||
|
#define PCIE_GEN3_QHP_COM_CORE_CLK_EN 0x1e8
|
||||||
|
#define PCIE_GEN3_QHP_COM_CMN_CONFIG 0x1f0
|
||||||
|
#define PCIE_GEN3_QHP_COM_SVS_MODE_CLK_SEL 0x1fc
|
||||||
|
#define PCIE_GEN3_QHP_COM_CORECLK_DIV_MODE1 0x21c
|
||||||
|
#define PCIE_GEN3_QHP_COM_CMN_MODE 0x224
|
||||||
|
#define PCIE_GEN3_QHP_COM_VREGCLK_DIV1 0x228
|
||||||
|
#define PCIE_GEN3_QHP_COM_VREGCLK_DIV2 0x22c
|
||||||
|
|
||||||
|
/* PCIE GEN3 QHP Lane registers */
|
||||||
|
#define PCIE_GEN3_QHP_L0_DRVR_CTRL0 0xc
|
||||||
|
#define PCIE_GEN3_QHP_L0_DRVR_CTRL1 0x10
|
||||||
|
#define PCIE_GEN3_QHP_L0_DRVR_CTRL2 0x14
|
||||||
|
#define PCIE_GEN3_QHP_L0_DRVR_TAP_EN 0x18
|
||||||
|
#define PCIE_GEN3_QHP_L0_TX_BAND_MODE 0x60
|
||||||
|
#define PCIE_GEN3_QHP_L0_LANE_MODE 0x64
|
||||||
|
#define PCIE_GEN3_QHP_L0_PARALLEL_RATE 0x7c
|
||||||
|
#define PCIE_GEN3_QHP_L0_CML_CTRL_MODE0 0xc0
|
||||||
|
#define PCIE_GEN3_QHP_L0_CML_CTRL_MODE1 0xc4
|
||||||
|
#define PCIE_GEN3_QHP_L0_CML_CTRL_MODE2 0xc8
|
||||||
|
#define PCIE_GEN3_QHP_L0_PREAMP_CTRL_MODE1 0xd0
|
||||||
|
#define PCIE_GEN3_QHP_L0_PREAMP_CTRL_MODE2 0xd4
|
||||||
|
#define PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE0 0xd8
|
||||||
|
#define PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE1 0xdc
|
||||||
|
#define PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE2 0xe0
|
||||||
|
#define PCIE_GEN3_QHP_L0_CTLE_THRESH_DFE 0xfc
|
||||||
|
#define PCIE_GEN3_QHP_L0_CGA_THRESH_DFE 0x100
|
||||||
|
#define PCIE_GEN3_QHP_L0_RXENGINE_EN0 0x108
|
||||||
|
#define PCIE_GEN3_QHP_L0_CTLE_TRAIN_TIME 0x114
|
||||||
|
#define PCIE_GEN3_QHP_L0_CTLE_DFE_OVRLP_TIME 0x118
|
||||||
|
#define PCIE_GEN3_QHP_L0_DFE_REFRESH_TIME 0x11c
|
||||||
|
#define PCIE_GEN3_QHP_L0_DFE_ENABLE_TIME 0x120
|
||||||
|
#define PCIE_GEN3_QHP_L0_VGA_GAIN 0x124
|
||||||
|
#define PCIE_GEN3_QHP_L0_DFE_GAIN 0x128
|
||||||
|
#define PCIE_GEN3_QHP_L0_EQ_GAIN 0x130
|
||||||
|
#define PCIE_GEN3_QHP_L0_OFFSET_GAIN 0x134
|
||||||
|
#define PCIE_GEN3_QHP_L0_PRE_GAIN 0x138
|
||||||
|
#define PCIE_GEN3_QHP_L0_VGA_INITVAL 0x13c
|
||||||
|
#define PCIE_GEN3_QHP_L0_EQ_INTVAL 0x154
|
||||||
|
#define PCIE_GEN3_QHP_L0_EDAC_INITVAL 0x160
|
||||||
|
#define PCIE_GEN3_QHP_L0_RXEQ_INITB0 0x168
|
||||||
|
#define PCIE_GEN3_QHP_L0_RXEQ_INITB1 0x16c
|
||||||
|
#define PCIE_GEN3_QHP_L0_RCVRDONE_THRESH1 0x178
|
||||||
|
#define PCIE_GEN3_QHP_L0_RXEQ_CTRL 0x180
|
||||||
|
#define PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE0 0x184
|
||||||
|
#define PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE1 0x188
|
||||||
|
#define PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE2 0x18c
|
||||||
|
#define PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE0 0x190
|
||||||
|
#define PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE1 0x194
|
||||||
|
#define PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE2 0x198
|
||||||
|
#define PCIE_GEN3_QHP_L0_UCDR_SO_CONFIG 0x19c
|
||||||
|
#define PCIE_GEN3_QHP_L0_RX_BAND 0x1a4
|
||||||
|
#define PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE0 0x1c0
|
||||||
|
#define PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE1 0x1c4
|
||||||
|
#define PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE2 0x1c8
|
||||||
|
#define PCIE_GEN3_QHP_L0_SIGDET_ENABLES 0x230
|
||||||
|
#define PCIE_GEN3_QHP_L0_SIGDET_CNTRL 0x234
|
||||||
|
#define PCIE_GEN3_QHP_L0_SIGDET_DEGLITCH_CNTRL 0x238
|
||||||
|
#define PCIE_GEN3_QHP_L0_DCC_GAIN 0x2a4
|
||||||
|
#define PCIE_GEN3_QHP_L0_RSM_START 0x2a8
|
||||||
|
#define PCIE_GEN3_QHP_L0_RX_EN_SIGNAL 0x2ac
|
||||||
|
#define PCIE_GEN3_QHP_L0_PSM_RX_EN_CAL 0x2b0
|
||||||
|
#define PCIE_GEN3_QHP_L0_RX_MISC_CNTRL0 0x2b8
|
||||||
|
#define PCIE_GEN3_QHP_L0_TS0_TIMER 0x2c0
|
||||||
|
#define PCIE_GEN3_QHP_L0_DLL_HIGHDATARATE 0x2c4
|
||||||
|
#define PCIE_GEN3_QHP_L0_RX_RESETCODE_OFFSET 0x2cc
|
||||||
|
|
||||||
|
/* PCIE GEN3 PCS registers */
|
||||||
|
#define PCIE_GEN3_QHP_PHY_TXMGN_MAIN_V0_M3P5DB 0x2c
|
||||||
|
#define PCIE_GEN3_QHP_PHY_TXMGN_POST_V0_M3P5DB 0x40
|
||||||
|
#define PCIE_GEN3_QHP_PHY_TXMGN_MAIN_V0_M6DB 0x54
|
||||||
|
#define PCIE_GEN3_QHP_PHY_TXMGN_POST_V0_M6DB 0x68
|
||||||
|
#define PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG 0x15c
|
||||||
|
#define PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG5 0x16c
|
||||||
|
#define PCIE_GEN3_QHP_PHY_PCS_TX_RX_CONFIG 0x174
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2017, 2019, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
@@ -66,6 +66,14 @@
|
|||||||
#define IMP_RES_OFFSET_MASK GENMASK(5, 0)
|
#define IMP_RES_OFFSET_MASK GENMASK(5, 0)
|
||||||
#define IMP_RES_OFFSET_SHIFT 0x0
|
#define IMP_RES_OFFSET_SHIFT 0x0
|
||||||
|
|
||||||
|
/* QUSB2PHY_PLL_BIAS_CONTROL_2 register bits */
|
||||||
|
#define BIAS_CTRL2_RES_OFFSET_MASK GENMASK(5, 0)
|
||||||
|
#define BIAS_CTRL2_RES_OFFSET_SHIFT 0x0
|
||||||
|
|
||||||
|
/* QUSB2PHY_CHG_CONTROL_2 register bits */
|
||||||
|
#define CHG_CTRL2_OFFSET_MASK GENMASK(5, 4)
|
||||||
|
#define CHG_CTRL2_OFFSET_SHIFT 0x4
|
||||||
|
|
||||||
/* QUSB2PHY_PORT_TUNE1 register bits */
|
/* QUSB2PHY_PORT_TUNE1 register bits */
|
||||||
#define HSTX_TRIM_MASK GENMASK(7, 4)
|
#define HSTX_TRIM_MASK GENMASK(7, 4)
|
||||||
#define HSTX_TRIM_SHIFT 0x4
|
#define HSTX_TRIM_SHIFT 0x4
|
||||||
@@ -73,6 +81,10 @@
|
|||||||
#define PREEMPHASIS_EN_MASK GENMASK(1, 0)
|
#define PREEMPHASIS_EN_MASK GENMASK(1, 0)
|
||||||
#define PREEMPHASIS_EN_SHIFT 0x0
|
#define PREEMPHASIS_EN_SHIFT 0x0
|
||||||
|
|
||||||
|
/* QUSB2PHY_PORT_TUNE2 register bits */
|
||||||
|
#define HSDISC_TRIM_MASK GENMASK(1, 0)
|
||||||
|
#define HSDISC_TRIM_SHIFT 0x0
|
||||||
|
|
||||||
#define QUSB2PHY_PLL_ANALOG_CONTROLS_TWO 0x04
|
#define QUSB2PHY_PLL_ANALOG_CONTROLS_TWO 0x04
|
||||||
#define QUSB2PHY_PLL_CLOCK_INVERTERS 0x18c
|
#define QUSB2PHY_PLL_CLOCK_INVERTERS 0x18c
|
||||||
#define QUSB2PHY_PLL_CMODE 0x2c
|
#define QUSB2PHY_PLL_CMODE 0x2c
|
||||||
@@ -177,7 +189,7 @@ static const struct qusb2_phy_init_tbl msm8998_init_tbl[] = {
|
|||||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19),
|
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19),
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned int sdm845_regs_layout[] = {
|
static const unsigned int qusb2_v2_regs_layout[] = {
|
||||||
[QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8,
|
[QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8,
|
||||||
[QUSB2PHY_PLL_STATUS] = 0x1a0,
|
[QUSB2PHY_PLL_STATUS] = 0x1a0,
|
||||||
[QUSB2PHY_PORT_TUNE1] = 0x240,
|
[QUSB2PHY_PORT_TUNE1] = 0x240,
|
||||||
@@ -191,7 +203,7 @@ static const unsigned int sdm845_regs_layout[] = {
|
|||||||
[QUSB2PHY_INTR_CTRL] = 0x230,
|
[QUSB2PHY_INTR_CTRL] = 0x230,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct qusb2_phy_init_tbl sdm845_init_tbl[] = {
|
static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = {
|
||||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x03),
|
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x03),
|
||||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c),
|
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c),
|
||||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80),
|
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80),
|
||||||
@@ -258,10 +270,10 @@ static const struct qusb2_phy_cfg msm8998_phy_cfg = {
|
|||||||
.update_tune1_with_efuse = true,
|
.update_tune1_with_efuse = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct qusb2_phy_cfg sdm845_phy_cfg = {
|
static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {
|
||||||
.tbl = sdm845_init_tbl,
|
.tbl = qusb2_v2_init_tbl,
|
||||||
.tbl_num = ARRAY_SIZE(sdm845_init_tbl),
|
.tbl_num = ARRAY_SIZE(qusb2_v2_init_tbl),
|
||||||
.regs = sdm845_regs_layout,
|
.regs = qusb2_v2_regs_layout,
|
||||||
|
|
||||||
.disable_ctrl = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN |
|
.disable_ctrl = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN |
|
||||||
POWER_DOWN),
|
POWER_DOWN),
|
||||||
@@ -277,6 +289,34 @@ static const char * const qusb2_phy_vreg_names[] = {
|
|||||||
|
|
||||||
#define QUSB2_NUM_VREGS ARRAY_SIZE(qusb2_phy_vreg_names)
|
#define QUSB2_NUM_VREGS ARRAY_SIZE(qusb2_phy_vreg_names)
|
||||||
|
|
||||||
|
/* struct override_param - structure holding qusb2 v2 phy overriding param
|
||||||
|
* set override true if the device tree property exists and read and assign
|
||||||
|
* to value
|
||||||
|
*/
|
||||||
|
struct override_param {
|
||||||
|
bool override;
|
||||||
|
u8 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*struct override_params - structure holding qusb2 v2 phy overriding params
|
||||||
|
* @imp_res_offset: rescode offset to be updated in IMP_CTRL1 register
|
||||||
|
* @hstx_trim: HSTX_TRIM to be updated in TUNE1 register
|
||||||
|
* @preemphasis: Amplitude Pre-Emphasis to be updated in TUNE1 register
|
||||||
|
* @preemphasis_width: half/full-width Pre-Emphasis updated via TUNE1
|
||||||
|
* @bias_ctrl: bias ctrl to be updated in BIAS_CONTROL_2 register
|
||||||
|
* @charge_ctrl: charge ctrl to be updated in CHG_CTRL2 register
|
||||||
|
* @hsdisc_trim: disconnect threshold to be updated in TUNE2 register
|
||||||
|
*/
|
||||||
|
struct override_params {
|
||||||
|
struct override_param imp_res_offset;
|
||||||
|
struct override_param hstx_trim;
|
||||||
|
struct override_param preemphasis;
|
||||||
|
struct override_param preemphasis_width;
|
||||||
|
struct override_param bias_ctrl;
|
||||||
|
struct override_param charge_ctrl;
|
||||||
|
struct override_param hsdisc_trim;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct qusb2_phy - structure holding qusb2 phy attributes
|
* struct qusb2_phy - structure holding qusb2 phy attributes
|
||||||
*
|
*
|
||||||
@@ -292,14 +332,7 @@ static const char * const qusb2_phy_vreg_names[] = {
|
|||||||
* @tcsr: TCSR syscon register map
|
* @tcsr: TCSR syscon register map
|
||||||
* @cell: nvmem cell containing phy tuning value
|
* @cell: nvmem cell containing phy tuning value
|
||||||
*
|
*
|
||||||
* @override_imp_res_offset: PHY should use different rescode offset
|
* @overrides: pointer to structure for all overriding tuning params
|
||||||
* @imp_res_offset_value: rescode offset to be updated in IMP_CTRL1 register
|
|
||||||
* @override_hstx_trim: PHY should use different HSTX o/p current value
|
|
||||||
* @hstx_trim_value: HSTX_TRIM value to be updated in TUNE1 register
|
|
||||||
* @override_preemphasis: PHY should use different pre-amphasis amplitude
|
|
||||||
* @preemphasis_level: Amplitude Pre-Emphasis to be updated in TUNE1 register
|
|
||||||
* @override_preemphasis_width: PHY should use different pre-emphasis duration
|
|
||||||
* @preemphasis_width: half/full-width Pre-Emphasis updated via TUNE1
|
|
||||||
*
|
*
|
||||||
* @cfg: phy config data
|
* @cfg: phy config data
|
||||||
* @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme
|
* @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme
|
||||||
@@ -319,14 +352,7 @@ struct qusb2_phy {
|
|||||||
struct regmap *tcsr;
|
struct regmap *tcsr;
|
||||||
struct nvmem_cell *cell;
|
struct nvmem_cell *cell;
|
||||||
|
|
||||||
bool override_imp_res_offset;
|
struct override_params overrides;
|
||||||
u8 imp_res_offset_value;
|
|
||||||
bool override_hstx_trim;
|
|
||||||
u8 hstx_trim_value;
|
|
||||||
bool override_preemphasis;
|
|
||||||
u8 preemphasis_level;
|
|
||||||
bool override_preemphasis_width;
|
|
||||||
u8 preemphasis_width;
|
|
||||||
|
|
||||||
const struct qusb2_phy_cfg *cfg;
|
const struct qusb2_phy_cfg *cfg;
|
||||||
bool has_se_clk_scheme;
|
bool has_se_clk_scheme;
|
||||||
@@ -394,24 +420,35 @@ void qcom_qusb2_phy_configure(void __iomem *base,
|
|||||||
static void qusb2_phy_override_phy_params(struct qusb2_phy *qphy)
|
static void qusb2_phy_override_phy_params(struct qusb2_phy *qphy)
|
||||||
{
|
{
|
||||||
const struct qusb2_phy_cfg *cfg = qphy->cfg;
|
const struct qusb2_phy_cfg *cfg = qphy->cfg;
|
||||||
|
struct override_params *or = &qphy->overrides;
|
||||||
|
|
||||||
if (qphy->override_imp_res_offset)
|
if (or->imp_res_offset.override)
|
||||||
qusb2_write_mask(qphy->base, QUSB2PHY_IMP_CTRL1,
|
qusb2_write_mask(qphy->base, QUSB2PHY_IMP_CTRL1,
|
||||||
qphy->imp_res_offset_value << IMP_RES_OFFSET_SHIFT,
|
or->imp_res_offset.value << IMP_RES_OFFSET_SHIFT,
|
||||||
IMP_RES_OFFSET_MASK);
|
IMP_RES_OFFSET_MASK);
|
||||||
|
|
||||||
if (qphy->override_hstx_trim)
|
if (or->bias_ctrl.override)
|
||||||
|
qusb2_write_mask(qphy->base, QUSB2PHY_PLL_BIAS_CONTROL_2,
|
||||||
|
or->bias_ctrl.value << BIAS_CTRL2_RES_OFFSET_SHIFT,
|
||||||
|
BIAS_CTRL2_RES_OFFSET_MASK);
|
||||||
|
|
||||||
|
if (or->charge_ctrl.override)
|
||||||
|
qusb2_write_mask(qphy->base, QUSB2PHY_CHG_CTRL2,
|
||||||
|
or->charge_ctrl.value << CHG_CTRL2_OFFSET_SHIFT,
|
||||||
|
CHG_CTRL2_OFFSET_MASK);
|
||||||
|
|
||||||
|
if (or->hstx_trim.override)
|
||||||
qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1],
|
qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1],
|
||||||
qphy->hstx_trim_value << HSTX_TRIM_SHIFT,
|
or->hstx_trim.value << HSTX_TRIM_SHIFT,
|
||||||
HSTX_TRIM_MASK);
|
HSTX_TRIM_MASK);
|
||||||
|
|
||||||
if (qphy->override_preemphasis)
|
if (or->preemphasis.override)
|
||||||
qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1],
|
qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1],
|
||||||
qphy->preemphasis_level << PREEMPHASIS_EN_SHIFT,
|
or->preemphasis.value << PREEMPHASIS_EN_SHIFT,
|
||||||
PREEMPHASIS_EN_MASK);
|
PREEMPHASIS_EN_MASK);
|
||||||
|
|
||||||
if (qphy->override_preemphasis_width) {
|
if (or->preemphasis_width.override) {
|
||||||
if (qphy->preemphasis_width ==
|
if (or->preemphasis_width.value ==
|
||||||
QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT)
|
QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT)
|
||||||
qusb2_setbits(qphy->base,
|
qusb2_setbits(qphy->base,
|
||||||
cfg->regs[QUSB2PHY_PORT_TUNE1],
|
cfg->regs[QUSB2PHY_PORT_TUNE1],
|
||||||
@@ -421,6 +458,11 @@ static void qusb2_phy_override_phy_params(struct qusb2_phy *qphy)
|
|||||||
cfg->regs[QUSB2PHY_PORT_TUNE1],
|
cfg->regs[QUSB2PHY_PORT_TUNE1],
|
||||||
PREEMPH_WIDTH_HALF_BIT);
|
PREEMPH_WIDTH_HALF_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (or->hsdisc_trim.override)
|
||||||
|
qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE2],
|
||||||
|
or->hsdisc_trim.value << HSDISC_TRIM_SHIFT,
|
||||||
|
HSDISC_TRIM_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -774,8 +816,8 @@ static const struct of_device_id qusb2_phy_of_match_table[] = {
|
|||||||
.compatible = "qcom,msm8998-qusb2-phy",
|
.compatible = "qcom,msm8998-qusb2-phy",
|
||||||
.data = &msm8998_phy_cfg,
|
.data = &msm8998_phy_cfg,
|
||||||
}, {
|
}, {
|
||||||
.compatible = "qcom,sdm845-qusb2-phy",
|
.compatible = "qcom,qusb2-v2-phy",
|
||||||
.data = &sdm845_phy_cfg,
|
.data = &qusb2_v2_phy_cfg,
|
||||||
},
|
},
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
@@ -796,10 +838,12 @@ static int qusb2_phy_probe(struct platform_device *pdev)
|
|||||||
int ret, i;
|
int ret, i;
|
||||||
int num;
|
int num;
|
||||||
u32 value;
|
u32 value;
|
||||||
|
struct override_params *or;
|
||||||
|
|
||||||
qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
|
qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
|
||||||
if (!qphy)
|
if (!qphy)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
or = &qphy->overrides;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
qphy->base = devm_ioremap_resource(dev, res);
|
qphy->base = devm_ioremap_resource(dev, res);
|
||||||
@@ -864,26 +908,44 @@ static int qusb2_phy_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
if (!of_property_read_u32(dev->of_node, "qcom,imp-res-offset-value",
|
if (!of_property_read_u32(dev->of_node, "qcom,imp-res-offset-value",
|
||||||
&value)) {
|
&value)) {
|
||||||
qphy->imp_res_offset_value = (u8)value;
|
or->imp_res_offset.value = (u8)value;
|
||||||
qphy->override_imp_res_offset = true;
|
or->imp_res_offset.override = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!of_property_read_u32(dev->of_node, "qcom,bias-ctrl-value",
|
||||||
|
&value)) {
|
||||||
|
or->bias_ctrl.value = (u8)value;
|
||||||
|
or->bias_ctrl.override = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!of_property_read_u32(dev->of_node, "qcom,charge-ctrl-value",
|
||||||
|
&value)) {
|
||||||
|
or->charge_ctrl.value = (u8)value;
|
||||||
|
or->charge_ctrl.override = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!of_property_read_u32(dev->of_node, "qcom,hstx-trim-value",
|
if (!of_property_read_u32(dev->of_node, "qcom,hstx-trim-value",
|
||||||
&value)) {
|
&value)) {
|
||||||
qphy->hstx_trim_value = (u8)value;
|
or->hstx_trim.value = (u8)value;
|
||||||
qphy->override_hstx_trim = true;
|
or->hstx_trim.override = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-level",
|
if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-level",
|
||||||
&value)) {
|
&value)) {
|
||||||
qphy->preemphasis_level = (u8)value;
|
or->preemphasis.value = (u8)value;
|
||||||
qphy->override_preemphasis = true;
|
or->preemphasis.override = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-width",
|
if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-width",
|
||||||
&value)) {
|
&value)) {
|
||||||
qphy->preemphasis_width = (u8)value;
|
or->preemphasis_width.value = (u8)value;
|
||||||
qphy->override_preemphasis_width = true;
|
or->preemphasis_width.override = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!of_property_read_u32(dev->of_node, "qcom,hsdisc-trim-value",
|
||||||
|
&value)) {
|
||||||
|
or->hsdisc_trim.value = (u8)value;
|
||||||
|
or->hsdisc_trim.override = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_runtime_set_active(dev);
|
pm_runtime_set_active(dev);
|
||||||
|
|||||||
415
drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c
Normal file
415
drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c
Normal file
@@ -0,0 +1,415 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2018, Linux Foundation. All rights reserved.
|
||||||
|
* Copyright (c) 2018-2020, Linaro Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_graph.h>
|
||||||
|
#include <linux/phy/phy.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/reset.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
/* PHY register and bit definitions */
|
||||||
|
#define PHY_CTRL_COMMON0 0x078
|
||||||
|
#define SIDDQ BIT(2)
|
||||||
|
#define PHY_IRQ_CMD 0x0d0
|
||||||
|
#define PHY_INTR_MASK0 0x0d4
|
||||||
|
#define PHY_INTR_CLEAR0 0x0dc
|
||||||
|
#define DPDM_MASK 0x1e
|
||||||
|
#define DP_1_0 BIT(4)
|
||||||
|
#define DP_0_1 BIT(3)
|
||||||
|
#define DM_1_0 BIT(2)
|
||||||
|
#define DM_0_1 BIT(1)
|
||||||
|
|
||||||
|
enum hsphy_voltage {
|
||||||
|
VOL_NONE,
|
||||||
|
VOL_MIN,
|
||||||
|
VOL_MAX,
|
||||||
|
VOL_NUM,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum hsphy_vreg {
|
||||||
|
VDD,
|
||||||
|
VDDA_1P8,
|
||||||
|
VDDA_3P3,
|
||||||
|
VREG_NUM,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hsphy_init_seq {
|
||||||
|
int offset;
|
||||||
|
int val;
|
||||||
|
int delay;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hsphy_data {
|
||||||
|
const struct hsphy_init_seq *init_seq;
|
||||||
|
unsigned int init_seq_num;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hsphy_priv {
|
||||||
|
void __iomem *base;
|
||||||
|
struct clk_bulk_data *clks;
|
||||||
|
int num_clks;
|
||||||
|
struct reset_control *phy_reset;
|
||||||
|
struct reset_control *por_reset;
|
||||||
|
struct regulator_bulk_data vregs[VREG_NUM];
|
||||||
|
const struct hsphy_data *data;
|
||||||
|
enum phy_mode mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode,
|
||||||
|
int submode)
|
||||||
|
{
|
||||||
|
struct hsphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
priv->mode = PHY_MODE_INVALID;
|
||||||
|
|
||||||
|
if (mode > 0)
|
||||||
|
priv->mode = mode;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcom_snps_hsphy_enable_hv_interrupts(struct hsphy_priv *priv)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
/* Clear any existing interrupts before enabling the interrupts */
|
||||||
|
val = readb(priv->base + PHY_INTR_CLEAR0);
|
||||||
|
val |= DPDM_MASK;
|
||||||
|
writeb(val, priv->base + PHY_INTR_CLEAR0);
|
||||||
|
|
||||||
|
writeb(0x0, priv->base + PHY_IRQ_CMD);
|
||||||
|
usleep_range(200, 220);
|
||||||
|
writeb(0x1, priv->base + PHY_IRQ_CMD);
|
||||||
|
|
||||||
|
/* Make sure the interrupts are cleared */
|
||||||
|
usleep_range(200, 220);
|
||||||
|
|
||||||
|
val = readb(priv->base + PHY_INTR_MASK0);
|
||||||
|
switch (priv->mode) {
|
||||||
|
case PHY_MODE_USB_HOST_HS:
|
||||||
|
case PHY_MODE_USB_HOST_FS:
|
||||||
|
case PHY_MODE_USB_DEVICE_HS:
|
||||||
|
case PHY_MODE_USB_DEVICE_FS:
|
||||||
|
val |= DP_1_0 | DM_0_1;
|
||||||
|
break;
|
||||||
|
case PHY_MODE_USB_HOST_LS:
|
||||||
|
case PHY_MODE_USB_DEVICE_LS:
|
||||||
|
val |= DP_0_1 | DM_1_0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* No device connected */
|
||||||
|
val |= DP_0_1 | DM_0_1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
writeb(val, priv->base + PHY_INTR_MASK0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcom_snps_hsphy_disable_hv_interrupts(struct hsphy_priv *priv)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = readb(priv->base + PHY_INTR_MASK0);
|
||||||
|
val &= ~DPDM_MASK;
|
||||||
|
writeb(val, priv->base + PHY_INTR_MASK0);
|
||||||
|
|
||||||
|
/* Clear any pending interrupts */
|
||||||
|
val = readb(priv->base + PHY_INTR_CLEAR0);
|
||||||
|
val |= DPDM_MASK;
|
||||||
|
writeb(val, priv->base + PHY_INTR_CLEAR0);
|
||||||
|
|
||||||
|
writeb(0x0, priv->base + PHY_IRQ_CMD);
|
||||||
|
usleep_range(200, 220);
|
||||||
|
|
||||||
|
writeb(0x1, priv->base + PHY_IRQ_CMD);
|
||||||
|
usleep_range(200, 220);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcom_snps_hsphy_enter_retention(struct hsphy_priv *priv)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = readb(priv->base + PHY_CTRL_COMMON0);
|
||||||
|
val |= SIDDQ;
|
||||||
|
writeb(val, priv->base + PHY_CTRL_COMMON0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcom_snps_hsphy_exit_retention(struct hsphy_priv *priv)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = readb(priv->base + PHY_CTRL_COMMON0);
|
||||||
|
val &= ~SIDDQ;
|
||||||
|
writeb(val, priv->base + PHY_CTRL_COMMON0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_snps_hsphy_power_on(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct hsphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regulator_bulk_enable(VREG_NUM, priv->vregs);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks);
|
||||||
|
if (ret)
|
||||||
|
goto err_disable_regulator;
|
||||||
|
qcom_snps_hsphy_disable_hv_interrupts(priv);
|
||||||
|
qcom_snps_hsphy_exit_retention(priv);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_disable_regulator:
|
||||||
|
regulator_bulk_disable(VREG_NUM, priv->vregs);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_snps_hsphy_power_off(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct hsphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
qcom_snps_hsphy_enter_retention(priv);
|
||||||
|
qcom_snps_hsphy_enable_hv_interrupts(priv);
|
||||||
|
clk_bulk_disable_unprepare(priv->num_clks, priv->clks);
|
||||||
|
regulator_bulk_disable(VREG_NUM, priv->vregs);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_snps_hsphy_reset(struct hsphy_priv *priv)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = reset_control_assert(priv->phy_reset);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
usleep_range(10, 15);
|
||||||
|
|
||||||
|
ret = reset_control_deassert(priv->phy_reset);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
usleep_range(80, 100);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qcom_snps_hsphy_init_sequence(struct hsphy_priv *priv)
|
||||||
|
{
|
||||||
|
const struct hsphy_data *data = priv->data;
|
||||||
|
const struct hsphy_init_seq *seq;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Device match data is optional. */
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
seq = data->init_seq;
|
||||||
|
|
||||||
|
for (i = 0; i < data->init_seq_num; i++, seq++) {
|
||||||
|
writeb(seq->val, priv->base + seq->offset);
|
||||||
|
if (seq->delay)
|
||||||
|
usleep_range(seq->delay, seq->delay + 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_snps_hsphy_por_reset(struct hsphy_priv *priv)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = reset_control_assert(priv->por_reset);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Femto PHY is POR reset in the following scenarios.
|
||||||
|
*
|
||||||
|
* 1. After overriding the parameter registers.
|
||||||
|
* 2. Low power mode exit from PHY retention.
|
||||||
|
*
|
||||||
|
* Ensure that SIDDQ is cleared before bringing the PHY
|
||||||
|
* out of reset.
|
||||||
|
*/
|
||||||
|
qcom_snps_hsphy_exit_retention(priv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As per databook, 10 usec delay is required between
|
||||||
|
* PHY POR assert and de-assert.
|
||||||
|
*/
|
||||||
|
usleep_range(10, 20);
|
||||||
|
ret = reset_control_deassert(priv->por_reset);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As per databook, it takes 75 usec for PHY to stabilize
|
||||||
|
* after the reset.
|
||||||
|
*/
|
||||||
|
usleep_range(80, 100);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_snps_hsphy_init(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct hsphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = qcom_snps_hsphy_reset(priv);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
qcom_snps_hsphy_init_sequence(priv);
|
||||||
|
|
||||||
|
ret = qcom_snps_hsphy_por_reset(priv);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct phy_ops qcom_snps_hsphy_ops = {
|
||||||
|
.init = qcom_snps_hsphy_init,
|
||||||
|
.power_on = qcom_snps_hsphy_power_on,
|
||||||
|
.power_off = qcom_snps_hsphy_power_off,
|
||||||
|
.set_mode = qcom_snps_hsphy_set_mode,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const qcom_snps_hsphy_clks[] = {
|
||||||
|
"ref",
|
||||||
|
"ahb",
|
||||||
|
"sleep",
|
||||||
|
};
|
||||||
|
|
||||||
|
static int qcom_snps_hsphy_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct phy_provider *provider;
|
||||||
|
struct hsphy_priv *priv;
|
||||||
|
struct phy *phy;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
if (IS_ERR(priv->base))
|
||||||
|
return PTR_ERR(priv->base);
|
||||||
|
|
||||||
|
priv->num_clks = ARRAY_SIZE(qcom_snps_hsphy_clks);
|
||||||
|
priv->clks = devm_kcalloc(dev, priv->num_clks, sizeof(*priv->clks),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!priv->clks)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (i = 0; i < priv->num_clks; i++)
|
||||||
|
priv->clks[i].id = qcom_snps_hsphy_clks[i];
|
||||||
|
|
||||||
|
ret = devm_clk_bulk_get(dev, priv->num_clks, priv->clks);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
priv->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
|
||||||
|
if (IS_ERR(priv->phy_reset))
|
||||||
|
return PTR_ERR(priv->phy_reset);
|
||||||
|
|
||||||
|
priv->por_reset = devm_reset_control_get_exclusive(dev, "por");
|
||||||
|
if (IS_ERR(priv->por_reset))
|
||||||
|
return PTR_ERR(priv->por_reset);
|
||||||
|
|
||||||
|
priv->vregs[VDD].supply = "vdd";
|
||||||
|
priv->vregs[VDDA_1P8].supply = "vdda1p8";
|
||||||
|
priv->vregs[VDDA_3P3].supply = "vdda3p3";
|
||||||
|
|
||||||
|
ret = devm_regulator_bulk_get(dev, VREG_NUM, priv->vregs);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Get device match data */
|
||||||
|
priv->data = device_get_match_data(dev);
|
||||||
|
|
||||||
|
phy = devm_phy_create(dev, dev->of_node, &qcom_snps_hsphy_ops);
|
||||||
|
if (IS_ERR(phy))
|
||||||
|
return PTR_ERR(phy);
|
||||||
|
|
||||||
|
phy_set_drvdata(phy, priv);
|
||||||
|
|
||||||
|
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||||
|
if (IS_ERR(provider))
|
||||||
|
return PTR_ERR(provider);
|
||||||
|
|
||||||
|
ret = regulator_set_load(priv->vregs[VDDA_1P8].consumer, 19000);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regulator_set_load(priv->vregs[VDDA_3P3].consumer, 16000);
|
||||||
|
if (ret < 0)
|
||||||
|
goto unset_1p8_load;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
unset_1p8_load:
|
||||||
|
regulator_set_load(priv->vregs[VDDA_1P8].consumer, 0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The macro is used to define an initialization sequence. Each tuple
|
||||||
|
* is meant to program 'value' into phy register at 'offset' with 'delay'
|
||||||
|
* in us followed.
|
||||||
|
*/
|
||||||
|
#define HSPHY_INIT_CFG(o, v, d) { .offset = o, .val = v, .delay = d, }
|
||||||
|
|
||||||
|
static const struct hsphy_init_seq init_seq_femtophy[] = {
|
||||||
|
HSPHY_INIT_CFG(0xc0, 0x01, 0),
|
||||||
|
HSPHY_INIT_CFG(0xe8, 0x0d, 0),
|
||||||
|
HSPHY_INIT_CFG(0x74, 0x12, 0),
|
||||||
|
HSPHY_INIT_CFG(0x98, 0x63, 0),
|
||||||
|
HSPHY_INIT_CFG(0x9c, 0x03, 0),
|
||||||
|
HSPHY_INIT_CFG(0xa0, 0x1d, 0),
|
||||||
|
HSPHY_INIT_CFG(0xa4, 0x03, 0),
|
||||||
|
HSPHY_INIT_CFG(0x8c, 0x23, 0),
|
||||||
|
HSPHY_INIT_CFG(0x78, 0x08, 0),
|
||||||
|
HSPHY_INIT_CFG(0x7c, 0xdc, 0),
|
||||||
|
HSPHY_INIT_CFG(0x90, 0xe0, 20),
|
||||||
|
HSPHY_INIT_CFG(0x74, 0x10, 0),
|
||||||
|
HSPHY_INIT_CFG(0x90, 0x60, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct hsphy_data hsphy_data_femtophy = {
|
||||||
|
.init_seq = init_seq_femtophy,
|
||||||
|
.init_seq_num = ARRAY_SIZE(init_seq_femtophy),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id qcom_snps_hsphy_match[] = {
|
||||||
|
{ .compatible = "qcom,usb-hs-28nm-femtophy", .data = &hsphy_data_femtophy, },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_match);
|
||||||
|
|
||||||
|
static struct platform_driver qcom_snps_hsphy_driver = {
|
||||||
|
.probe = qcom_snps_hsphy_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "qcom,usb-hs-28nm-phy",
|
||||||
|
.of_match_table = qcom_snps_hsphy_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(qcom_snps_hsphy_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Qualcomm 28nm Hi-Speed USB PHY driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
246
drivers/phy/qualcomm/phy-qcom-usb-ss.c
Normal file
246
drivers/phy/qualcomm/phy-qcom-usb-ss.c
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012-2014,2017 The Linux Foundation. All rights reserved.
|
||||||
|
* Copyright (c) 2018-2020, Linaro Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.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 PHY_CTRL0 0x6C
|
||||||
|
#define PHY_CTRL1 0x70
|
||||||
|
#define PHY_CTRL2 0x74
|
||||||
|
#define PHY_CTRL4 0x7C
|
||||||
|
|
||||||
|
/* PHY_CTRL bits */
|
||||||
|
#define REF_PHY_EN BIT(0)
|
||||||
|
#define LANE0_PWR_ON BIT(2)
|
||||||
|
#define SWI_PCS_CLK_SEL BIT(4)
|
||||||
|
#define TST_PWR_DOWN BIT(4)
|
||||||
|
#define PHY_RESET BIT(7)
|
||||||
|
|
||||||
|
#define NUM_BULK_CLKS 3
|
||||||
|
#define NUM_BULK_REGS 2
|
||||||
|
|
||||||
|
struct ssphy_priv {
|
||||||
|
void __iomem *base;
|
||||||
|
struct device *dev;
|
||||||
|
struct reset_control *reset_com;
|
||||||
|
struct reset_control *reset_phy;
|
||||||
|
struct regulator_bulk_data regs[NUM_BULK_REGS];
|
||||||
|
struct clk_bulk_data clks[NUM_BULK_CLKS];
|
||||||
|
enum phy_mode mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void qcom_ssphy_updatel(void __iomem *addr, u32 mask, u32 val)
|
||||||
|
{
|
||||||
|
writel((readl(addr) & ~mask) | val, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_ssphy_do_reset(struct ssphy_priv *priv)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!priv->reset_com) {
|
||||||
|
qcom_ssphy_updatel(priv->base + PHY_CTRL1, PHY_RESET,
|
||||||
|
PHY_RESET);
|
||||||
|
usleep_range(10, 20);
|
||||||
|
qcom_ssphy_updatel(priv->base + PHY_CTRL1, PHY_RESET, 0);
|
||||||
|
} else {
|
||||||
|
ret = reset_control_assert(priv->reset_com);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(priv->dev, "Failed to assert reset com\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = reset_control_assert(priv->reset_phy);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(priv->dev, "Failed to assert reset phy\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep_range(10, 20);
|
||||||
|
|
||||||
|
ret = reset_control_deassert(priv->reset_com);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(priv->dev, "Failed to deassert reset com\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = reset_control_deassert(priv->reset_phy);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(priv->dev, "Failed to deassert reset phy\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_ssphy_power_on(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct ssphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regulator_bulk_enable(NUM_BULK_REGS, priv->regs);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = clk_bulk_prepare_enable(NUM_BULK_CLKS, priv->clks);
|
||||||
|
if (ret)
|
||||||
|
goto err_disable_regulator;
|
||||||
|
|
||||||
|
ret = qcom_ssphy_do_reset(priv);
|
||||||
|
if (ret)
|
||||||
|
goto err_disable_clock;
|
||||||
|
|
||||||
|
writeb(SWI_PCS_CLK_SEL, priv->base + PHY_CTRL0);
|
||||||
|
qcom_ssphy_updatel(priv->base + PHY_CTRL4, LANE0_PWR_ON, LANE0_PWR_ON);
|
||||||
|
qcom_ssphy_updatel(priv->base + PHY_CTRL2, REF_PHY_EN, REF_PHY_EN);
|
||||||
|
qcom_ssphy_updatel(priv->base + PHY_CTRL4, TST_PWR_DOWN, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
err_disable_clock:
|
||||||
|
clk_bulk_disable_unprepare(NUM_BULK_CLKS, priv->clks);
|
||||||
|
err_disable_regulator:
|
||||||
|
regulator_bulk_disable(NUM_BULK_REGS, priv->regs);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_ssphy_power_off(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct ssphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
qcom_ssphy_updatel(priv->base + PHY_CTRL4, LANE0_PWR_ON, 0);
|
||||||
|
qcom_ssphy_updatel(priv->base + PHY_CTRL2, REF_PHY_EN, 0);
|
||||||
|
qcom_ssphy_updatel(priv->base + PHY_CTRL4, TST_PWR_DOWN, TST_PWR_DOWN);
|
||||||
|
|
||||||
|
clk_bulk_disable_unprepare(NUM_BULK_CLKS, priv->clks);
|
||||||
|
regulator_bulk_disable(NUM_BULK_REGS, priv->regs);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_ssphy_init_clock(struct ssphy_priv *priv)
|
||||||
|
{
|
||||||
|
priv->clks[0].id = "ref";
|
||||||
|
priv->clks[1].id = "ahb";
|
||||||
|
priv->clks[2].id = "pipe";
|
||||||
|
|
||||||
|
return devm_clk_bulk_get(priv->dev, NUM_BULK_CLKS, priv->clks);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_ssphy_init_regulator(struct ssphy_priv *priv)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
priv->regs[0].supply = "vdd";
|
||||||
|
priv->regs[1].supply = "vdda1p8";
|
||||||
|
ret = devm_regulator_bulk_get(priv->dev, NUM_BULK_REGS, priv->regs);
|
||||||
|
if (ret) {
|
||||||
|
if (ret != -EPROBE_DEFER)
|
||||||
|
dev_err(priv->dev, "Failed to get regulators\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qcom_ssphy_init_reset(struct ssphy_priv *priv)
|
||||||
|
{
|
||||||
|
priv->reset_com = devm_reset_control_get_optional_exclusive(priv->dev, "com");
|
||||||
|
if (IS_ERR(priv->reset_com)) {
|
||||||
|
dev_err(priv->dev, "Failed to get reset control com\n");
|
||||||
|
return PTR_ERR(priv->reset_com);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->reset_com) {
|
||||||
|
/* if reset_com is present, reset_phy is no longer optional */
|
||||||
|
priv->reset_phy = devm_reset_control_get_exclusive(priv->dev, "phy");
|
||||||
|
if (IS_ERR(priv->reset_phy)) {
|
||||||
|
dev_err(priv->dev, "Failed to get reset control phy\n");
|
||||||
|
return PTR_ERR(priv->reset_phy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct phy_ops qcom_ssphy_ops = {
|
||||||
|
.power_off = qcom_ssphy_power_off,
|
||||||
|
.power_on = qcom_ssphy_power_on,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int qcom_ssphy_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct phy_provider *provider;
|
||||||
|
struct ssphy_priv *priv;
|
||||||
|
struct phy *phy;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
priv = devm_kzalloc(dev, sizeof(struct ssphy_priv), GFP_KERNEL);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->dev = dev;
|
||||||
|
priv->mode = PHY_MODE_INVALID;
|
||||||
|
|
||||||
|
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
if (IS_ERR(priv->base))
|
||||||
|
return PTR_ERR(priv->base);
|
||||||
|
|
||||||
|
ret = qcom_ssphy_init_clock(priv);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = qcom_ssphy_init_reset(priv);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = qcom_ssphy_init_regulator(priv);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
phy = devm_phy_create(dev, dev->of_node, &qcom_ssphy_ops);
|
||||||
|
if (IS_ERR(phy)) {
|
||||||
|
dev_err(dev, "Failed to create the SS phy\n");
|
||||||
|
return PTR_ERR(phy);
|
||||||
|
}
|
||||||
|
|
||||||
|
phy_set_drvdata(phy, priv);
|
||||||
|
|
||||||
|
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||||
|
|
||||||
|
return PTR_ERR_OR_ZERO(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id qcom_ssphy_match[] = {
|
||||||
|
{ .compatible = "qcom,usb-ss-28nm-phy", },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, qcom_ssphy_match);
|
||||||
|
|
||||||
|
static struct platform_driver qcom_ssphy_driver = {
|
||||||
|
.probe = qcom_ssphy_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "qcom-usb-ssphy",
|
||||||
|
.of_match_table = qcom_ssphy_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(qcom_ssphy_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Qualcomm SuperSpeed USB PHY driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
@@ -763,7 +763,7 @@ static void rockchip_chg_detect_work(struct work_struct *work)
|
|||||||
/* put the controller in normal mode */
|
/* put the controller in normal mode */
|
||||||
property_enable(base, &rphy->phy_cfg->chg_det.opmode, true);
|
property_enable(base, &rphy->phy_cfg->chg_det.opmode, true);
|
||||||
rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work);
|
rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work);
|
||||||
dev_info(&rport->phy->dev, "charger = %s\n",
|
dev_dbg(&rport->phy->dev, "charger = %s\n",
|
||||||
chg_to_string(rphy->chg_type));
|
chg_to_string(rphy->chg_type));
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -19,6 +19,10 @@
|
|||||||
#include <linux/resource.h>
|
#include <linux/resource.h>
|
||||||
|
|
||||||
/* PHY */
|
/* PHY */
|
||||||
|
#define PCL_PHY_CLKCTRL 0x0000
|
||||||
|
#define PORT_SEL_MASK GENMASK(11, 9)
|
||||||
|
#define PORT_SEL_1 FIELD_PREP(PORT_SEL_MASK, 1)
|
||||||
|
|
||||||
#define PCL_PHY_TEST_I 0x2000
|
#define PCL_PHY_TEST_I 0x2000
|
||||||
#define PCL_PHY_TEST_O 0x2004
|
#define PCL_PHY_TEST_O 0x2004
|
||||||
#define TESTI_DAT_MASK GENMASK(13, 6)
|
#define TESTI_DAT_MASK GENMASK(13, 6)
|
||||||
@@ -45,13 +49,14 @@
|
|||||||
struct uniphier_pciephy_priv {
|
struct uniphier_pciephy_priv {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct clk *clk;
|
struct clk *clk, *clk_gio;
|
||||||
struct reset_control *rst;
|
struct reset_control *rst, *rst_gio;
|
||||||
const struct uniphier_pciephy_soc_data *data;
|
const struct uniphier_pciephy_soc_data *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct uniphier_pciephy_soc_data {
|
struct uniphier_pciephy_soc_data {
|
||||||
bool has_syscon;
|
bool is_legacy;
|
||||||
|
void (*set_phymode)(struct regmap *regmap);
|
||||||
};
|
};
|
||||||
|
|
||||||
static void uniphier_pciephy_testio_write(struct uniphier_pciephy_priv *priv,
|
static void uniphier_pciephy_testio_write(struct uniphier_pciephy_priv *priv,
|
||||||
@@ -111,16 +116,35 @@ static void uniphier_pciephy_deassert(struct uniphier_pciephy_priv *priv)
|
|||||||
static int uniphier_pciephy_init(struct phy *phy)
|
static int uniphier_pciephy_init(struct phy *phy)
|
||||||
{
|
{
|
||||||
struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy);
|
struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
u32 val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = clk_prepare_enable(priv->clk);
|
ret = clk_prepare_enable(priv->clk);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = reset_control_deassert(priv->rst);
|
ret = clk_prepare_enable(priv->clk_gio);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_clk_disable;
|
goto out_clk_disable;
|
||||||
|
|
||||||
|
ret = reset_control_deassert(priv->rst);
|
||||||
|
if (ret)
|
||||||
|
goto out_clk_gio_disable;
|
||||||
|
|
||||||
|
ret = reset_control_deassert(priv->rst_gio);
|
||||||
|
if (ret)
|
||||||
|
goto out_rst_assert;
|
||||||
|
|
||||||
|
/* support only 1 port */
|
||||||
|
val = readl(priv->base + PCL_PHY_CLKCTRL);
|
||||||
|
val &= ~PORT_SEL_MASK;
|
||||||
|
val |= PORT_SEL_1;
|
||||||
|
writel(val, priv->base + PCL_PHY_CLKCTRL);
|
||||||
|
|
||||||
|
/* legacy controller doesn't have phy_reset and parameters */
|
||||||
|
if (priv->data->is_legacy)
|
||||||
|
return 0;
|
||||||
|
|
||||||
uniphier_pciephy_set_param(priv, PCL_PHY_R00,
|
uniphier_pciephy_set_param(priv, PCL_PHY_R00,
|
||||||
RX_EQ_ADJ_EN, RX_EQ_ADJ_EN);
|
RX_EQ_ADJ_EN, RX_EQ_ADJ_EN);
|
||||||
uniphier_pciephy_set_param(priv, PCL_PHY_R06, RX_EQ_ADJ,
|
uniphier_pciephy_set_param(priv, PCL_PHY_R06, RX_EQ_ADJ,
|
||||||
@@ -134,6 +158,10 @@ static int uniphier_pciephy_init(struct phy *phy)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
out_rst_assert:
|
||||||
|
reset_control_assert(priv->rst);
|
||||||
|
out_clk_gio_disable:
|
||||||
|
clk_disable_unprepare(priv->clk_gio);
|
||||||
out_clk_disable:
|
out_clk_disable:
|
||||||
clk_disable_unprepare(priv->clk);
|
clk_disable_unprepare(priv->clk);
|
||||||
|
|
||||||
@@ -144,8 +172,11 @@ static int uniphier_pciephy_exit(struct phy *phy)
|
|||||||
{
|
{
|
||||||
struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy);
|
struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
|
||||||
uniphier_pciephy_assert(priv);
|
if (!priv->data->is_legacy)
|
||||||
|
uniphier_pciephy_assert(priv);
|
||||||
|
reset_control_assert(priv->rst_gio);
|
||||||
reset_control_assert(priv->rst);
|
reset_control_assert(priv->rst);
|
||||||
|
clk_disable_unprepare(priv->clk_gio);
|
||||||
clk_disable_unprepare(priv->clk);
|
clk_disable_unprepare(priv->clk);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -163,7 +194,6 @@ static int uniphier_pciephy_probe(struct platform_device *pdev)
|
|||||||
struct phy_provider *phy_provider;
|
struct phy_provider *phy_provider;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
struct resource *res;
|
|
||||||
struct phy *phy;
|
struct phy *phy;
|
||||||
|
|
||||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
@@ -176,18 +206,36 @@ static int uniphier_pciephy_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
priv->dev = dev;
|
priv->dev = dev;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
priv->base = devm_ioremap_resource(dev, res);
|
|
||||||
if (IS_ERR(priv->base))
|
if (IS_ERR(priv->base))
|
||||||
return PTR_ERR(priv->base);
|
return PTR_ERR(priv->base);
|
||||||
|
|
||||||
priv->clk = devm_clk_get(dev, NULL);
|
if (priv->data->is_legacy) {
|
||||||
if (IS_ERR(priv->clk))
|
priv->clk_gio = devm_clk_get(dev, "gio");
|
||||||
return PTR_ERR(priv->clk);
|
if (IS_ERR(priv->clk_gio))
|
||||||
|
return PTR_ERR(priv->clk_gio);
|
||||||
|
|
||||||
priv->rst = devm_reset_control_get_shared(dev, NULL);
|
priv->rst_gio =
|
||||||
if (IS_ERR(priv->rst))
|
devm_reset_control_get_shared(dev, "gio");
|
||||||
return PTR_ERR(priv->rst);
|
if (IS_ERR(priv->rst_gio))
|
||||||
|
return PTR_ERR(priv->rst_gio);
|
||||||
|
|
||||||
|
priv->clk = devm_clk_get(dev, "link");
|
||||||
|
if (IS_ERR(priv->clk))
|
||||||
|
return PTR_ERR(priv->clk);
|
||||||
|
|
||||||
|
priv->rst = devm_reset_control_get_shared(dev, "link");
|
||||||
|
if (IS_ERR(priv->rst))
|
||||||
|
return PTR_ERR(priv->rst);
|
||||||
|
} else {
|
||||||
|
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);
|
phy = devm_phy_create(dev, dev->of_node, &uniphier_pciephy_ops);
|
||||||
if (IS_ERR(phy))
|
if (IS_ERR(phy))
|
||||||
@@ -195,9 +243,8 @@ static int uniphier_pciephy_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
|
regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||||
"socionext,syscon");
|
"socionext,syscon");
|
||||||
if (!IS_ERR(regmap) && priv->data->has_syscon)
|
if (!IS_ERR(regmap) && priv->data->set_phymode)
|
||||||
regmap_update_bits(regmap, SG_USBPCIESEL,
|
priv->data->set_phymode(regmap);
|
||||||
SG_USBPCIESEL_PCIE, SG_USBPCIESEL_PCIE);
|
|
||||||
|
|
||||||
phy_set_drvdata(phy, priv);
|
phy_set_drvdata(phy, priv);
|
||||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||||
@@ -205,15 +252,30 @@ static int uniphier_pciephy_probe(struct platform_device *pdev)
|
|||||||
return PTR_ERR_OR_ZERO(phy_provider);
|
return PTR_ERR_OR_ZERO(phy_provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void uniphier_pciephy_ld20_setmode(struct regmap *regmap)
|
||||||
|
{
|
||||||
|
regmap_update_bits(regmap, SG_USBPCIESEL,
|
||||||
|
SG_USBPCIESEL_PCIE, SG_USBPCIESEL_PCIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct uniphier_pciephy_soc_data uniphier_pro5_data = {
|
||||||
|
.is_legacy = true,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct uniphier_pciephy_soc_data uniphier_ld20_data = {
|
static const struct uniphier_pciephy_soc_data uniphier_ld20_data = {
|
||||||
.has_syscon = true,
|
.is_legacy = false,
|
||||||
|
.set_phymode = uniphier_pciephy_ld20_setmode,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct uniphier_pciephy_soc_data uniphier_pxs3_data = {
|
static const struct uniphier_pciephy_soc_data uniphier_pxs3_data = {
|
||||||
.has_syscon = false,
|
.is_legacy = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id uniphier_pciephy_match[] = {
|
static const struct of_device_id uniphier_pciephy_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "socionext,uniphier-pro5-pcie-phy",
|
||||||
|
.data = &uniphier_pro5_data,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.compatible = "socionext,uniphier-ld20-pcie-phy",
|
.compatible = "socionext,uniphier-ld20-pcie-phy",
|
||||||
.data = &uniphier_ld20_data,
|
.data = &uniphier_ld20_data,
|
||||||
|
|||||||
@@ -41,10 +41,12 @@
|
|||||||
|
|
||||||
#define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
|
#define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
|
||||||
|
|
||||||
|
#define RX_CHK_SYNC PHY_F(0, 5, 5) /* RX sync mode */
|
||||||
|
#define RX_SYNC_SEL PHY_F(1, 1, 0) /* RX sync length */
|
||||||
#define LS_SLEW PHY_F(10, 6, 6) /* LS mode slew rate */
|
#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 FS_LS_DRV PHY_F(10, 5, 5) /* FS/LS slew rate */
|
||||||
|
|
||||||
#define MAX_PHY_PARAMS 2
|
#define MAX_PHY_PARAMS 4
|
||||||
|
|
||||||
struct uniphier_u3hsphy_param {
|
struct uniphier_u3hsphy_param {
|
||||||
struct {
|
struct {
|
||||||
@@ -66,13 +68,14 @@ struct uniphier_u3hsphy_trim_param {
|
|||||||
struct uniphier_u3hsphy_priv {
|
struct uniphier_u3hsphy_priv {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct clk *clk, *clk_parent, *clk_ext;
|
struct clk *clk, *clk_parent, *clk_ext, *clk_parent_gio;
|
||||||
struct reset_control *rst, *rst_parent;
|
struct reset_control *rst, *rst_parent, *rst_parent_gio;
|
||||||
struct regulator *vbus;
|
struct regulator *vbus;
|
||||||
const struct uniphier_u3hsphy_soc_data *data;
|
const struct uniphier_u3hsphy_soc_data *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct uniphier_u3hsphy_soc_data {
|
struct uniphier_u3hsphy_soc_data {
|
||||||
|
bool is_legacy;
|
||||||
int nparams;
|
int nparams;
|
||||||
const struct uniphier_u3hsphy_param param[MAX_PHY_PARAMS];
|
const struct uniphier_u3hsphy_param param[MAX_PHY_PARAMS];
|
||||||
u32 config0;
|
u32 config0;
|
||||||
@@ -256,11 +259,20 @@ static int uniphier_u3hsphy_init(struct phy *phy)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = reset_control_deassert(priv->rst_parent);
|
ret = clk_prepare_enable(priv->clk_parent_gio);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_clk_disable;
|
goto out_clk_disable;
|
||||||
|
|
||||||
if (!priv->data->config0 && !priv->data->config1)
|
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)
|
||||||
|
|| (!priv->data->config0 && !priv->data->config1))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
config0 = priv->data->config0;
|
config0 = priv->data->config0;
|
||||||
@@ -280,6 +292,8 @@ static int uniphier_u3hsphy_init(struct phy *phy)
|
|||||||
|
|
||||||
out_rst_assert:
|
out_rst_assert:
|
||||||
reset_control_assert(priv->rst_parent);
|
reset_control_assert(priv->rst_parent);
|
||||||
|
out_clk_gio_disable:
|
||||||
|
clk_disable_unprepare(priv->clk_parent_gio);
|
||||||
out_clk_disable:
|
out_clk_disable:
|
||||||
clk_disable_unprepare(priv->clk_parent);
|
clk_disable_unprepare(priv->clk_parent);
|
||||||
|
|
||||||
@@ -290,7 +304,9 @@ static int uniphier_u3hsphy_exit(struct phy *phy)
|
|||||||
{
|
{
|
||||||
struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
|
struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
reset_control_assert(priv->rst_parent_gio);
|
||||||
reset_control_assert(priv->rst_parent);
|
reset_control_assert(priv->rst_parent);
|
||||||
|
clk_disable_unprepare(priv->clk_parent_gio);
|
||||||
clk_disable_unprepare(priv->clk_parent);
|
clk_disable_unprepare(priv->clk_parent);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -309,7 +325,6 @@ static int uniphier_u3hsphy_probe(struct platform_device *pdev)
|
|||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct uniphier_u3hsphy_priv *priv;
|
struct uniphier_u3hsphy_priv *priv;
|
||||||
struct phy_provider *phy_provider;
|
struct phy_provider *phy_provider;
|
||||||
struct resource *res;
|
|
||||||
struct phy *phy;
|
struct phy *phy;
|
||||||
|
|
||||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
@@ -322,27 +337,38 @@ static int uniphier_u3hsphy_probe(struct platform_device *pdev)
|
|||||||
priv->data->nparams > MAX_PHY_PARAMS))
|
priv->data->nparams > MAX_PHY_PARAMS))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
priv->base = devm_ioremap_resource(dev, res);
|
|
||||||
if (IS_ERR(priv->base))
|
if (IS_ERR(priv->base))
|
||||||
return PTR_ERR(priv->base);
|
return PTR_ERR(priv->base);
|
||||||
|
|
||||||
priv->clk = devm_clk_get(dev, "phy");
|
if (!priv->data->is_legacy) {
|
||||||
if (IS_ERR(priv->clk))
|
priv->clk = devm_clk_get(dev, "phy");
|
||||||
return PTR_ERR(priv->clk);
|
if (IS_ERR(priv->clk))
|
||||||
|
return PTR_ERR(priv->clk);
|
||||||
|
|
||||||
|
priv->clk_ext = devm_clk_get_optional(dev, "phy-ext");
|
||||||
|
if (IS_ERR(priv->clk_ext))
|
||||||
|
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");
|
priv->clk_parent = devm_clk_get(dev, "link");
|
||||||
if (IS_ERR(priv->clk_parent))
|
if (IS_ERR(priv->clk_parent))
|
||||||
return PTR_ERR(priv->clk_parent);
|
return PTR_ERR(priv->clk_parent);
|
||||||
|
|
||||||
priv->clk_ext = devm_clk_get_optional(dev, "phy-ext");
|
|
||||||
if (IS_ERR(priv->clk_ext))
|
|
||||||
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");
|
priv->rst_parent = devm_reset_control_get_shared(dev, "link");
|
||||||
if (IS_ERR(priv->rst_parent))
|
if (IS_ERR(priv->rst_parent))
|
||||||
return PTR_ERR(priv->rst_parent);
|
return PTR_ERR(priv->rst_parent);
|
||||||
@@ -364,13 +390,26 @@ static int uniphier_u3hsphy_probe(struct platform_device *pdev)
|
|||||||
return PTR_ERR_OR_ZERO(phy_provider);
|
return PTR_ERR_OR_ZERO(phy_provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = {
|
static const struct uniphier_u3hsphy_soc_data uniphier_pro5_data = {
|
||||||
|
.is_legacy = true,
|
||||||
.nparams = 0,
|
.nparams = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = {
|
static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = {
|
||||||
|
.is_legacy = false,
|
||||||
.nparams = 2,
|
.nparams = 2,
|
||||||
.param = {
|
.param = {
|
||||||
|
{ RX_CHK_SYNC, 1 },
|
||||||
|
{ RX_SYNC_SEL, 1 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = {
|
||||||
|
.is_legacy = false,
|
||||||
|
.nparams = 4,
|
||||||
|
.param = {
|
||||||
|
{ RX_CHK_SYNC, 1 },
|
||||||
|
{ RX_SYNC_SEL, 1 },
|
||||||
{ LS_SLEW, 1 },
|
{ LS_SLEW, 1 },
|
||||||
{ FS_LS_DRV, 1 },
|
{ FS_LS_DRV, 1 },
|
||||||
},
|
},
|
||||||
@@ -380,13 +419,22 @@ static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = {
|
static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = {
|
||||||
.nparams = 0,
|
.is_legacy = false,
|
||||||
|
.nparams = 2,
|
||||||
|
.param = {
|
||||||
|
{ RX_CHK_SYNC, 1 },
|
||||||
|
{ RX_SYNC_SEL, 1 },
|
||||||
|
},
|
||||||
.trim_func = uniphier_u3hsphy_trim_ld20,
|
.trim_func = uniphier_u3hsphy_trim_ld20,
|
||||||
.config0 = 0x92316680,
|
.config0 = 0x92316680,
|
||||||
.config1 = 0x00000106,
|
.config1 = 0x00000106,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id uniphier_u3hsphy_match[] = {
|
static const struct of_device_id uniphier_u3hsphy_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "socionext,uniphier-pro5-usb3-hsphy",
|
||||||
|
.data = &uniphier_pro5_data,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.compatible = "socionext,uniphier-pxs2-usb3-hsphy",
|
.compatible = "socionext,uniphier-pxs2-usb3-hsphy",
|
||||||
.data = &uniphier_pxs2_data,
|
.data = &uniphier_pxs2_data,
|
||||||
|
|||||||
@@ -215,7 +215,6 @@ static int uniphier_u3ssphy_probe(struct platform_device *pdev)
|
|||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct uniphier_u3ssphy_priv *priv;
|
struct uniphier_u3ssphy_priv *priv;
|
||||||
struct phy_provider *phy_provider;
|
struct phy_provider *phy_provider;
|
||||||
struct resource *res;
|
|
||||||
struct phy *phy;
|
struct phy *phy;
|
||||||
|
|
||||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
@@ -228,8 +227,7 @@ static int uniphier_u3ssphy_probe(struct platform_device *pdev)
|
|||||||
priv->data->nparams > MAX_PHY_PARAMS))
|
priv->data->nparams > MAX_PHY_PARAMS))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
priv->base = devm_ioremap_resource(dev, res);
|
|
||||||
if (IS_ERR(priv->base))
|
if (IS_ERR(priv->base))
|
||||||
return PTR_ERR(priv->base);
|
return PTR_ERR(priv->base);
|
||||||
|
|
||||||
@@ -314,6 +312,10 @@ static const struct of_device_id uniphier_u3ssphy_match[] = {
|
|||||||
.compatible = "socionext,uniphier-pro4-usb3-ssphy",
|
.compatible = "socionext,uniphier-pro4-usb3-ssphy",
|
||||||
.data = &uniphier_pro4_data,
|
.data = &uniphier_pro4_data,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.compatible = "socionext,uniphier-pro5-usb3-ssphy",
|
||||||
|
.data = &uniphier_pro4_data,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.compatible = "socionext,uniphier-pxs2-usb3-ssphy",
|
.compatible = "socionext,uniphier-pxs2-usb3-ssphy",
|
||||||
.data = &uniphier_pxs2_data,
|
.data = &uniphier_pxs2_data,
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
config PHY_TEGRA_XUSB
|
config PHY_TEGRA_XUSB
|
||||||
tristate "NVIDIA Tegra XUSB pad controller driver"
|
tristate "NVIDIA Tegra XUSB pad controller driver"
|
||||||
depends on ARCH_TEGRA
|
depends on ARCH_TEGRA
|
||||||
|
select USB_CONN_GPIO
|
||||||
|
select USB_PHY
|
||||||
help
|
help
|
||||||
Choose this option if you have an NVIDIA Tegra SoC.
|
Choose this option if you have an NVIDIA Tegra SoC.
|
||||||
|
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_124_SOC) += xusb-tegra124.o
|
|||||||
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_132_SOC) += xusb-tegra124.o
|
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_132_SOC) += xusb-tegra124.o
|
||||||
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_210_SOC) += xusb-tegra210.o
|
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_210_SOC) += xusb-tegra210.o
|
||||||
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_186_SOC) += xusb-tegra186.o
|
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_186_SOC) += xusb-tegra186.o
|
||||||
|
phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_194_SOC) += xusb-tegra186.o
|
||||||
obj-$(CONFIG_PHY_TEGRA194_P2U) += phy-tegra194-p2u.o
|
obj-$(CONFIG_PHY_TEGRA194_P2U) += phy-tegra194-p2u.o
|
||||||
|
|||||||
@@ -1422,6 +1422,8 @@ tegra124_usb2_port_map(struct tegra_xusb_port *port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct tegra_xusb_port_ops tegra124_usb2_port_ops = {
|
static const struct tegra_xusb_port_ops tegra124_usb2_port_ops = {
|
||||||
|
.release = tegra_xusb_usb2_port_release,
|
||||||
|
.remove = tegra_xusb_usb2_port_remove,
|
||||||
.enable = tegra124_usb2_port_enable,
|
.enable = tegra124_usb2_port_enable,
|
||||||
.disable = tegra124_usb2_port_disable,
|
.disable = tegra124_usb2_port_disable,
|
||||||
.map = tegra124_usb2_port_map,
|
.map = tegra124_usb2_port_map,
|
||||||
@@ -1443,6 +1445,7 @@ tegra124_ulpi_port_map(struct tegra_xusb_port *port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct tegra_xusb_port_ops tegra124_ulpi_port_ops = {
|
static const struct tegra_xusb_port_ops tegra124_ulpi_port_ops = {
|
||||||
|
.release = tegra_xusb_ulpi_port_release,
|
||||||
.enable = tegra124_ulpi_port_enable,
|
.enable = tegra124_ulpi_port_enable,
|
||||||
.disable = tegra124_ulpi_port_disable,
|
.disable = tegra124_ulpi_port_disable,
|
||||||
.map = tegra124_ulpi_port_map,
|
.map = tegra124_ulpi_port_map,
|
||||||
@@ -1464,6 +1467,7 @@ tegra124_hsic_port_map(struct tegra_xusb_port *port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct tegra_xusb_port_ops tegra124_hsic_port_ops = {
|
static const struct tegra_xusb_port_ops tegra124_hsic_port_ops = {
|
||||||
|
.release = tegra_xusb_hsic_port_release,
|
||||||
.enable = tegra124_hsic_port_enable,
|
.enable = tegra124_hsic_port_enable,
|
||||||
.disable = tegra124_hsic_port_disable,
|
.disable = tegra124_hsic_port_disable,
|
||||||
.map = tegra124_hsic_port_map,
|
.map = tegra124_hsic_port_map,
|
||||||
@@ -1647,6 +1651,8 @@ tegra124_usb3_port_map(struct tegra_xusb_port *port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct tegra_xusb_port_ops tegra124_usb3_port_ops = {
|
static const struct tegra_xusb_port_ops tegra124_usb3_port_ops = {
|
||||||
|
.release = tegra_xusb_usb3_port_release,
|
||||||
|
.remove = tegra_xusb_usb3_port_remove,
|
||||||
.enable = tegra124_usb3_port_enable,
|
.enable = tegra124_usb3_port_enable,
|
||||||
.disable = tegra124_usb3_port_disable,
|
.disable = tegra124_usb3_port_disable,
|
||||||
.map = tegra124_usb3_port_map,
|
.map = tegra124_usb3_port_map,
|
||||||
|
|||||||
@@ -63,6 +63,10 @@
|
|||||||
#define SSPX_ELPG_CLAMP_EN(x) BIT(0 + (x) * 3)
|
#define SSPX_ELPG_CLAMP_EN(x) BIT(0 + (x) * 3)
|
||||||
#define SSPX_ELPG_CLAMP_EN_EARLY(x) BIT(1 + (x) * 3)
|
#define SSPX_ELPG_CLAMP_EN_EARLY(x) BIT(1 + (x) * 3)
|
||||||
#define SSPX_ELPG_VCORE_DOWN(x) BIT(2 + (x) * 3)
|
#define SSPX_ELPG_VCORE_DOWN(x) BIT(2 + (x) * 3)
|
||||||
|
#define XUSB_PADCTL_SS_PORT_CFG 0x2c
|
||||||
|
#define PORTX_SPEED_SUPPORT_SHIFT(x) ((x) * 4)
|
||||||
|
#define PORTX_SPEED_SUPPORT_MASK (0x3)
|
||||||
|
#define PORT_SPEED_SUPPORT_GEN1 (0x0)
|
||||||
|
|
||||||
#define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x88 + (x) * 0x40)
|
#define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x88 + (x) * 0x40)
|
||||||
#define HS_CURR_LEVEL(x) ((x) & 0x3f)
|
#define HS_CURR_LEVEL(x) ((x) & 0x3f)
|
||||||
@@ -301,6 +305,97 @@ static void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy)
|
|||||||
tegra186_utmi_bias_pad_power_off(padctl);
|
tegra186_utmi_bias_pad_power_off(padctl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
|
||||||
|
bool status)
|
||||||
|
{
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
|
||||||
|
|
||||||
|
value = padctl_readl(padctl, USB2_VBUS_ID);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
value |= VBUS_OVERRIDE;
|
||||||
|
value &= ~ID_OVERRIDE(~0);
|
||||||
|
value |= ID_OVERRIDE_FLOATING;
|
||||||
|
} else {
|
||||||
|
value &= ~VBUS_OVERRIDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
padctl_writel(padctl, value, USB2_VBUS_ID);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra186_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
|
||||||
|
bool status)
|
||||||
|
{
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");
|
||||||
|
|
||||||
|
value = padctl_readl(padctl, USB2_VBUS_ID);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
if (value & VBUS_OVERRIDE) {
|
||||||
|
value &= ~VBUS_OVERRIDE;
|
||||||
|
padctl_writel(padctl, value, USB2_VBUS_ID);
|
||||||
|
usleep_range(1000, 2000);
|
||||||
|
|
||||||
|
value = padctl_readl(padctl, USB2_VBUS_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
value &= ~ID_OVERRIDE(~0);
|
||||||
|
value |= ID_OVERRIDE_GROUNDED;
|
||||||
|
} else {
|
||||||
|
value &= ~ID_OVERRIDE(~0);
|
||||||
|
value |= ID_OVERRIDE_FLOATING;
|
||||||
|
}
|
||||||
|
|
||||||
|
padctl_writel(padctl, value, USB2_VBUS_ID);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra186_utmi_phy_set_mode(struct phy *phy, enum phy_mode mode,
|
||||||
|
int submode)
|
||||||
|
{
|
||||||
|
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
|
||||||
|
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
|
||||||
|
struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
|
||||||
|
lane->index);
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
mutex_lock(&padctl->lock);
|
||||||
|
|
||||||
|
dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
|
||||||
|
|
||||||
|
if (mode == PHY_MODE_USB_OTG) {
|
||||||
|
if (submode == USB_ROLE_HOST) {
|
||||||
|
tegra186_xusb_padctl_id_override(padctl, true);
|
||||||
|
|
||||||
|
err = regulator_enable(port->supply);
|
||||||
|
} else if (submode == USB_ROLE_DEVICE) {
|
||||||
|
tegra186_xusb_padctl_vbus_override(padctl, true);
|
||||||
|
} else if (submode == USB_ROLE_NONE) {
|
||||||
|
/*
|
||||||
|
* When port is peripheral only or role transitions to
|
||||||
|
* USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
|
||||||
|
* enabled.
|
||||||
|
*/
|
||||||
|
if (regulator_is_enabled(port->supply))
|
||||||
|
regulator_disable(port->supply);
|
||||||
|
|
||||||
|
tegra186_xusb_padctl_id_override(padctl, false);
|
||||||
|
tegra186_xusb_padctl_vbus_override(padctl, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&padctl->lock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int tegra186_utmi_phy_power_on(struct phy *phy)
|
static int tegra186_utmi_phy_power_on(struct phy *phy)
|
||||||
{
|
{
|
||||||
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
|
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
|
||||||
@@ -439,6 +534,7 @@ static const struct phy_ops utmi_phy_ops = {
|
|||||||
.exit = tegra186_utmi_phy_exit,
|
.exit = tegra186_utmi_phy_exit,
|
||||||
.power_on = tegra186_utmi_phy_power_on,
|
.power_on = tegra186_utmi_phy_power_on,
|
||||||
.power_off = tegra186_utmi_phy_power_off,
|
.power_off = tegra186_utmi_phy_power_off,
|
||||||
|
.set_mode = tegra186_utmi_phy_set_mode,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -503,19 +599,6 @@ static const char * const tegra186_usb2_functions[] = {
|
|||||||
"xusb",
|
"xusb",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct tegra_xusb_lane_soc tegra186_usb2_lanes[] = {
|
|
||||||
TEGRA186_LANE("usb2-0", 0, 0, 0, usb2),
|
|
||||||
TEGRA186_LANE("usb2-1", 0, 0, 0, usb2),
|
|
||||||
TEGRA186_LANE("usb2-2", 0, 0, 0, usb2),
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct tegra_xusb_pad_soc tegra186_usb2_pad = {
|
|
||||||
.name = "usb2",
|
|
||||||
.num_lanes = ARRAY_SIZE(tegra186_usb2_lanes),
|
|
||||||
.lanes = tegra186_usb2_lanes,
|
|
||||||
.ops = &tegra186_usb2_pad_ops,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int tegra186_usb2_port_enable(struct tegra_xusb_port *port)
|
static int tegra186_usb2_port_enable(struct tegra_xusb_port *port)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@@ -532,6 +615,8 @@ tegra186_usb2_port_map(struct tegra_xusb_port *port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct tegra_xusb_port_ops tegra186_usb2_port_ops = {
|
static const struct tegra_xusb_port_ops tegra186_usb2_port_ops = {
|
||||||
|
.release = tegra_xusb_usb2_port_release,
|
||||||
|
.remove = tegra_xusb_usb2_port_remove,
|
||||||
.enable = tegra186_usb2_port_enable,
|
.enable = tegra186_usb2_port_enable,
|
||||||
.disable = tegra186_usb2_port_disable,
|
.disable = tegra186_usb2_port_disable,
|
||||||
.map = tegra186_usb2_port_map,
|
.map = tegra186_usb2_port_map,
|
||||||
@@ -591,6 +676,8 @@ tegra186_usb3_port_map(struct tegra_xusb_port *port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct tegra_xusb_port_ops tegra186_usb3_port_ops = {
|
static const struct tegra_xusb_port_ops tegra186_usb3_port_ops = {
|
||||||
|
.release = tegra_xusb_usb3_port_release,
|
||||||
|
.remove = tegra_xusb_usb3_port_remove,
|
||||||
.enable = tegra186_usb3_port_enable,
|
.enable = tegra186_usb3_port_enable,
|
||||||
.disable = tegra186_usb3_port_disable,
|
.disable = tegra186_usb3_port_disable,
|
||||||
.map = tegra186_usb3_port_map,
|
.map = tegra186_usb3_port_map,
|
||||||
@@ -635,6 +722,15 @@ static int tegra186_usb3_phy_power_on(struct phy *phy)
|
|||||||
|
|
||||||
padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CAP);
|
padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CAP);
|
||||||
|
|
||||||
|
if (padctl->soc->supports_gen2 && port->disable_gen2) {
|
||||||
|
value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CFG);
|
||||||
|
value &= ~(PORTX_SPEED_SUPPORT_MASK <<
|
||||||
|
PORTX_SPEED_SUPPORT_SHIFT(index));
|
||||||
|
value |= (PORT_SPEED_SUPPORT_GEN1 <<
|
||||||
|
PORTX_SPEED_SUPPORT_SHIFT(index));
|
||||||
|
padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CFG);
|
||||||
|
}
|
||||||
|
|
||||||
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
|
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
|
||||||
value &= ~SSPX_ELPG_VCORE_DOWN(index);
|
value &= ~SSPX_ELPG_VCORE_DOWN(index);
|
||||||
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
|
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
|
||||||
@@ -765,27 +861,6 @@ static const char * const tegra186_usb3_functions[] = {
|
|||||||
"xusb",
|
"xusb",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct tegra_xusb_lane_soc tegra186_usb3_lanes[] = {
|
|
||||||
TEGRA186_LANE("usb3-0", 0, 0, 0, usb3),
|
|
||||||
TEGRA186_LANE("usb3-1", 0, 0, 0, usb3),
|
|
||||||
TEGRA186_LANE("usb3-2", 0, 0, 0, usb3),
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct tegra_xusb_pad_soc tegra186_usb3_pad = {
|
|
||||||
.name = "usb3",
|
|
||||||
.num_lanes = ARRAY_SIZE(tegra186_usb3_lanes),
|
|
||||||
.lanes = tegra186_usb3_lanes,
|
|
||||||
.ops = &tegra186_usb3_pad_ops,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct tegra_xusb_pad_soc * const tegra186_pads[] = {
|
|
||||||
&tegra186_usb2_pad,
|
|
||||||
&tegra186_usb3_pad,
|
|
||||||
#if 0 /* TODO implement */
|
|
||||||
&tegra186_hsic_pad,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl)
|
tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl)
|
||||||
{
|
{
|
||||||
@@ -802,7 +877,9 @@ tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl)
|
|||||||
|
|
||||||
err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
|
err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(dev, "failed to read calibration fuse: %d\n", err);
|
if (err != -EPROBE_DEFER)
|
||||||
|
dev_err(dev, "failed to read calibration fuse: %d\n",
|
||||||
|
err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -857,34 +934,13 @@ static void tegra186_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
|
|
||||||
bool status)
|
|
||||||
{
|
|
||||||
u32 value;
|
|
||||||
|
|
||||||
dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
|
|
||||||
|
|
||||||
value = padctl_readl(padctl, USB2_VBUS_ID);
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
value |= VBUS_OVERRIDE;
|
|
||||||
value &= ~ID_OVERRIDE(~0);
|
|
||||||
value |= ID_OVERRIDE_FLOATING;
|
|
||||||
} else {
|
|
||||||
value &= ~VBUS_OVERRIDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
padctl_writel(padctl, value, USB2_VBUS_ID);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct tegra_xusb_padctl_ops tegra186_xusb_padctl_ops = {
|
static const struct tegra_xusb_padctl_ops tegra186_xusb_padctl_ops = {
|
||||||
.probe = tegra186_xusb_padctl_probe,
|
.probe = tegra186_xusb_padctl_probe,
|
||||||
.remove = tegra186_xusb_padctl_remove,
|
.remove = tegra186_xusb_padctl_remove,
|
||||||
.vbus_override = tegra186_xusb_padctl_vbus_override,
|
.vbus_override = tegra186_xusb_padctl_vbus_override,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
|
||||||
static const char * const tegra186_xusb_padctl_supply_names[] = {
|
static const char * const tegra186_xusb_padctl_supply_names[] = {
|
||||||
"avdd-pll-erefeut",
|
"avdd-pll-erefeut",
|
||||||
"avdd-usb",
|
"avdd-usb",
|
||||||
@@ -892,6 +948,40 @@ static const char * const tegra186_xusb_padctl_supply_names[] = {
|
|||||||
"vddio-hsic",
|
"vddio-hsic",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct tegra_xusb_lane_soc tegra186_usb2_lanes[] = {
|
||||||
|
TEGRA186_LANE("usb2-0", 0, 0, 0, usb2),
|
||||||
|
TEGRA186_LANE("usb2-1", 0, 0, 0, usb2),
|
||||||
|
TEGRA186_LANE("usb2-2", 0, 0, 0, usb2),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct tegra_xusb_pad_soc tegra186_usb2_pad = {
|
||||||
|
.name = "usb2",
|
||||||
|
.num_lanes = ARRAY_SIZE(tegra186_usb2_lanes),
|
||||||
|
.lanes = tegra186_usb2_lanes,
|
||||||
|
.ops = &tegra186_usb2_pad_ops,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct tegra_xusb_lane_soc tegra186_usb3_lanes[] = {
|
||||||
|
TEGRA186_LANE("usb3-0", 0, 0, 0, usb3),
|
||||||
|
TEGRA186_LANE("usb3-1", 0, 0, 0, usb3),
|
||||||
|
TEGRA186_LANE("usb3-2", 0, 0, 0, usb3),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct tegra_xusb_pad_soc tegra186_usb3_pad = {
|
||||||
|
.name = "usb3",
|
||||||
|
.num_lanes = ARRAY_SIZE(tegra186_usb3_lanes),
|
||||||
|
.lanes = tegra186_usb3_lanes,
|
||||||
|
.ops = &tegra186_usb3_pad_ops,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct tegra_xusb_pad_soc * const tegra186_pads[] = {
|
||||||
|
&tegra186_usb2_pad,
|
||||||
|
&tegra186_usb3_pad,
|
||||||
|
#if 0 /* TODO implement */
|
||||||
|
&tegra186_hsic_pad,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc = {
|
const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc = {
|
||||||
.num_pads = ARRAY_SIZE(tegra186_pads),
|
.num_pads = ARRAY_SIZE(tegra186_pads),
|
||||||
.pads = tegra186_pads,
|
.pads = tegra186_pads,
|
||||||
@@ -916,6 +1006,67 @@ const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc = {
|
|||||||
.num_supplies = ARRAY_SIZE(tegra186_xusb_padctl_supply_names),
|
.num_supplies = ARRAY_SIZE(tegra186_xusb_padctl_supply_names),
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(tegra186_xusb_padctl_soc);
|
EXPORT_SYMBOL_GPL(tegra186_xusb_padctl_soc);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
|
||||||
|
static const char * const tegra194_xusb_padctl_supply_names[] = {
|
||||||
|
"avdd-usb",
|
||||||
|
"vclamp-usb",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct tegra_xusb_lane_soc tegra194_usb2_lanes[] = {
|
||||||
|
TEGRA186_LANE("usb2-0", 0, 0, 0, usb2),
|
||||||
|
TEGRA186_LANE("usb2-1", 0, 0, 0, usb2),
|
||||||
|
TEGRA186_LANE("usb2-2", 0, 0, 0, usb2),
|
||||||
|
TEGRA186_LANE("usb2-3", 0, 0, 0, usb2),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct tegra_xusb_pad_soc tegra194_usb2_pad = {
|
||||||
|
.name = "usb2",
|
||||||
|
.num_lanes = ARRAY_SIZE(tegra194_usb2_lanes),
|
||||||
|
.lanes = tegra194_usb2_lanes,
|
||||||
|
.ops = &tegra186_usb2_pad_ops,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct tegra_xusb_lane_soc tegra194_usb3_lanes[] = {
|
||||||
|
TEGRA186_LANE("usb3-0", 0, 0, 0, usb3),
|
||||||
|
TEGRA186_LANE("usb3-1", 0, 0, 0, usb3),
|
||||||
|
TEGRA186_LANE("usb3-2", 0, 0, 0, usb3),
|
||||||
|
TEGRA186_LANE("usb3-3", 0, 0, 0, usb3),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct tegra_xusb_pad_soc tegra194_usb3_pad = {
|
||||||
|
.name = "usb3",
|
||||||
|
.num_lanes = ARRAY_SIZE(tegra194_usb3_lanes),
|
||||||
|
.lanes = tegra194_usb3_lanes,
|
||||||
|
.ops = &tegra186_usb3_pad_ops,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct tegra_xusb_pad_soc * const tegra194_pads[] = {
|
||||||
|
&tegra194_usb2_pad,
|
||||||
|
&tegra194_usb3_pad,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct tegra_xusb_padctl_soc tegra194_xusb_padctl_soc = {
|
||||||
|
.num_pads = ARRAY_SIZE(tegra194_pads),
|
||||||
|
.pads = tegra194_pads,
|
||||||
|
.ports = {
|
||||||
|
.usb2 = {
|
||||||
|
.ops = &tegra186_usb2_port_ops,
|
||||||
|
.count = 4,
|
||||||
|
},
|
||||||
|
.usb3 = {
|
||||||
|
.ops = &tegra186_usb3_port_ops,
|
||||||
|
.count = 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.ops = &tegra186_xusb_padctl_ops,
|
||||||
|
.supply_names = tegra194_xusb_padctl_supply_names,
|
||||||
|
.num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names),
|
||||||
|
.supports_gen2 = true,
|
||||||
|
};
|
||||||
|
EXPORT_SYMBOL_GPL(tegra194_xusb_padctl_soc);
|
||||||
|
#endif
|
||||||
|
|
||||||
MODULE_AUTHOR("JC Kuo <jckuo@nvidia.com>");
|
MODULE_AUTHOR("JC Kuo <jckuo@nvidia.com>");
|
||||||
MODULE_DESCRIPTION("NVIDIA Tegra186 XUSB Pad Controller driver");
|
MODULE_DESCRIPTION("NVIDIA Tegra186 XUSB Pad Controller driver");
|
||||||
|
|||||||
@@ -236,6 +236,7 @@
|
|||||||
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT 18
|
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT 18
|
||||||
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK 0xf
|
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK 0xf
|
||||||
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8
|
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8
|
||||||
|
#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED 0
|
||||||
|
|
||||||
struct tegra210_xusb_fuse_calibration {
|
struct tegra210_xusb_fuse_calibration {
|
||||||
u32 hs_curr_level[4];
|
u32 hs_curr_level[4];
|
||||||
@@ -935,6 +936,103 @@ static int tegra210_usb2_phy_exit(struct phy *phy)
|
|||||||
return tegra210_xusb_padctl_disable(lane->pad->padctl);
|
return tegra210_xusb_padctl_disable(lane->pad->padctl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tegra210_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
|
||||||
|
bool status)
|
||||||
|
{
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
|
||||||
|
|
||||||
|
value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
|
||||||
|
value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
|
||||||
|
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
|
||||||
|
value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
|
||||||
|
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
|
||||||
|
} else {
|
||||||
|
value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra210_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
|
||||||
|
bool status)
|
||||||
|
{
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");
|
||||||
|
|
||||||
|
value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
if (value & XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON) {
|
||||||
|
value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
|
||||||
|
padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
|
||||||
|
usleep_range(1000, 2000);
|
||||||
|
|
||||||
|
value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
|
||||||
|
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
|
||||||
|
value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED <<
|
||||||
|
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
|
||||||
|
} else {
|
||||||
|
value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
|
||||||
|
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
|
||||||
|
value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
|
||||||
|
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra210_usb2_phy_set_mode(struct phy *phy, enum phy_mode mode,
|
||||||
|
int submode)
|
||||||
|
{
|
||||||
|
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
|
||||||
|
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
|
||||||
|
struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
|
||||||
|
lane->index);
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
mutex_lock(&padctl->lock);
|
||||||
|
|
||||||
|
dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
|
||||||
|
|
||||||
|
if (mode == PHY_MODE_USB_OTG) {
|
||||||
|
if (submode == USB_ROLE_HOST) {
|
||||||
|
tegra210_xusb_padctl_id_override(padctl, true);
|
||||||
|
|
||||||
|
err = regulator_enable(port->supply);
|
||||||
|
} else if (submode == USB_ROLE_DEVICE) {
|
||||||
|
tegra210_xusb_padctl_vbus_override(padctl, true);
|
||||||
|
} else if (submode == USB_ROLE_NONE) {
|
||||||
|
/*
|
||||||
|
* When port is peripheral only or role transitions to
|
||||||
|
* USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
|
||||||
|
* be enabled.
|
||||||
|
*/
|
||||||
|
if (regulator_is_enabled(port->supply))
|
||||||
|
regulator_disable(port->supply);
|
||||||
|
|
||||||
|
tegra210_xusb_padctl_id_override(padctl, false);
|
||||||
|
tegra210_xusb_padctl_vbus_override(padctl, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&padctl->lock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int tegra210_usb2_phy_power_on(struct phy *phy)
|
static int tegra210_usb2_phy_power_on(struct phy *phy)
|
||||||
{
|
{
|
||||||
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
|
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
|
||||||
@@ -1048,9 +1146,11 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
|
|||||||
padctl_writel(padctl, value,
|
padctl_writel(padctl, value,
|
||||||
XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
|
XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
|
||||||
|
|
||||||
err = regulator_enable(port->supply);
|
if (port->supply && port->mode == USB_DR_MODE_HOST) {
|
||||||
if (err)
|
err = regulator_enable(port->supply);
|
||||||
return err;
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_lock(&padctl->lock);
|
mutex_lock(&padctl->lock);
|
||||||
|
|
||||||
@@ -1164,6 +1264,7 @@ static const struct phy_ops tegra210_usb2_phy_ops = {
|
|||||||
.exit = tegra210_usb2_phy_exit,
|
.exit = tegra210_usb2_phy_exit,
|
||||||
.power_on = tegra210_usb2_phy_power_on,
|
.power_on = tegra210_usb2_phy_power_on,
|
||||||
.power_off = tegra210_usb2_phy_power_off,
|
.power_off = tegra210_usb2_phy_power_off,
|
||||||
|
.set_mode = tegra210_usb2_phy_set_mode,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1852,6 +1953,8 @@ tegra210_usb2_port_map(struct tegra_xusb_port *port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct tegra_xusb_port_ops tegra210_usb2_port_ops = {
|
static const struct tegra_xusb_port_ops tegra210_usb2_port_ops = {
|
||||||
|
.release = tegra_xusb_usb2_port_release,
|
||||||
|
.remove = tegra_xusb_usb2_port_remove,
|
||||||
.enable = tegra210_usb2_port_enable,
|
.enable = tegra210_usb2_port_enable,
|
||||||
.disable = tegra210_usb2_port_disable,
|
.disable = tegra210_usb2_port_disable,
|
||||||
.map = tegra210_usb2_port_map,
|
.map = tegra210_usb2_port_map,
|
||||||
@@ -1873,6 +1976,7 @@ tegra210_hsic_port_map(struct tegra_xusb_port *port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = {
|
static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = {
|
||||||
|
.release = tegra_xusb_hsic_port_release,
|
||||||
.enable = tegra210_hsic_port_enable,
|
.enable = tegra210_hsic_port_enable,
|
||||||
.disable = tegra210_hsic_port_disable,
|
.disable = tegra210_hsic_port_disable,
|
||||||
.map = tegra210_hsic_port_map,
|
.map = tegra210_hsic_port_map,
|
||||||
@@ -2018,35 +2122,13 @@ tegra210_usb3_port_map(struct tegra_xusb_port *port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = {
|
static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = {
|
||||||
|
.release = tegra_xusb_usb3_port_release,
|
||||||
|
.remove = tegra_xusb_usb3_port_remove,
|
||||||
.enable = tegra210_usb3_port_enable,
|
.enable = tegra210_usb3_port_enable,
|
||||||
.disable = tegra210_usb3_port_disable,
|
.disable = tegra210_usb3_port_disable,
|
||||||
.map = tegra210_usb3_port_map,
|
.map = tegra210_usb3_port_map,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int tegra210_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
|
|
||||||
bool status)
|
|
||||||
{
|
|
||||||
u32 value;
|
|
||||||
|
|
||||||
dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
|
|
||||||
|
|
||||||
value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
|
|
||||||
value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
|
|
||||||
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
|
|
||||||
value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
|
|
||||||
XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
|
|
||||||
} else {
|
|
||||||
value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
|
|
||||||
}
|
|
||||||
|
|
||||||
padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tegra210_utmi_port_reset(struct phy *phy)
|
static int tegra210_utmi_port_reset(struct phy *phy)
|
||||||
{
|
{
|
||||||
struct tegra_xusb_padctl *padctl;
|
struct tegra_xusb_padctl *padctl;
|
||||||
|
|||||||
@@ -65,6 +65,12 @@ static const struct of_device_id tegra_xusb_padctl_of_match[] = {
|
|||||||
.compatible = "nvidia,tegra186-xusb-padctl",
|
.compatible = "nvidia,tegra186-xusb-padctl",
|
||||||
.data = &tegra186_xusb_padctl_soc,
|
.data = &tegra186_xusb_padctl_soc,
|
||||||
},
|
},
|
||||||
|
#endif
|
||||||
|
#if defined(CONFIG_ARCH_TEGRA_194_SOC)
|
||||||
|
{
|
||||||
|
.compatible = "nvidia,tegra194-xusb-padctl",
|
||||||
|
.data = &tegra194_xusb_padctl_soc,
|
||||||
|
},
|
||||||
#endif
|
#endif
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
@@ -501,6 +507,10 @@ tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl, unsigned int index)
|
|||||||
|
|
||||||
static void tegra_xusb_port_release(struct device *dev)
|
static void tegra_xusb_port_release(struct device *dev)
|
||||||
{
|
{
|
||||||
|
struct tegra_xusb_port *port = to_tegra_xusb_port(dev);
|
||||||
|
|
||||||
|
if (port->ops->release)
|
||||||
|
port->ops->release(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct device_type tegra_xusb_port_type = {
|
static struct device_type tegra_xusb_port_type = {
|
||||||
@@ -541,6 +551,16 @@ unregister:
|
|||||||
|
|
||||||
static void tegra_xusb_port_unregister(struct tegra_xusb_port *port)
|
static void tegra_xusb_port_unregister(struct tegra_xusb_port *port)
|
||||||
{
|
{
|
||||||
|
if (!IS_ERR_OR_NULL(port->usb_role_sw)) {
|
||||||
|
of_platform_depopulate(&port->dev);
|
||||||
|
usb_role_switch_unregister(port->usb_role_sw);
|
||||||
|
cancel_work_sync(&port->usb_phy_work);
|
||||||
|
usb_remove_phy(&port->usb_phy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port->ops->remove)
|
||||||
|
port->ops->remove(port);
|
||||||
|
|
||||||
device_unregister(&port->dev);
|
device_unregister(&port->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,11 +571,146 @@ static const char *const modes[] = {
|
|||||||
[USB_DR_MODE_OTG] = "otg",
|
[USB_DR_MODE_OTG] = "otg",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char * const usb_roles[] = {
|
||||||
|
[USB_ROLE_NONE] = "none",
|
||||||
|
[USB_ROLE_HOST] = "host",
|
||||||
|
[USB_ROLE_DEVICE] = "device",
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum usb_phy_events to_usb_phy_event(enum usb_role role)
|
||||||
|
{
|
||||||
|
switch (role) {
|
||||||
|
case USB_ROLE_DEVICE:
|
||||||
|
return USB_EVENT_VBUS;
|
||||||
|
|
||||||
|
case USB_ROLE_HOST:
|
||||||
|
return USB_EVENT_ID;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return USB_EVENT_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_xusb_usb_phy_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct tegra_xusb_port *port = container_of(work,
|
||||||
|
struct tegra_xusb_port,
|
||||||
|
usb_phy_work);
|
||||||
|
enum usb_role role = usb_role_switch_get_role(port->usb_role_sw);
|
||||||
|
|
||||||
|
usb_phy_set_event(&port->usb_phy, to_usb_phy_event(role));
|
||||||
|
|
||||||
|
dev_dbg(&port->dev, "%s(): calling notifier for role %s\n", __func__,
|
||||||
|
usb_roles[role]);
|
||||||
|
|
||||||
|
atomic_notifier_call_chain(&port->usb_phy.notifier, 0, &port->usb_phy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_xusb_role_sw_set(struct usb_role_switch *sw,
|
||||||
|
enum usb_role role)
|
||||||
|
{
|
||||||
|
struct tegra_xusb_port *port = usb_role_switch_get_drvdata(sw);
|
||||||
|
|
||||||
|
dev_dbg(&port->dev, "%s(): role %s\n", __func__, usb_roles[role]);
|
||||||
|
|
||||||
|
schedule_work(&port->usb_phy_work);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_xusb_set_peripheral(struct usb_otg *otg,
|
||||||
|
struct usb_gadget *gadget)
|
||||||
|
{
|
||||||
|
struct tegra_xusb_port *port = container_of(otg->usb_phy,
|
||||||
|
struct tegra_xusb_port,
|
||||||
|
usb_phy);
|
||||||
|
|
||||||
|
if (gadget != NULL)
|
||||||
|
schedule_work(&port->usb_phy_work);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_xusb_set_host(struct usb_otg *otg, struct usb_bus *host)
|
||||||
|
{
|
||||||
|
struct tegra_xusb_port *port = container_of(otg->usb_phy,
|
||||||
|
struct tegra_xusb_port,
|
||||||
|
usb_phy);
|
||||||
|
|
||||||
|
if (host != NULL)
|
||||||
|
schedule_work(&port->usb_phy_work);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_xusb_lane *lane;
|
||||||
|
struct usb_role_switch_desc role_sx_desc = {
|
||||||
|
.fwnode = dev_fwnode(&port->dev),
|
||||||
|
.set = tegra_xusb_role_sw_set,
|
||||||
|
};
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* USB role switch driver needs parent driver owner info. This is a
|
||||||
|
* suboptimal solution. TODO: Need to revisit this in a follow-up patch
|
||||||
|
* where an optimal solution is possible with changes to USB role
|
||||||
|
* switch driver.
|
||||||
|
*/
|
||||||
|
port->dev.driver = devm_kzalloc(&port->dev,
|
||||||
|
sizeof(struct device_driver),
|
||||||
|
GFP_KERNEL);
|
||||||
|
port->dev.driver->owner = THIS_MODULE;
|
||||||
|
|
||||||
|
port->usb_role_sw = usb_role_switch_register(&port->dev,
|
||||||
|
&role_sx_desc);
|
||||||
|
if (IS_ERR(port->usb_role_sw)) {
|
||||||
|
err = PTR_ERR(port->usb_role_sw);
|
||||||
|
dev_err(&port->dev, "failed to register USB role switch: %d",
|
||||||
|
err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT_WORK(&port->usb_phy_work, tegra_xusb_usb_phy_work);
|
||||||
|
usb_role_switch_set_drvdata(port->usb_role_sw, port);
|
||||||
|
|
||||||
|
port->usb_phy.otg = devm_kzalloc(&port->dev, sizeof(struct usb_otg),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!port->usb_phy.otg)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
lane = tegra_xusb_find_lane(port->padctl, "usb2", port->index);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assign phy dev to usb-phy dev. Host/device drivers can use phy
|
||||||
|
* reference to retrieve usb-phy details.
|
||||||
|
*/
|
||||||
|
port->usb_phy.dev = &lane->pad->lanes[port->index]->dev;
|
||||||
|
port->usb_phy.dev->driver = port->padctl->dev->driver;
|
||||||
|
port->usb_phy.otg->usb_phy = &port->usb_phy;
|
||||||
|
port->usb_phy.otg->set_peripheral = tegra_xusb_set_peripheral;
|
||||||
|
port->usb_phy.otg->set_host = tegra_xusb_set_host;
|
||||||
|
|
||||||
|
err = usb_add_phy_dev(&port->usb_phy);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(&port->dev, "Failed to add USB PHY: %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* populate connector entry */
|
||||||
|
of_platform_populate(port->dev.of_node, NULL, NULL, &port->dev);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
|
static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
|
||||||
{
|
{
|
||||||
struct tegra_xusb_port *port = &usb2->base;
|
struct tegra_xusb_port *port = &usb2->base;
|
||||||
struct device_node *np = port->dev.of_node;
|
struct device_node *np = port->dev.of_node;
|
||||||
const char *mode;
|
const char *mode;
|
||||||
|
int err;
|
||||||
|
|
||||||
usb2->internal = of_property_read_bool(np, "nvidia,internal");
|
usb2->internal = of_property_read_bool(np, "nvidia,internal");
|
||||||
|
|
||||||
@@ -572,7 +727,21 @@ static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
|
|||||||
usb2->mode = USB_DR_MODE_HOST;
|
usb2->mode = USB_DR_MODE_HOST;
|
||||||
}
|
}
|
||||||
|
|
||||||
usb2->supply = devm_regulator_get(&port->dev, "vbus");
|
/* usb-role-switch property is mandatory for OTG/Peripheral modes */
|
||||||
|
if (usb2->mode == USB_DR_MODE_PERIPHERAL ||
|
||||||
|
usb2->mode == USB_DR_MODE_OTG) {
|
||||||
|
if (of_property_read_bool(np, "usb-role-switch")) {
|
||||||
|
err = tegra_xusb_setup_usb_role_switch(port);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
} else {
|
||||||
|
dev_err(&port->dev, "usb-role-switch not found for %s mode",
|
||||||
|
modes[usb2->mode]);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usb2->supply = regulator_get(&port->dev, "vbus");
|
||||||
return PTR_ERR_OR_ZERO(usb2->supply);
|
return PTR_ERR_OR_ZERO(usb2->supply);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -591,7 +760,7 @@ static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl,
|
|||||||
if (!np || !of_device_is_available(np))
|
if (!np || !of_device_is_available(np))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
usb2 = devm_kzalloc(padctl->dev, sizeof(*usb2), GFP_KERNEL);
|
usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
|
||||||
if (!usb2) {
|
if (!usb2) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -622,6 +791,20 @@ out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tegra_xusb_usb2_port_release(struct tegra_xusb_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_xusb_usb2_port *usb2 = to_usb2_port(port);
|
||||||
|
|
||||||
|
kfree(usb2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tegra_xusb_usb2_port_remove(struct tegra_xusb_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_xusb_usb2_port *usb2 = to_usb2_port(port);
|
||||||
|
|
||||||
|
regulator_put(usb2->supply);
|
||||||
|
}
|
||||||
|
|
||||||
static int tegra_xusb_ulpi_port_parse_dt(struct tegra_xusb_ulpi_port *ulpi)
|
static int tegra_xusb_ulpi_port_parse_dt(struct tegra_xusb_ulpi_port *ulpi)
|
||||||
{
|
{
|
||||||
struct tegra_xusb_port *port = &ulpi->base;
|
struct tegra_xusb_port *port = &ulpi->base;
|
||||||
@@ -643,7 +826,7 @@ static int tegra_xusb_add_ulpi_port(struct tegra_xusb_padctl *padctl,
|
|||||||
if (!np || !of_device_is_available(np))
|
if (!np || !of_device_is_available(np))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ulpi = devm_kzalloc(padctl->dev, sizeof(*ulpi), GFP_KERNEL);
|
ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL);
|
||||||
if (!ulpi) {
|
if (!ulpi) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -674,6 +857,13 @@ out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tegra_xusb_ulpi_port_release(struct tegra_xusb_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_xusb_ulpi_port *ulpi = to_ulpi_port(port);
|
||||||
|
|
||||||
|
kfree(ulpi);
|
||||||
|
}
|
||||||
|
|
||||||
static int tegra_xusb_hsic_port_parse_dt(struct tegra_xusb_hsic_port *hsic)
|
static int tegra_xusb_hsic_port_parse_dt(struct tegra_xusb_hsic_port *hsic)
|
||||||
{
|
{
|
||||||
/* XXX */
|
/* XXX */
|
||||||
@@ -691,7 +881,7 @@ static int tegra_xusb_add_hsic_port(struct tegra_xusb_padctl *padctl,
|
|||||||
if (!np || !of_device_is_available(np))
|
if (!np || !of_device_is_available(np))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
hsic = devm_kzalloc(padctl->dev, sizeof(*hsic), GFP_KERNEL);
|
hsic = kzalloc(sizeof(*hsic), GFP_KERNEL);
|
||||||
if (!hsic) {
|
if (!hsic) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -722,10 +912,18 @@ out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tegra_xusb_hsic_port_release(struct tegra_xusb_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_xusb_hsic_port *hsic = to_hsic_port(port);
|
||||||
|
|
||||||
|
kfree(hsic);
|
||||||
|
}
|
||||||
|
|
||||||
static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3)
|
static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3)
|
||||||
{
|
{
|
||||||
struct tegra_xusb_port *port = &usb3->base;
|
struct tegra_xusb_port *port = &usb3->base;
|
||||||
struct device_node *np = port->dev.of_node;
|
struct device_node *np = port->dev.of_node;
|
||||||
|
enum usb_device_speed maximum_speed;
|
||||||
u32 value;
|
u32 value;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -739,7 +937,17 @@ static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3)
|
|||||||
|
|
||||||
usb3->internal = of_property_read_bool(np, "nvidia,internal");
|
usb3->internal = of_property_read_bool(np, "nvidia,internal");
|
||||||
|
|
||||||
usb3->supply = devm_regulator_get(&port->dev, "vbus");
|
if (device_property_present(&port->dev, "maximum-speed")) {
|
||||||
|
maximum_speed = usb_get_maximum_speed(&port->dev);
|
||||||
|
if (maximum_speed == USB_SPEED_SUPER)
|
||||||
|
usb3->disable_gen2 = true;
|
||||||
|
else if (maximum_speed == USB_SPEED_SUPER_PLUS)
|
||||||
|
usb3->disable_gen2 = false;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
usb3->supply = regulator_get(&port->dev, "vbus");
|
||||||
return PTR_ERR_OR_ZERO(usb3->supply);
|
return PTR_ERR_OR_ZERO(usb3->supply);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -759,7 +967,7 @@ static int tegra_xusb_add_usb3_port(struct tegra_xusb_padctl *padctl,
|
|||||||
if (!np || !of_device_is_available(np))
|
if (!np || !of_device_is_available(np))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
usb3 = devm_kzalloc(padctl->dev, sizeof(*usb3), GFP_KERNEL);
|
usb3 = kzalloc(sizeof(*usb3), GFP_KERNEL);
|
||||||
if (!usb3) {
|
if (!usb3) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -790,6 +998,20 @@ out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tegra_xusb_usb3_port_release(struct tegra_xusb_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
|
||||||
|
|
||||||
|
kfree(usb3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tegra_xusb_usb3_port_remove(struct tegra_xusb_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
|
||||||
|
|
||||||
|
regulator_put(usb3->supply);
|
||||||
|
}
|
||||||
|
|
||||||
static void __tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl)
|
static void __tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl)
|
||||||
{
|
{
|
||||||
struct tegra_xusb_port *port, *tmp;
|
struct tegra_xusb_port *port, *tmp;
|
||||||
@@ -1001,7 +1223,13 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
err = tegra_xusb_setup_ports(padctl);
|
err = tegra_xusb_setup_ports(padctl);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&pdev->dev, "failed to setup XUSB ports: %d\n", err);
|
const char *level = KERN_ERR;
|
||||||
|
|
||||||
|
if (err == -EPROBE_DEFER)
|
||||||
|
level = KERN_DEBUG;
|
||||||
|
|
||||||
|
dev_printk(level, &pdev->dev,
|
||||||
|
dev_fmt("failed to setup XUSB ports: %d\n"), err);
|
||||||
goto remove_pads;
|
goto remove_pads;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1143,6 +1371,27 @@ int tegra_phy_xusb_utmi_port_reset(struct phy *phy)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_port_reset);
|
EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_port_reset);
|
||||||
|
|
||||||
|
int tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl *padctl,
|
||||||
|
unsigned int port)
|
||||||
|
{
|
||||||
|
struct tegra_xusb_usb2_port *usb2;
|
||||||
|
struct tegra_xusb_usb3_port *usb3;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
usb2 = tegra_xusb_find_usb2_port(padctl, port);
|
||||||
|
if (!usb2)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for (i = 0; i < padctl->soc->ports.usb3.count; i++) {
|
||||||
|
usb3 = tegra_xusb_find_usb3_port(padctl, i);
|
||||||
|
if (usb3 && usb3->port == usb2->base.index)
|
||||||
|
return usb3->base.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(tegra_xusb_padctl_get_usb3_companion);
|
||||||
|
|
||||||
MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
|
MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
|
||||||
MODULE_DESCRIPTION("Tegra XUSB Pad Controller driver");
|
MODULE_DESCRIPTION("Tegra XUSB Pad Controller driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
#include <linux/usb/otg.h>
|
#include <linux/usb/otg.h>
|
||||||
|
#include <linux/usb/role.h>
|
||||||
|
|
||||||
/* legacy entry points for backwards-compatibility */
|
/* legacy entry points for backwards-compatibility */
|
||||||
int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev);
|
int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev);
|
||||||
@@ -266,9 +267,18 @@ struct tegra_xusb_port {
|
|||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct device dev;
|
struct device dev;
|
||||||
|
|
||||||
|
struct usb_role_switch *usb_role_sw;
|
||||||
|
struct work_struct usb_phy_work;
|
||||||
|
struct usb_phy usb_phy;
|
||||||
|
|
||||||
const struct tegra_xusb_port_ops *ops;
|
const struct tegra_xusb_port_ops *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline struct tegra_xusb_port *to_tegra_xusb_port(struct device *dev)
|
||||||
|
{
|
||||||
|
return container_of(dev, struct tegra_xusb_port, dev);
|
||||||
|
}
|
||||||
|
|
||||||
struct tegra_xusb_lane_map {
|
struct tegra_xusb_lane_map {
|
||||||
unsigned int port;
|
unsigned int port;
|
||||||
const char *type;
|
const char *type;
|
||||||
@@ -303,6 +313,8 @@ to_usb2_port(struct tegra_xusb_port *port)
|
|||||||
struct tegra_xusb_usb2_port *
|
struct tegra_xusb_usb2_port *
|
||||||
tegra_xusb_find_usb2_port(struct tegra_xusb_padctl *padctl,
|
tegra_xusb_find_usb2_port(struct tegra_xusb_padctl *padctl,
|
||||||
unsigned int index);
|
unsigned int index);
|
||||||
|
void tegra_xusb_usb2_port_release(struct tegra_xusb_port *port);
|
||||||
|
void tegra_xusb_usb2_port_remove(struct tegra_xusb_port *port);
|
||||||
|
|
||||||
struct tegra_xusb_ulpi_port {
|
struct tegra_xusb_ulpi_port {
|
||||||
struct tegra_xusb_port base;
|
struct tegra_xusb_port base;
|
||||||
@@ -317,6 +329,8 @@ to_ulpi_port(struct tegra_xusb_port *port)
|
|||||||
return container_of(port, struct tegra_xusb_ulpi_port, base);
|
return container_of(port, struct tegra_xusb_ulpi_port, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tegra_xusb_ulpi_port_release(struct tegra_xusb_port *port);
|
||||||
|
|
||||||
struct tegra_xusb_hsic_port {
|
struct tegra_xusb_hsic_port {
|
||||||
struct tegra_xusb_port base;
|
struct tegra_xusb_port base;
|
||||||
};
|
};
|
||||||
@@ -327,12 +341,15 @@ to_hsic_port(struct tegra_xusb_port *port)
|
|||||||
return container_of(port, struct tegra_xusb_hsic_port, base);
|
return container_of(port, struct tegra_xusb_hsic_port, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tegra_xusb_hsic_port_release(struct tegra_xusb_port *port);
|
||||||
|
|
||||||
struct tegra_xusb_usb3_port {
|
struct tegra_xusb_usb3_port {
|
||||||
struct tegra_xusb_port base;
|
struct tegra_xusb_port base;
|
||||||
struct regulator *supply;
|
struct regulator *supply;
|
||||||
bool context_saved;
|
bool context_saved;
|
||||||
unsigned int port;
|
unsigned int port;
|
||||||
bool internal;
|
bool internal;
|
||||||
|
bool disable_gen2;
|
||||||
|
|
||||||
u32 tap1;
|
u32 tap1;
|
||||||
u32 amp;
|
u32 amp;
|
||||||
@@ -349,8 +366,12 @@ to_usb3_port(struct tegra_xusb_port *port)
|
|||||||
struct tegra_xusb_usb3_port *
|
struct tegra_xusb_usb3_port *
|
||||||
tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl,
|
tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl,
|
||||||
unsigned int index);
|
unsigned int index);
|
||||||
|
void tegra_xusb_usb3_port_release(struct tegra_xusb_port *port);
|
||||||
|
void tegra_xusb_usb3_port_remove(struct tegra_xusb_port *port);
|
||||||
|
|
||||||
struct tegra_xusb_port_ops {
|
struct tegra_xusb_port_ops {
|
||||||
|
void (*release)(struct tegra_xusb_port *port);
|
||||||
|
void (*remove)(struct tegra_xusb_port *port);
|
||||||
int (*enable)(struct tegra_xusb_port *port);
|
int (*enable)(struct tegra_xusb_port *port);
|
||||||
void (*disable)(struct tegra_xusb_port *port);
|
void (*disable)(struct tegra_xusb_port *port);
|
||||||
struct tegra_xusb_lane *(*map)(struct tegra_xusb_port *port);
|
struct tegra_xusb_lane *(*map)(struct tegra_xusb_port *port);
|
||||||
@@ -392,6 +413,7 @@ struct tegra_xusb_padctl_soc {
|
|||||||
|
|
||||||
const char * const *supply_names;
|
const char * const *supply_names;
|
||||||
unsigned int num_supplies;
|
unsigned int num_supplies;
|
||||||
|
bool supports_gen2;
|
||||||
bool need_fake_usb3_port;
|
bool need_fake_usb3_port;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -448,5 +470,8 @@ extern const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc;
|
|||||||
#if defined(CONFIG_ARCH_TEGRA_186_SOC)
|
#if defined(CONFIG_ARCH_TEGRA_186_SOC)
|
||||||
extern const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc;
|
extern const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc;
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(CONFIG_ARCH_TEGRA_194_SOC)
|
||||||
|
extern const struct tegra_xusb_padctl_soc tegra194_xusb_padctl_soc;
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __PHY_TEGRA_XUSB_H */
|
#endif /* __PHY_TEGRA_XUSB_H */
|
||||||
|
|||||||
@@ -170,6 +170,21 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dm814 = {
|
|||||||
.regfields = phy_gmii_sel_fields_am33xx,
|
.regfields = phy_gmii_sel_fields_am33xx,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const
|
||||||
|
struct reg_field phy_gmii_sel_fields_am654[][PHY_GMII_SEL_LAST] = {
|
||||||
|
{
|
||||||
|
[PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4040, 0, 1),
|
||||||
|
[PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD((~0), 0, 0),
|
||||||
|
[PHY_GMII_SEL_RMII_IO_CLK_EN] = REG_FIELD((~0), 0, 0),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const
|
||||||
|
struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = {
|
||||||
|
.num_ports = 1,
|
||||||
|
.regfields = phy_gmii_sel_fields_am654,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct of_device_id phy_gmii_sel_id_table[] = {
|
static const struct of_device_id phy_gmii_sel_id_table[] = {
|
||||||
{
|
{
|
||||||
.compatible = "ti,am3352-phy-gmii-sel",
|
.compatible = "ti,am3352-phy-gmii-sel",
|
||||||
@@ -187,6 +202,10 @@ static const struct of_device_id phy_gmii_sel_id_table[] = {
|
|||||||
.compatible = "ti,dm814-phy-gmii-sel",
|
.compatible = "ti,dm814-phy-gmii-sel",
|
||||||
.data = &phy_gmii_sel_soc_dm814,
|
.data = &phy_gmii_sel_soc_dm814,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.compatible = "ti,am654-phy-gmii-sel",
|
||||||
|
.data = &phy_gmii_sel_soc_am654,
|
||||||
|
},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, phy_gmii_sel_id_table);
|
MODULE_DEVICE_TABLE(of, phy_gmii_sel_id_table);
|
||||||
|
|||||||
@@ -147,10 +147,10 @@ static ssize_t boot_acl_show(struct device *dev, struct device_attribute *attr,
|
|||||||
|
|
||||||
for (ret = 0, i = 0; i < tb->nboot_acl; i++) {
|
for (ret = 0, i = 0; i < tb->nboot_acl; i++) {
|
||||||
if (!uuid_is_null(&uuids[i]))
|
if (!uuid_is_null(&uuids[i]))
|
||||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%pUb",
|
ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%pUb",
|
||||||
&uuids[i]);
|
&uuids[i]);
|
||||||
|
|
||||||
ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s",
|
ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s",
|
||||||
i < tb->nboot_acl - 1 ? "," : "\n");
|
i < tb->nboot_acl - 1 ? "," : "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ struct tb_drom_entry_header {
|
|||||||
|
|
||||||
struct tb_drom_entry_generic {
|
struct tb_drom_entry_generic {
|
||||||
struct tb_drom_entry_header header;
|
struct tb_drom_entry_header header;
|
||||||
u8 data[0];
|
u8 data[];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct tb_drom_entry_port {
|
struct tb_drom_entry_port {
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ struct icm_notification {
|
|||||||
struct ep_name_entry {
|
struct ep_name_entry {
|
||||||
u8 len;
|
u8 len;
|
||||||
u8 type;
|
u8 type;
|
||||||
u8 data[0];
|
u8 data[];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define EP_NAME_INTEL_VSS 0x10
|
#define EP_NAME_INTEL_VSS 0x10
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ int usb4_switch_setup(struct tb_switch *sw)
|
|||||||
/**
|
/**
|
||||||
* usb4_switch_read_uid() - Read UID from USB4 router
|
* usb4_switch_read_uid() - Read UID from USB4 router
|
||||||
* @sw: USB4 router
|
* @sw: USB4 router
|
||||||
|
* @uid: UID is stored here
|
||||||
*
|
*
|
||||||
* Reads 64-bit UID from USB4 router config space.
|
* Reads 64-bit UID from USB4 router config space.
|
||||||
*/
|
*/
|
||||||
@@ -296,6 +297,9 @@ static int usb4_switch_drom_read_block(struct tb_switch *sw,
|
|||||||
/**
|
/**
|
||||||
* usb4_switch_drom_read() - Read arbitrary bytes from USB4 router DROM
|
* usb4_switch_drom_read() - Read arbitrary bytes from USB4 router DROM
|
||||||
* @sw: USB4 router
|
* @sw: USB4 router
|
||||||
|
* @address: Byte address inside DROM to start reading
|
||||||
|
* @buf: Buffer where the DROM content is stored
|
||||||
|
* @size: Number of bytes to read from DROM
|
||||||
*
|
*
|
||||||
* Uses USB4 router operations to read router DROM. For devices this
|
* Uses USB4 router operations to read router DROM. For devices this
|
||||||
* should always work but for hosts it may return %-EOPNOTSUPP in which
|
* should always work but for hosts it may return %-EOPNOTSUPP in which
|
||||||
|
|||||||
@@ -350,7 +350,7 @@ struct l1_code {
|
|||||||
u8 string_header[E4_L1_STRING_HEADER];
|
u8 string_header[E4_L1_STRING_HEADER];
|
||||||
u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
|
u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
|
||||||
struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
|
struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
|
||||||
u8 code[0];
|
u8 code[];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
/* structures describing a block within a DSP page */
|
/* structures describing a block within a DSP page */
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0+
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* usbatm.h - Generic USB xDSL driver core
|
* usbatm.h - Generic USB xDSL driver core
|
||||||
*
|
*
|
||||||
@@ -164,7 +164,7 @@ struct usbatm_data {
|
|||||||
unsigned char *cell_buf; /* holds partial rx cell */
|
unsigned char *cell_buf; /* holds partial rx cell */
|
||||||
unsigned int buf_usage;
|
unsigned int buf_usage;
|
||||||
|
|
||||||
struct urb *urbs[0];
|
struct urb *urbs[];
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void *to_usbatm_driver_data(struct usb_interface *intf)
|
static inline void *to_usbatm_driver_data(struct usb_interface *intf)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0+
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
/*
|
/*
|
||||||
* c67x00-hcd.h: Cypress C67X00 USB HCD
|
* c67x00-hcd.h: Cypress C67X00 USB HCD
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0+
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
/*
|
/*
|
||||||
* c67x00.h: Cypress C67X00 USB register and field definitions
|
* c67x00.h: Cypress C67X00 USB register and field definitions
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -201,4 +201,4 @@ MODULE_DEVICE_TABLE(pci, cdns3_pci_ids);
|
|||||||
|
|
||||||
MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
|
MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
MODULE_DESCRIPTION("Cadence USBSS PCI wrapperr");
|
MODULE_DESCRIPTION("Cadence USBSS PCI wrapper");
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ enum modestrap_mode { USBSS_MODESTRAP_MODE_NONE,
|
|||||||
struct cdns_ti {
|
struct cdns_ti {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
void __iomem *usbss;
|
void __iomem *usbss;
|
||||||
int usb2_only:1;
|
unsigned usb2_only:1;
|
||||||
int vbus_divider:1;
|
unsigned vbus_divider:1;
|
||||||
struct clk *usb2_refclk;
|
struct clk *usb2_refclk;
|
||||||
struct clk *lpm_clk;
|
struct clk *lpm_clk;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -330,9 +330,9 @@ exit:
|
|||||||
*
|
*
|
||||||
* Returns role
|
* Returns role
|
||||||
*/
|
*/
|
||||||
static enum usb_role cdns3_role_get(struct device *dev)
|
static enum usb_role cdns3_role_get(struct usb_role_switch *sw)
|
||||||
{
|
{
|
||||||
struct cdns3 *cdns = dev_get_drvdata(dev);
|
struct cdns3 *cdns = usb_role_switch_get_drvdata(sw);
|
||||||
|
|
||||||
return cdns->role;
|
return cdns->role;
|
||||||
}
|
}
|
||||||
@@ -346,9 +346,9 @@ static enum usb_role cdns3_role_get(struct device *dev)
|
|||||||
* - Role switch for dual-role devices
|
* - Role switch for dual-role devices
|
||||||
* - USB_ROLE_GADGET <--> USB_ROLE_NONE for peripheral-only devices
|
* - USB_ROLE_GADGET <--> USB_ROLE_NONE for peripheral-only devices
|
||||||
*/
|
*/
|
||||||
static int cdns3_role_set(struct device *dev, enum usb_role role)
|
static int cdns3_role_set(struct usb_role_switch *sw, enum usb_role role)
|
||||||
{
|
{
|
||||||
struct cdns3 *cdns = dev_get_drvdata(dev);
|
struct cdns3 *cdns = usb_role_switch_get_drvdata(sw);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
pm_runtime_get_sync(cdns->dev);
|
pm_runtime_get_sync(cdns->dev);
|
||||||
@@ -423,12 +423,6 @@ pm_put:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct usb_role_switch_desc cdns3_switch_desc = {
|
|
||||||
.set = cdns3_role_set,
|
|
||||||
.get = cdns3_role_get,
|
|
||||||
.allow_userspace_control = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cdns3_probe - probe for cdns3 core device
|
* cdns3_probe - probe for cdns3 core device
|
||||||
* @pdev: Pointer to cdns3 core platform device
|
* @pdev: Pointer to cdns3 core platform device
|
||||||
@@ -437,6 +431,7 @@ static const struct usb_role_switch_desc cdns3_switch_desc = {
|
|||||||
*/
|
*/
|
||||||
static int cdns3_probe(struct platform_device *pdev)
|
static int cdns3_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
struct usb_role_switch_desc sw_desc = { };
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
struct cdns3 *cdns;
|
struct cdns3 *cdns;
|
||||||
@@ -529,7 +524,12 @@ static int cdns3_probe(struct platform_device *pdev)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err3;
|
goto err3;
|
||||||
|
|
||||||
cdns->role_sw = usb_role_switch_register(dev, &cdns3_switch_desc);
|
sw_desc.set = cdns3_role_set;
|
||||||
|
sw_desc.get = cdns3_role_get;
|
||||||
|
sw_desc.allow_userspace_control = true;
|
||||||
|
sw_desc.driver_data = cdns;
|
||||||
|
|
||||||
|
cdns->role_sw = usb_role_switch_register(dev, &sw_desc);
|
||||||
if (IS_ERR(cdns->role_sw)) {
|
if (IS_ERR(cdns->role_sw)) {
|
||||||
ret = PTR_ERR(cdns->role_sw);
|
ret = PTR_ERR(cdns->role_sw);
|
||||||
dev_warn(dev, "Unable to register Role Switch\n");
|
dev_warn(dev, "Unable to register Role Switch\n");
|
||||||
|
|||||||
@@ -1380,7 +1380,7 @@ static bool cdns3_request_handled(struct cdns3_endpoint *priv_ep,
|
|||||||
struct cdns3_request *priv_req)
|
struct cdns3_request *priv_req)
|
||||||
{
|
{
|
||||||
struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
|
struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
|
||||||
struct cdns3_trb *trb = priv_req->trb;
|
struct cdns3_trb *trb;
|
||||||
int current_index = 0;
|
int current_index = 0;
|
||||||
int handled = 0;
|
int handled = 0;
|
||||||
int doorbell;
|
int doorbell;
|
||||||
|
|||||||
@@ -1199,7 +1199,7 @@ struct cdns3_aligned_buf {
|
|||||||
void *buf;
|
void *buf;
|
||||||
dma_addr_t dma;
|
dma_addr_t dma;
|
||||||
u32 size;
|
u32 size;
|
||||||
int in_use:1;
|
unsigned in_use:1;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1308,8 +1308,8 @@ struct cdns3_device {
|
|||||||
unsigned u2_allowed:1;
|
unsigned u2_allowed:1;
|
||||||
unsigned is_selfpowered:1;
|
unsigned is_selfpowered:1;
|
||||||
unsigned setup_pending:1;
|
unsigned setup_pending:1;
|
||||||
int hw_configured_flag:1;
|
unsigned hw_configured_flag:1;
|
||||||
int wake_up_flag:1;
|
unsigned wake_up_flag:1;
|
||||||
unsigned status_completion_no_call:1;
|
unsigned status_completion_no_call:1;
|
||||||
unsigned using_streams:1;
|
unsigned using_streams:1;
|
||||||
int out_mem_is_allocated;
|
int out_mem_is_allocated;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/*
|
/*
|
||||||
* bits.h - register bits of the ChipIdea USB IP core
|
* bits.h - register bits of the ChipIdea USB IP core
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/*
|
/*
|
||||||
* ci.h - common structures, functions, and macros of the ChipIdea driver
|
* ci.h - common structures, functions, and macros of the ChipIdea driver
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0+
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
/*
|
/*
|
||||||
* Copyright 2012 Freescale Semiconductor, Inc.
|
* Copyright 2012 Freescale Semiconductor, Inc.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -600,9 +600,9 @@ static int ci_cable_notifier(struct notifier_block *nb, unsigned long event,
|
|||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum usb_role ci_usb_role_switch_get(struct device *dev)
|
static enum usb_role ci_usb_role_switch_get(struct usb_role_switch *sw)
|
||||||
{
|
{
|
||||||
struct ci_hdrc *ci = dev_get_drvdata(dev);
|
struct ci_hdrc *ci = usb_role_switch_get_drvdata(sw);
|
||||||
enum usb_role role;
|
enum usb_role role;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
@@ -613,9 +613,10 @@ static enum usb_role ci_usb_role_switch_get(struct device *dev)
|
|||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ci_usb_role_switch_set(struct device *dev, enum usb_role role)
|
static int ci_usb_role_switch_set(struct usb_role_switch *sw,
|
||||||
|
enum usb_role role)
|
||||||
{
|
{
|
||||||
struct ci_hdrc *ci = dev_get_drvdata(dev);
|
struct ci_hdrc *ci = usb_role_switch_get_drvdata(sw);
|
||||||
struct ci_hdrc_cable *cable = NULL;
|
struct ci_hdrc_cable *cable = NULL;
|
||||||
enum usb_role current_role = ci_role_to_usb_role(ci);
|
enum usb_role current_role = ci_role_to_usb_role(ci);
|
||||||
enum ci_role ci_role = usb_role_to_ci_role(role);
|
enum ci_role ci_role = usb_role_to_ci_role(role);
|
||||||
@@ -1118,6 +1119,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ci_role_switch.fwnode) {
|
if (ci_role_switch.fwnode) {
|
||||||
|
ci_role_switch.driver_data = ci;
|
||||||
ci->role_switch = usb_role_switch_register(dev,
|
ci->role_switch = usb_role_switch_register(dev,
|
||||||
&ci_role_switch);
|
&ci_role_switch);
|
||||||
if (IS_ERR(ci->role_switch)) {
|
if (IS_ERR(ci->role_switch)) {
|
||||||
|
|||||||
@@ -170,6 +170,13 @@ static void ci_handle_id_switch(struct ci_hdrc *ci)
|
|||||||
dev_dbg(ci->dev, "switching from %s to %s\n",
|
dev_dbg(ci->dev, "switching from %s to %s\n",
|
||||||
ci_role(ci)->name, ci->roles[role]->name);
|
ci_role(ci)->name, ci->roles[role]->name);
|
||||||
|
|
||||||
|
if (ci->vbus_active && ci->role == CI_ROLE_GADGET)
|
||||||
|
/*
|
||||||
|
* vbus disconnect event is lost due to role
|
||||||
|
* switch occurs during system suspend.
|
||||||
|
*/
|
||||||
|
usb_gadget_vbus_disconnect(&ci->gadget);
|
||||||
|
|
||||||
ci_role_stop(ci);
|
ci_role_stop(ci);
|
||||||
|
|
||||||
if (role == CI_ROLE_GADGET &&
|
if (role == CI_ROLE_GADGET &&
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2013-2014 Freescale Semiconductor, Inc.
|
* Copyright (C) 2013-2014 Freescale Semiconductor, Inc.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
* Copyright (C) 2014 Freescale Semiconductor, Inc.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1532,7 +1532,7 @@ static void ci_hdrc_gadget_connect(struct usb_gadget *_gadget, int is_active)
|
|||||||
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
|
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
|
||||||
|
|
||||||
if (is_active) {
|
if (is_active) {
|
||||||
pm_runtime_get_sync(&_gadget->dev);
|
pm_runtime_get_sync(ci->dev);
|
||||||
hw_device_reset(ci);
|
hw_device_reset(ci);
|
||||||
spin_lock_irq(&ci->lock);
|
spin_lock_irq(&ci->lock);
|
||||||
if (ci->driver) {
|
if (ci->driver) {
|
||||||
@@ -1552,7 +1552,7 @@ static void ci_hdrc_gadget_connect(struct usb_gadget *_gadget, int is_active)
|
|||||||
ci->platdata->notify_event(ci,
|
ci->platdata->notify_event(ci,
|
||||||
CI_HDRC_CONTROLLER_STOPPED_EVENT);
|
CI_HDRC_CONTROLLER_STOPPED_EVENT);
|
||||||
_gadget_stop_activity(&ci->gadget);
|
_gadget_stop_activity(&ci->gadget);
|
||||||
pm_runtime_put_sync(&_gadget->dev);
|
pm_runtime_put_sync(ci->dev);
|
||||||
usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED);
|
usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1637,12 +1637,12 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
|
|||||||
if (ci_otg_is_fsm_mode(ci) || ci->role == CI_ROLE_HOST)
|
if (ci_otg_is_fsm_mode(ci) || ci->role == CI_ROLE_HOST)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pm_runtime_get_sync(&ci->gadget.dev);
|
pm_runtime_get_sync(ci->dev);
|
||||||
if (is_on)
|
if (is_on)
|
||||||
hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
|
hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
|
||||||
else
|
else
|
||||||
hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
|
hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
|
||||||
pm_runtime_put_sync(&ci->gadget.dev);
|
pm_runtime_put_sync(ci->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1840,7 +1840,7 @@ static int ci_udc_stop(struct usb_gadget *gadget)
|
|||||||
CI_HDRC_CONTROLLER_STOPPED_EVENT);
|
CI_HDRC_CONTROLLER_STOPPED_EVENT);
|
||||||
_gadget_stop_activity(&ci->gadget);
|
_gadget_stop_activity(&ci->gadget);
|
||||||
spin_lock_irqsave(&ci->lock, flags);
|
spin_lock_irqsave(&ci->lock, flags);
|
||||||
pm_runtime_put(&ci->gadget.dev);
|
pm_runtime_put(ci->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ci->lock, flags);
|
spin_unlock_irqrestore(&ci->lock, flags);
|
||||||
@@ -1971,9 +1971,6 @@ static int udc_start(struct ci_hdrc *ci)
|
|||||||
if (retval)
|
if (retval)
|
||||||
goto destroy_eps;
|
goto destroy_eps;
|
||||||
|
|
||||||
pm_runtime_no_callbacks(&ci->gadget.dev);
|
|
||||||
pm_runtime_enable(&ci->gadget.dev);
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
destroy_eps:
|
destroy_eps:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/*
|
/*
|
||||||
* udc.h - ChipIdea UDC structures
|
* udc.h - ChipIdea UDC structures
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -923,16 +923,16 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
|
|||||||
|
|
||||||
mutex_lock(&acm->port.mutex);
|
mutex_lock(&acm->port.mutex);
|
||||||
|
|
||||||
if ((ss->close_delay != old_close_delay) ||
|
if (!capable(CAP_SYS_ADMIN)) {
|
||||||
(ss->closing_wait != old_closing_wait)) {
|
if ((ss->close_delay != old_close_delay) ||
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
(ss->closing_wait != old_closing_wait))
|
||||||
retval = -EPERM;
|
retval = -EPERM;
|
||||||
else {
|
else
|
||||||
acm->port.close_delay = close_delay;
|
retval = -EOPNOTSUPP;
|
||||||
acm->port.closing_wait = closing_wait;
|
} else {
|
||||||
}
|
acm->port.close_delay = close_delay;
|
||||||
} else
|
acm->port.closing_wait = closing_wait;
|
||||||
retval = -EOPNOTSUPP;
|
}
|
||||||
|
|
||||||
mutex_unlock(&acm->port.mutex);
|
mutex_unlock(&acm->port.mutex);
|
||||||
return retval;
|
return retval;
|
||||||
|
|||||||
@@ -261,9 +261,19 @@ static int usb_probe_device(struct device *dev)
|
|||||||
*/
|
*/
|
||||||
if (!udriver->supports_autosuspend)
|
if (!udriver->supports_autosuspend)
|
||||||
error = usb_autoresume_device(udev);
|
error = usb_autoresume_device(udev);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
if (!error)
|
if (udriver->generic_subclass)
|
||||||
error = udriver->probe(udev);
|
error = usb_generic_driver_probe(udev);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
error = udriver->probe(udev);
|
||||||
|
if (error == -ENODEV && udriver != &usb_generic_driver) {
|
||||||
|
udev->use_generic_driver = 1;
|
||||||
|
return -EPROBE_DEFER;
|
||||||
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +283,10 @@ static int usb_unbind_device(struct device *dev)
|
|||||||
struct usb_device *udev = to_usb_device(dev);
|
struct usb_device *udev = to_usb_device(dev);
|
||||||
struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
|
struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
|
||||||
|
|
||||||
udriver->disconnect(udev);
|
if (udriver->disconnect)
|
||||||
|
udriver->disconnect(udev);
|
||||||
|
if (udriver->generic_subclass)
|
||||||
|
usb_generic_driver_disconnect(udev);
|
||||||
if (!udriver->supports_autosuspend)
|
if (!udriver->supports_autosuspend)
|
||||||
usb_autosuspend_device(udev);
|
usb_autosuspend_device(udev);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -790,17 +803,42 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(usb_match_id);
|
EXPORT_SYMBOL_GPL(usb_match_id);
|
||||||
|
|
||||||
|
const struct usb_device_id *usb_device_match_id(struct usb_device *udev,
|
||||||
|
const struct usb_device_id *id)
|
||||||
|
{
|
||||||
|
if (!id)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (; id->idVendor || id->idProduct ; id++) {
|
||||||
|
if (usb_match_device(udev, id))
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int usb_device_match(struct device *dev, struct device_driver *drv)
|
static int usb_device_match(struct device *dev, struct device_driver *drv)
|
||||||
{
|
{
|
||||||
/* devices and interfaces are handled separately */
|
/* devices and interfaces are handled separately */
|
||||||
if (is_usb_device(dev)) {
|
if (is_usb_device(dev)) {
|
||||||
|
struct usb_device *udev;
|
||||||
|
struct usb_device_driver *udrv;
|
||||||
|
|
||||||
/* interface drivers never match devices */
|
/* interface drivers never match devices */
|
||||||
if (!is_usb_device_driver(drv))
|
if (!is_usb_device_driver(drv))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* TODO: Add real matching code */
|
udev = to_usb_device(dev);
|
||||||
return 1;
|
udrv = to_usb_device_driver(drv);
|
||||||
|
|
||||||
|
if (udrv->id_table &&
|
||||||
|
usb_device_match_id(udev, udrv->id_table) != NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (udrv->match)
|
||||||
|
return udrv->match(udev);
|
||||||
|
return 0;
|
||||||
|
|
||||||
} else if (is_usb_interface(dev)) {
|
} else if (is_usb_interface(dev)) {
|
||||||
struct usb_interface *intf;
|
struct usb_interface *intf;
|
||||||
@@ -1149,7 +1187,10 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
|
|||||||
udev->do_remote_wakeup = 0;
|
udev->do_remote_wakeup = 0;
|
||||||
udriver = &usb_generic_driver;
|
udriver = &usb_generic_driver;
|
||||||
}
|
}
|
||||||
status = udriver->suspend(udev, msg);
|
if (udriver->suspend)
|
||||||
|
status = udriver->suspend(udev, msg);
|
||||||
|
if (status == 0 && udriver->generic_subclass)
|
||||||
|
status = usb_generic_driver_suspend(udev, msg);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
|
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
|
||||||
@@ -1181,7 +1222,10 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
|
|||||||
udev->reset_resume = 1;
|
udev->reset_resume = 1;
|
||||||
|
|
||||||
udriver = to_usb_device_driver(udev->dev.driver);
|
udriver = to_usb_device_driver(udev->dev.driver);
|
||||||
status = udriver->resume(udev, msg);
|
if (udriver->generic_subclass)
|
||||||
|
status = usb_generic_driver_resume(udev, msg);
|
||||||
|
if (status == 0 && udriver->resume)
|
||||||
|
status = udriver->resume(udev, msg);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
|
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
|
||||||
|
|||||||
@@ -195,7 +195,38 @@ int usb_choose_configuration(struct usb_device *udev)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(usb_choose_configuration);
|
EXPORT_SYMBOL_GPL(usb_choose_configuration);
|
||||||
|
|
||||||
static int generic_probe(struct usb_device *udev)
|
static int __check_usb_generic(struct device_driver *drv, void *data)
|
||||||
|
{
|
||||||
|
struct usb_device *udev = data;
|
||||||
|
struct usb_device_driver *udrv;
|
||||||
|
|
||||||
|
if (!is_usb_device_driver(drv))
|
||||||
|
return 0;
|
||||||
|
udrv = to_usb_device_driver(drv);
|
||||||
|
if (udrv == &usb_generic_driver)
|
||||||
|
return 0;
|
||||||
|
if (!udrv->id_table)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return usb_device_match_id(udev, udrv->id_table) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool usb_generic_driver_match(struct usb_device *udev)
|
||||||
|
{
|
||||||
|
if (udev->use_generic_driver)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If any other driver wants the device, leave the device to this other
|
||||||
|
* driver.
|
||||||
|
*/
|
||||||
|
if (bus_for_each_drv(&usb_bus_type, NULL, udev, __check_usb_generic))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int usb_generic_driver_probe(struct usb_device *udev)
|
||||||
{
|
{
|
||||||
int err, c;
|
int err, c;
|
||||||
|
|
||||||
@@ -222,7 +253,7 @@ static int generic_probe(struct usb_device *udev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void generic_disconnect(struct usb_device *udev)
|
void usb_generic_driver_disconnect(struct usb_device *udev)
|
||||||
{
|
{
|
||||||
usb_notify_remove_device(udev);
|
usb_notify_remove_device(udev);
|
||||||
|
|
||||||
@@ -234,7 +265,7 @@ static void generic_disconnect(struct usb_device *udev)
|
|||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
|
||||||
static int generic_suspend(struct usb_device *udev, pm_message_t msg)
|
int usb_generic_driver_suspend(struct usb_device *udev, pm_message_t msg)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -262,7 +293,7 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int generic_resume(struct usb_device *udev, pm_message_t msg)
|
int usb_generic_driver_resume(struct usb_device *udev, pm_message_t msg)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -285,11 +316,12 @@ static int generic_resume(struct usb_device *udev, pm_message_t msg)
|
|||||||
|
|
||||||
struct usb_device_driver usb_generic_driver = {
|
struct usb_device_driver usb_generic_driver = {
|
||||||
.name = "usb",
|
.name = "usb",
|
||||||
.probe = generic_probe,
|
.match = usb_generic_driver_match,
|
||||||
.disconnect = generic_disconnect,
|
.probe = usb_generic_driver_probe,
|
||||||
|
.disconnect = usb_generic_driver_disconnect,
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
.suspend = generic_suspend,
|
.suspend = usb_generic_driver_suspend,
|
||||||
.resume = generic_resume,
|
.resume = usb_generic_driver_resume,
|
||||||
#endif
|
#endif
|
||||||
.supports_autosuspend = 1,
|
.supports_autosuspend = 1,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
* Released under the GPLv2 only.
|
* Released under the GPLv2 only.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
||||||
#include <linux/pci.h> /* for scatterlist macros */
|
#include <linux/pci.h> /* for scatterlist macros */
|
||||||
#include <linux/usb.h>
|
#include <linux/usb.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
@@ -1941,6 +1942,7 @@ free_interfaces:
|
|||||||
intf->dev.of_node = usb_of_get_interface_node(dev,
|
intf->dev.of_node = usb_of_get_interface_node(dev,
|
||||||
configuration, ifnum);
|
configuration, ifnum);
|
||||||
}
|
}
|
||||||
|
ACPI_COMPANION_SET(&intf->dev, ACPI_COMPANION(&dev->dev));
|
||||||
intf->dev.driver = NULL;
|
intf->dev.driver = NULL;
|
||||||
intf->dev.bus = &usb_bus_type;
|
intf->dev.bus = &usb_bus_type;
|
||||||
intf->dev.type = &usb_if_device_type;
|
intf->dev.type = &usb_if_device_type;
|
||||||
|
|||||||
@@ -849,7 +849,7 @@ static struct attribute *dev_string_attrs[] = {
|
|||||||
static umode_t dev_string_attrs_are_visible(struct kobject *kobj,
|
static umode_t dev_string_attrs_are_visible(struct kobject *kobj,
|
||||||
struct attribute *a, int n)
|
struct attribute *a, int n)
|
||||||
{
|
{
|
||||||
struct device *dev = container_of(kobj, struct device, kobj);
|
struct device *dev = kobj_to_dev(kobj);
|
||||||
struct usb_device *udev = to_usb_device(dev);
|
struct usb_device *udev = to_usb_device(dev);
|
||||||
|
|
||||||
if (a == &dev_attr_manufacturer.attr) {
|
if (a == &dev_attr_manufacturer.attr) {
|
||||||
@@ -883,7 +883,7 @@ read_descriptors(struct file *filp, struct kobject *kobj,
|
|||||||
struct bin_attribute *attr,
|
struct bin_attribute *attr,
|
||||||
char *buf, loff_t off, size_t count)
|
char *buf, loff_t off, size_t count)
|
||||||
{
|
{
|
||||||
struct device *dev = container_of(kobj, struct device, kobj);
|
struct device *dev = kobj_to_dev(kobj);
|
||||||
struct usb_device *udev = to_usb_device(dev);
|
struct usb_device *udev = to_usb_device(dev);
|
||||||
size_t nleft = count;
|
size_t nleft = count;
|
||||||
size_t srclen, n;
|
size_t srclen, n;
|
||||||
@@ -1233,7 +1233,7 @@ static struct attribute *intf_assoc_attrs[] = {
|
|||||||
static umode_t intf_assoc_attrs_are_visible(struct kobject *kobj,
|
static umode_t intf_assoc_attrs_are_visible(struct kobject *kobj,
|
||||||
struct attribute *a, int n)
|
struct attribute *a, int n)
|
||||||
{
|
{
|
||||||
struct device *dev = container_of(kobj, struct device, kobj);
|
struct device *dev = kobj_to_dev(kobj);
|
||||||
struct usb_interface *intf = to_usb_interface(dev);
|
struct usb_interface *intf = to_usb_interface(dev);
|
||||||
|
|
||||||
if (intf->intf_assoc == NULL)
|
if (intf->intf_assoc == NULL)
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle,
|
|||||||
{
|
{
|
||||||
enum usb_port_connect_type connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN;
|
enum usb_port_connect_type connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN;
|
||||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||||
union acpi_object *upc;
|
union acpi_object *upc = NULL;
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -98,11 +98,12 @@ static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle,
|
|||||||
* no connectable, the port would be not used.
|
* no connectable, the port would be not used.
|
||||||
*/
|
*/
|
||||||
status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);
|
status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);
|
||||||
upc = buffer.pointer;
|
if (ACPI_FAILURE(status))
|
||||||
if (!upc || (upc->type != ACPI_TYPE_PACKAGE)
|
goto out;
|
||||||
|| upc->package.count != 4) {
|
|
||||||
|
upc = buffer.pointer;
|
||||||
|
if (!upc || (upc->type != ACPI_TYPE_PACKAGE) || upc->package.count != 4)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
if (upc->package.elements[0].integer.value)
|
if (upc->package.elements[0].integer.value)
|
||||||
if (pld->user_visible)
|
if (pld->user_visible)
|
||||||
@@ -186,7 +187,7 @@ usb_acpi_find_companion_for_port(struct usb_port *port_dev)
|
|||||||
|
|
||||||
handle = adev->handle;
|
handle = adev->handle;
|
||||||
status = acpi_get_physical_device_location(handle, &pld);
|
status = acpi_get_physical_device_location(handle, &pld);
|
||||||
if (!ACPI_FAILURE(status) && pld) {
|
if (ACPI_SUCCESS(status) && pld) {
|
||||||
port_dev->location = USB_ACPI_LOCATION_VALID
|
port_dev->location = USB_ACPI_LOCATION_VALID
|
||||||
| pld->group_token << 8 | pld->group_position;
|
| pld->group_token << 8 | pld->group_position;
|
||||||
port_dev->connect_type = usb_acpi_get_connect_type(handle, pld);
|
port_dev->connect_type = usb_acpi_get_connect_type(handle, pld);
|
||||||
|
|||||||
@@ -50,6 +50,12 @@ extern void usb_release_bos_descriptor(struct usb_device *dev);
|
|||||||
extern char *usb_cache_string(struct usb_device *udev, int index);
|
extern char *usb_cache_string(struct usb_device *udev, int index);
|
||||||
extern int usb_set_configuration(struct usb_device *dev, int configuration);
|
extern int usb_set_configuration(struct usb_device *dev, int configuration);
|
||||||
extern int usb_choose_configuration(struct usb_device *udev);
|
extern int usb_choose_configuration(struct usb_device *udev);
|
||||||
|
extern int usb_generic_driver_probe(struct usb_device *udev);
|
||||||
|
extern void usb_generic_driver_disconnect(struct usb_device *udev);
|
||||||
|
extern int usb_generic_driver_suspend(struct usb_device *udev,
|
||||||
|
pm_message_t msg);
|
||||||
|
extern int usb_generic_driver_resume(struct usb_device *udev,
|
||||||
|
pm_message_t msg);
|
||||||
|
|
||||||
static inline unsigned usb_get_max_power(struct usb_device *udev,
|
static inline unsigned usb_get_max_power(struct usb_device *udev,
|
||||||
struct usb_host_config *c)
|
struct usb_host_config *c)
|
||||||
@@ -66,6 +72,8 @@ extern int usb_match_one_id_intf(struct usb_device *dev,
|
|||||||
const struct usb_device_id *id);
|
const struct usb_device_id *id);
|
||||||
extern int usb_match_device(struct usb_device *dev,
|
extern int usb_match_device(struct usb_device *dev,
|
||||||
const struct usb_device_id *id);
|
const struct usb_device_id *id);
|
||||||
|
extern const struct usb_device_id *usb_device_match_id(struct usb_device *udev,
|
||||||
|
const struct usb_device_id *id);
|
||||||
extern void usb_forced_unbind_intf(struct usb_interface *intf);
|
extern void usb_forced_unbind_intf(struct usb_interface *intf);
|
||||||
extern void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev);
|
extern void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev);
|
||||||
|
|
||||||
|
|||||||
@@ -411,6 +411,10 @@ enum dwc2_ep0_state {
|
|||||||
* register.
|
* register.
|
||||||
* 0 - Deactivate the transceiver (default)
|
* 0 - Deactivate the transceiver (default)
|
||||||
* 1 - Activate the transceiver
|
* 1 - Activate the transceiver
|
||||||
|
* @activate_stm_id_vb_detection: Activate external ID pin and Vbus level
|
||||||
|
* detection using GGPIO register.
|
||||||
|
* 0 - Deactivate the external level detection (default)
|
||||||
|
* 1 - Activate the external level detection
|
||||||
* @g_dma: Enables gadget dma usage (default: autodetect).
|
* @g_dma: Enables gadget dma usage (default: autodetect).
|
||||||
* @g_dma_desc: Enables gadget descriptor DMA (default: autodetect).
|
* @g_dma_desc: Enables gadget descriptor DMA (default: autodetect).
|
||||||
* @g_rx_fifo_size: The periodic rx fifo size for the device, in
|
* @g_rx_fifo_size: The periodic rx fifo size for the device, in
|
||||||
@@ -481,6 +485,7 @@ struct dwc2_core_params {
|
|||||||
bool service_interval;
|
bool service_interval;
|
||||||
u8 hird_threshold;
|
u8 hird_threshold;
|
||||||
bool activate_stm_fs_transceiver;
|
bool activate_stm_fs_transceiver;
|
||||||
|
bool activate_stm_id_vb_detection;
|
||||||
bool ipg_isoc_en;
|
bool ipg_isoc_en;
|
||||||
u16 max_packet_count;
|
u16 max_packet_count;
|
||||||
u32 max_transfer_size;
|
u32 max_transfer_size;
|
||||||
@@ -874,6 +879,8 @@ struct dwc2_hregs_backup {
|
|||||||
* removed once all SoCs support usb transceiver.
|
* removed once all SoCs support usb transceiver.
|
||||||
* @supplies: Definition of USB power supplies
|
* @supplies: Definition of USB power supplies
|
||||||
* @vbus_supply: Regulator supplying vbus.
|
* @vbus_supply: Regulator supplying vbus.
|
||||||
|
* @usb33d: Optional 3.3v regulator used on some stm32 devices to
|
||||||
|
* supply ID and VBUS detection hardware.
|
||||||
* @lock: Spinlock that protects all the driver data structures
|
* @lock: Spinlock that protects all the driver data structures
|
||||||
* @priv: Stores a pointer to the struct usb_hcd
|
* @priv: Stores a pointer to the struct usb_hcd
|
||||||
* @queuing_high_bandwidth: True if multiple packets of a high-bandwidth
|
* @queuing_high_bandwidth: True if multiple packets of a high-bandwidth
|
||||||
@@ -1061,6 +1068,7 @@ struct dwc2_hsotg {
|
|||||||
struct dwc2_hsotg_plat *plat;
|
struct dwc2_hsotg_plat *plat;
|
||||||
struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES];
|
struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES];
|
||||||
struct regulator *vbus_supply;
|
struct regulator *vbus_supply;
|
||||||
|
struct regulator *usb33d;
|
||||||
|
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
void *priv;
|
void *priv;
|
||||||
|
|||||||
@@ -1646,7 +1646,8 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg,
|
|||||||
|
|
||||||
switch (ctrl->bRequestType & USB_RECIP_MASK) {
|
switch (ctrl->bRequestType & USB_RECIP_MASK) {
|
||||||
case USB_RECIP_DEVICE:
|
case USB_RECIP_DEVICE:
|
||||||
status = 1 << USB_DEVICE_SELF_POWERED;
|
status = hsotg->gadget.is_selfpowered <<
|
||||||
|
USB_DEVICE_SELF_POWERED;
|
||||||
status |= hsotg->remote_wakeup_allowed <<
|
status |= hsotg->remote_wakeup_allowed <<
|
||||||
USB_DEVICE_REMOTE_WAKEUP;
|
USB_DEVICE_REMOTE_WAKEUP;
|
||||||
reply = cpu_to_le16(status);
|
reply = cpu_to_le16(status);
|
||||||
@@ -4527,6 +4528,26 @@ static int dwc2_hsotg_gadget_getframe(struct usb_gadget *gadget)
|
|||||||
return dwc2_hsotg_read_frameno(to_hsotg(gadget));
|
return dwc2_hsotg_read_frameno(to_hsotg(gadget));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dwc2_hsotg_set_selfpowered - set if device is self/bus powered
|
||||||
|
* @gadget: The usb gadget state
|
||||||
|
* @is_selfpowered: Whether the device is self-powered
|
||||||
|
*
|
||||||
|
* Set if the device is self or bus powered.
|
||||||
|
*/
|
||||||
|
static int dwc2_hsotg_set_selfpowered(struct usb_gadget *gadget,
|
||||||
|
int is_selfpowered)
|
||||||
|
{
|
||||||
|
struct dwc2_hsotg *hsotg = to_hsotg(gadget);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&hsotg->lock, flags);
|
||||||
|
gadget->is_selfpowered = !!is_selfpowered;
|
||||||
|
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dwc2_hsotg_pullup - connect/disconnect the USB PHY
|
* dwc2_hsotg_pullup - connect/disconnect the USB PHY
|
||||||
* @gadget: The usb gadget state
|
* @gadget: The usb gadget state
|
||||||
@@ -4618,6 +4639,7 @@ static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA)
|
|||||||
|
|
||||||
static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = {
|
static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = {
|
||||||
.get_frame = dwc2_hsotg_gadget_getframe,
|
.get_frame = dwc2_hsotg_gadget_getframe,
|
||||||
|
.set_selfpowered = dwc2_hsotg_set_selfpowered,
|
||||||
.udc_start = dwc2_hsotg_udc_start,
|
.udc_start = dwc2_hsotg_udc_start,
|
||||||
.udc_stop = dwc2_hsotg_udc_stop,
|
.udc_stop = dwc2_hsotg_udc_stop,
|
||||||
.pullup = dwc2_hsotg_pullup,
|
.pullup = dwc2_hsotg_pullup,
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ struct dwc2_hcd_urb {
|
|||||||
u32 flags;
|
u32 flags;
|
||||||
u16 interval;
|
u16 interval;
|
||||||
struct dwc2_hcd_pipe_info pipe_info;
|
struct dwc2_hcd_pipe_info pipe_info;
|
||||||
struct dwc2_hcd_iso_packet_desc iso_descs[0];
|
struct dwc2_hcd_iso_packet_desc iso_descs[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Phases for control transfers */
|
/* Phases for control transfers */
|
||||||
|
|||||||
@@ -54,6 +54,12 @@
|
|||||||
#define GOTGCTL_HSTSETHNPEN BIT(10)
|
#define GOTGCTL_HSTSETHNPEN BIT(10)
|
||||||
#define GOTGCTL_HNPREQ BIT(9)
|
#define GOTGCTL_HNPREQ BIT(9)
|
||||||
#define GOTGCTL_HSTNEGSCS BIT(8)
|
#define GOTGCTL_HSTNEGSCS BIT(8)
|
||||||
|
#define GOTGCTL_BVALOVAL BIT(7)
|
||||||
|
#define GOTGCTL_BVALOEN BIT(6)
|
||||||
|
#define GOTGCTL_AVALOVAL BIT(5)
|
||||||
|
#define GOTGCTL_AVALOEN BIT(4)
|
||||||
|
#define GOTGCTL_VBVALOVAL BIT(3)
|
||||||
|
#define GOTGCTL_VBVALOEN BIT(2)
|
||||||
#define GOTGCTL_SESREQ BIT(1)
|
#define GOTGCTL_SESREQ BIT(1)
|
||||||
#define GOTGCTL_SESREQSCS BIT(0)
|
#define GOTGCTL_SESREQSCS BIT(0)
|
||||||
|
|
||||||
@@ -227,6 +233,8 @@
|
|||||||
#define GPVNDCTL HSOTG_REG(0x0034)
|
#define GPVNDCTL HSOTG_REG(0x0034)
|
||||||
#define GGPIO HSOTG_REG(0x0038)
|
#define GGPIO HSOTG_REG(0x0038)
|
||||||
#define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16)
|
#define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16)
|
||||||
|
#define GGPIO_STM32_OTG_GCCFG_VBDEN BIT(21)
|
||||||
|
#define GGPIO_STM32_OTG_GCCFG_IDEN BIT(22)
|
||||||
|
|
||||||
#define GUID HSOTG_REG(0x003c)
|
#define GUID HSOTG_REG(0x003c)
|
||||||
#define GSNPSID HSOTG_REG(0x0040)
|
#define GSNPSID HSOTG_REG(0x0040)
|
||||||
|
|||||||
@@ -163,6 +163,35 @@ static void dwc2_set_stm32f7_hsotg_params(struct dwc2_hsotg *hsotg)
|
|||||||
p->host_perio_tx_fifo_size = 256;
|
p->host_perio_tx_fifo_size = 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dwc2_set_stm32mp15_fsotg_params(struct dwc2_hsotg *hsotg)
|
||||||
|
{
|
||||||
|
struct dwc2_core_params *p = &hsotg->params;
|
||||||
|
|
||||||
|
p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
|
||||||
|
p->speed = DWC2_SPEED_PARAM_FULL;
|
||||||
|
p->host_rx_fifo_size = 128;
|
||||||
|
p->host_nperio_tx_fifo_size = 96;
|
||||||
|
p->host_perio_tx_fifo_size = 96;
|
||||||
|
p->max_packet_count = 256;
|
||||||
|
p->phy_type = DWC2_PHY_TYPE_PARAM_FS;
|
||||||
|
p->i2c_enable = false;
|
||||||
|
p->activate_stm_fs_transceiver = true;
|
||||||
|
p->activate_stm_id_vb_detection = true;
|
||||||
|
p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg)
|
||||||
|
{
|
||||||
|
struct dwc2_core_params *p = &hsotg->params;
|
||||||
|
|
||||||
|
p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
|
||||||
|
p->activate_stm_id_vb_detection = true;
|
||||||
|
p->host_rx_fifo_size = 440;
|
||||||
|
p->host_nperio_tx_fifo_size = 256;
|
||||||
|
p->host_perio_tx_fifo_size = 256;
|
||||||
|
p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
const struct of_device_id dwc2_of_match_table[] = {
|
const struct of_device_id dwc2_of_match_table[] = {
|
||||||
{ .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params },
|
{ .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params },
|
||||||
{ .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params },
|
{ .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params },
|
||||||
@@ -186,6 +215,10 @@ const struct of_device_id dwc2_of_match_table[] = {
|
|||||||
{ .compatible = "st,stm32f4x9-hsotg" },
|
{ .compatible = "st,stm32f4x9-hsotg" },
|
||||||
{ .compatible = "st,stm32f7-hsotg",
|
{ .compatible = "st,stm32f7-hsotg",
|
||||||
.data = dwc2_set_stm32f7_hsotg_params },
|
.data = dwc2_set_stm32f7_hsotg_params },
|
||||||
|
{ .compatible = "st,stm32mp15-fsotg",
|
||||||
|
.data = dwc2_set_stm32mp15_fsotg_params },
|
||||||
|
{ .compatible = "st,stm32mp15-hsotg",
|
||||||
|
.data = dwc2_set_stm32mp15_hsotg_params },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
|
MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
|
||||||
|
|||||||
@@ -285,7 +285,9 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
|
|||||||
ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies),
|
ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies),
|
||||||
hsotg->supplies);
|
hsotg->supplies);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(hsotg->dev, "failed to request supplies: %d\n", ret);
|
if (ret != -EPROBE_DEFER)
|
||||||
|
dev_err(hsotg->dev, "failed to request supplies: %d\n",
|
||||||
|
ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -312,6 +314,9 @@ static int dwc2_driver_remove(struct platform_device *dev)
|
|||||||
if (hsotg->gadget_enabled)
|
if (hsotg->gadget_enabled)
|
||||||
dwc2_hsotg_remove(hsotg);
|
dwc2_hsotg_remove(hsotg);
|
||||||
|
|
||||||
|
if (hsotg->params.activate_stm_id_vb_detection)
|
||||||
|
regulator_disable(hsotg->usb33d);
|
||||||
|
|
||||||
if (hsotg->ll_hw_enabled)
|
if (hsotg->ll_hw_enabled)
|
||||||
dwc2_lowlevel_hw_disable(hsotg);
|
dwc2_lowlevel_hw_disable(hsotg);
|
||||||
|
|
||||||
@@ -392,8 +397,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
hsotg->regs = devm_platform_get_and_ioremap_resource(dev, 0, &res);
|
||||||
hsotg->regs = devm_ioremap_resource(&dev->dev, res);
|
|
||||||
if (IS_ERR(hsotg->regs))
|
if (IS_ERR(hsotg->regs))
|
||||||
return PTR_ERR(hsotg->regs);
|
return PTR_ERR(hsotg->regs);
|
||||||
|
|
||||||
@@ -464,10 +468,35 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|||||||
if (retval)
|
if (retval)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
if (hsotg->params.activate_stm_id_vb_detection) {
|
||||||
|
u32 ggpio;
|
||||||
|
|
||||||
|
hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d");
|
||||||
|
if (IS_ERR(hsotg->usb33d)) {
|
||||||
|
retval = PTR_ERR(hsotg->usb33d);
|
||||||
|
if (retval != -EPROBE_DEFER)
|
||||||
|
dev_err(hsotg->dev,
|
||||||
|
"failed to request usb33d supply: %d\n",
|
||||||
|
retval);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
retval = regulator_enable(hsotg->usb33d);
|
||||||
|
if (retval) {
|
||||||
|
dev_err(hsotg->dev,
|
||||||
|
"failed to enable usb33d supply: %d\n", retval);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ggpio = dwc2_readl(hsotg, GGPIO);
|
||||||
|
ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN;
|
||||||
|
ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN;
|
||||||
|
dwc2_writel(hsotg, ggpio, GGPIO);
|
||||||
|
}
|
||||||
|
|
||||||
if (hsotg->dr_mode != USB_DR_MODE_HOST) {
|
if (hsotg->dr_mode != USB_DR_MODE_HOST) {
|
||||||
retval = dwc2_gadget_init(hsotg);
|
retval = dwc2_gadget_init(hsotg);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto error;
|
goto error_init;
|
||||||
hsotg->gadget_enabled = 1;
|
hsotg->gadget_enabled = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,7 +522,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|||||||
if (retval) {
|
if (retval) {
|
||||||
if (hsotg->gadget_enabled)
|
if (hsotg->gadget_enabled)
|
||||||
dwc2_hsotg_remove(hsotg);
|
dwc2_hsotg_remove(hsotg);
|
||||||
goto error;
|
goto error_init;
|
||||||
}
|
}
|
||||||
hsotg->hcd_enabled = 1;
|
hsotg->hcd_enabled = 1;
|
||||||
}
|
}
|
||||||
@@ -509,6 +538,9 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
error_init:
|
||||||
|
if (hsotg->params.activate_stm_id_vb_detection)
|
||||||
|
regulator_disable(hsotg->usb33d);
|
||||||
error:
|
error:
|
||||||
dwc2_lowlevel_hw_disable(hsotg);
|
dwc2_lowlevel_hw_disable(hsotg);
|
||||||
return retval;
|
return retval;
|
||||||
@@ -523,6 +555,37 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
|
|||||||
if (is_device_mode)
|
if (is_device_mode)
|
||||||
dwc2_hsotg_suspend(dwc2);
|
dwc2_hsotg_suspend(dwc2);
|
||||||
|
|
||||||
|
if (dwc2->params.activate_stm_id_vb_detection) {
|
||||||
|
unsigned long flags;
|
||||||
|
u32 ggpio, gotgctl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Need to force the mode to the current mode to avoid Mode
|
||||||
|
* Mismatch Interrupt when ID detection will be disabled.
|
||||||
|
*/
|
||||||
|
dwc2_force_mode(dwc2, !is_device_mode);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dwc2->lock, flags);
|
||||||
|
gotgctl = dwc2_readl(dwc2, GOTGCTL);
|
||||||
|
/* bypass debounce filter, enable overrides */
|
||||||
|
gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS;
|
||||||
|
gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN;
|
||||||
|
/* Force A / B session if needed */
|
||||||
|
if (gotgctl & GOTGCTL_ASESVLD)
|
||||||
|
gotgctl |= GOTGCTL_AVALOVAL;
|
||||||
|
if (gotgctl & GOTGCTL_BSESVLD)
|
||||||
|
gotgctl |= GOTGCTL_BVALOVAL;
|
||||||
|
dwc2_writel(dwc2, gotgctl, GOTGCTL);
|
||||||
|
spin_unlock_irqrestore(&dwc2->lock, flags);
|
||||||
|
|
||||||
|
ggpio = dwc2_readl(dwc2, GGPIO);
|
||||||
|
ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN;
|
||||||
|
ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN;
|
||||||
|
dwc2_writel(dwc2, ggpio, GGPIO);
|
||||||
|
|
||||||
|
regulator_disable(dwc2->usb33d);
|
||||||
|
}
|
||||||
|
|
||||||
if (dwc2->ll_hw_enabled &&
|
if (dwc2->ll_hw_enabled &&
|
||||||
(is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) {
|
(is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) {
|
||||||
ret = __dwc2_lowlevel_hw_disable(dwc2);
|
ret = __dwc2_lowlevel_hw_disable(dwc2);
|
||||||
@@ -544,6 +607,34 @@ static int __maybe_unused dwc2_resume(struct device *dev)
|
|||||||
}
|
}
|
||||||
dwc2->phy_off_for_suspend = false;
|
dwc2->phy_off_for_suspend = false;
|
||||||
|
|
||||||
|
if (dwc2->params.activate_stm_id_vb_detection) {
|
||||||
|
unsigned long flags;
|
||||||
|
u32 ggpio, gotgctl;
|
||||||
|
|
||||||
|
ret = regulator_enable(dwc2->usb33d);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ggpio = dwc2_readl(dwc2, GGPIO);
|
||||||
|
ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN;
|
||||||
|
ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN;
|
||||||
|
dwc2_writel(dwc2, ggpio, GGPIO);
|
||||||
|
|
||||||
|
/* ID/VBUS detection startup time */
|
||||||
|
usleep_range(5000, 7000);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dwc2->lock, flags);
|
||||||
|
gotgctl = dwc2_readl(dwc2, GOTGCTL);
|
||||||
|
gotgctl &= ~GOTGCTL_DBNCE_FLTR_BYPASS;
|
||||||
|
gotgctl &= ~(GOTGCTL_BVALOEN | GOTGCTL_AVALOEN |
|
||||||
|
GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL);
|
||||||
|
dwc2_writel(dwc2, gotgctl, GOTGCTL);
|
||||||
|
spin_unlock_irqrestore(&dwc2->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Need to restore FORCEDEVMODE/FORCEHOSTMODE */
|
||||||
|
dwc2_force_dr_mode(dwc2);
|
||||||
|
|
||||||
if (dwc2_is_device_mode(dwc2))
|
if (dwc2_is_device_mode(dwc2))
|
||||||
ret = dwc2_hsotg_resume(dwc2);
|
ret = dwc2_hsotg_resume(dwc2);
|
||||||
|
|
||||||
|
|||||||
@@ -289,12 +289,6 @@ done:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct clk_bulk_data dwc3_core_clks[] = {
|
|
||||||
{ .id = "ref" },
|
|
||||||
{ .id = "bus_early" },
|
|
||||||
{ .id = "suspend" },
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dwc3_frame_length_adjustment - Adjusts frame length if required
|
* dwc3_frame_length_adjustment - Adjusts frame length if required
|
||||||
* @dwc3: Pointer to our controller context structure
|
* @dwc3: Pointer to our controller context structure
|
||||||
@@ -1029,6 +1023,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
|||||||
if (dwc->dis_tx_ipgap_linecheck_quirk)
|
if (dwc->dis_tx_ipgap_linecheck_quirk)
|
||||||
reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
|
reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
|
||||||
|
|
||||||
|
if (dwc->parkmode_disable_ss_quirk)
|
||||||
|
reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS;
|
||||||
|
|
||||||
dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
|
dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1342,6 +1339,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
|
|||||||
"snps,dis-del-phy-power-chg-quirk");
|
"snps,dis-del-phy-power-chg-quirk");
|
||||||
dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev,
|
dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev,
|
||||||
"snps,dis-tx-ipgap-linecheck-quirk");
|
"snps,dis-tx-ipgap-linecheck-quirk");
|
||||||
|
dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev,
|
||||||
|
"snps,parkmode-disable-ss-quirk");
|
||||||
|
|
||||||
dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
|
dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
|
||||||
"snps,tx_de_emphasis_quirk");
|
"snps,tx_de_emphasis_quirk");
|
||||||
@@ -1441,11 +1440,6 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||||||
if (!dwc)
|
if (!dwc)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
dwc->clks = devm_kmemdup(dev, dwc3_core_clks, sizeof(dwc3_core_clks),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!dwc->clks)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
dwc->dev = dev;
|
dwc->dev = dev;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
@@ -1476,22 +1470,23 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
dwc3_get_properties(dwc);
|
dwc3_get_properties(dwc);
|
||||||
|
|
||||||
dwc->reset = devm_reset_control_get_optional_shared(dev, NULL);
|
dwc->reset = devm_reset_control_array_get(dev, true, true);
|
||||||
if (IS_ERR(dwc->reset))
|
if (IS_ERR(dwc->reset))
|
||||||
return PTR_ERR(dwc->reset);
|
return PTR_ERR(dwc->reset);
|
||||||
|
|
||||||
if (dev->of_node) {
|
if (dev->of_node) {
|
||||||
dwc->num_clks = ARRAY_SIZE(dwc3_core_clks);
|
ret = devm_clk_bulk_get_all(dev, &dwc->clks);
|
||||||
|
|
||||||
ret = devm_clk_bulk_get(dev, dwc->num_clks, dwc->clks);
|
|
||||||
if (ret == -EPROBE_DEFER)
|
if (ret == -EPROBE_DEFER)
|
||||||
return ret;
|
return ret;
|
||||||
/*
|
/*
|
||||||
* Clocks are optional, but new DT platforms should support all
|
* Clocks are optional, but new DT platforms should support all
|
||||||
* clocks as required by the DT-binding.
|
* clocks as required by the DT-binding.
|
||||||
*/
|
*/
|
||||||
if (ret)
|
if (ret < 0)
|
||||||
dwc->num_clks = 0;
|
dwc->num_clks = 0;
|
||||||
|
else
|
||||||
|
dwc->num_clks = ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = reset_control_deassert(dwc->reset);
|
ret = reset_control_deassert(dwc->reset);
|
||||||
@@ -1637,6 +1632,8 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
|||||||
|
|
||||||
switch (dwc->current_dr_role) {
|
switch (dwc->current_dr_role) {
|
||||||
case DWC3_GCTL_PRTCAP_DEVICE:
|
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||||
|
if (pm_runtime_suspended(dwc->dev))
|
||||||
|
break;
|
||||||
spin_lock_irqsave(&dwc->lock, flags);
|
spin_lock_irqsave(&dwc->lock, flags);
|
||||||
dwc3_gadget_suspend(dwc);
|
dwc3_gadget_suspend(dwc);
|
||||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#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>
|
||||||
|
#include <linux/usb/role.h>
|
||||||
#include <linux/ulpi/interface.h>
|
#include <linux/ulpi/interface.h>
|
||||||
|
|
||||||
#include <linux/phy/phy.h>
|
#include <linux/phy/phy.h>
|
||||||
@@ -249,6 +250,7 @@
|
|||||||
#define DWC3_GUCTL_HSTINAUTORETRY BIT(14)
|
#define DWC3_GUCTL_HSTINAUTORETRY BIT(14)
|
||||||
|
|
||||||
/* Global User Control 1 Register */
|
/* Global User Control 1 Register */
|
||||||
|
#define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17)
|
||||||
#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28)
|
#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28)
|
||||||
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
|
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
|
||||||
|
|
||||||
@@ -953,6 +955,9 @@ struct dwc3_scratchpad_array {
|
|||||||
* @hsphy_mode: UTMI phy mode, one of following:
|
* @hsphy_mode: UTMI phy mode, one of following:
|
||||||
* - USBPHY_INTERFACE_MODE_UTMI
|
* - USBPHY_INTERFACE_MODE_UTMI
|
||||||
* - USBPHY_INTERFACE_MODE_UTMIW
|
* - USBPHY_INTERFACE_MODE_UTMIW
|
||||||
|
* @role_sw: usb_role_switch handle
|
||||||
|
* @role_switch_default_mode: default operation mode of controller while
|
||||||
|
* usb role is USB_ROLE_NONE.
|
||||||
* @usb2_phy: pointer to USB2 PHY
|
* @usb2_phy: pointer to USB2 PHY
|
||||||
* @usb3_phy: pointer to USB3 PHY
|
* @usb3_phy: pointer to USB3 PHY
|
||||||
* @usb2_generic_phy: pointer to USB2 PHY
|
* @usb2_generic_phy: pointer to USB2 PHY
|
||||||
@@ -1024,6 +1029,8 @@ struct dwc3_scratchpad_array {
|
|||||||
* change quirk.
|
* change quirk.
|
||||||
* @dis_tx_ipgap_linecheck_quirk: set if we disable u2mac linestate
|
* @dis_tx_ipgap_linecheck_quirk: set if we disable u2mac linestate
|
||||||
* check during HS transmit.
|
* check during HS transmit.
|
||||||
|
* @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed
|
||||||
|
* instances in park mode.
|
||||||
* @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
|
* @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
|
||||||
* @tx_de_emphasis: Tx de-emphasis value
|
* @tx_de_emphasis: Tx de-emphasis value
|
||||||
* 0 - -6dB de-emphasis
|
* 0 - -6dB de-emphasis
|
||||||
@@ -1086,6 +1093,8 @@ struct dwc3 {
|
|||||||
struct extcon_dev *edev;
|
struct extcon_dev *edev;
|
||||||
struct notifier_block edev_nb;
|
struct notifier_block edev_nb;
|
||||||
enum usb_phy_interface hsphy_mode;
|
enum usb_phy_interface hsphy_mode;
|
||||||
|
struct usb_role_switch *role_sw;
|
||||||
|
enum usb_dr_mode role_switch_default_mode;
|
||||||
|
|
||||||
u32 fladj;
|
u32 fladj;
|
||||||
u32 irq_gadget;
|
u32 irq_gadget;
|
||||||
@@ -1215,6 +1224,7 @@ struct dwc3 {
|
|||||||
unsigned dis_u2_freeclk_exists_quirk:1;
|
unsigned dis_u2_freeclk_exists_quirk:1;
|
||||||
unsigned dis_del_phy_power_chg_quirk:1;
|
unsigned dis_del_phy_power_chg_quirk:1;
|
||||||
unsigned dis_tx_ipgap_linecheck_quirk:1;
|
unsigned dis_tx_ipgap_linecheck_quirk:1;
|
||||||
|
unsigned parkmode_disable_ss_quirk:1;
|
||||||
|
|
||||||
unsigned tx_de_emphasis_quirk:1;
|
unsigned tx_de_emphasis_quirk:1;
|
||||||
unsigned tx_de_emphasis:2;
|
unsigned tx_de_emphasis:2;
|
||||||
|
|||||||
@@ -476,6 +476,94 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
|
|||||||
return edev;
|
return edev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_USB_ROLE_SWITCH)
|
||||||
|
#define ROLE_SWITCH 1
|
||||||
|
static int dwc3_usb_role_switch_set(struct usb_role_switch *sw,
|
||||||
|
enum usb_role role)
|
||||||
|
{
|
||||||
|
struct dwc3 *dwc = usb_role_switch_get_drvdata(sw);
|
||||||
|
u32 mode;
|
||||||
|
|
||||||
|
switch (role) {
|
||||||
|
case USB_ROLE_HOST:
|
||||||
|
mode = DWC3_GCTL_PRTCAP_HOST;
|
||||||
|
break;
|
||||||
|
case USB_ROLE_DEVICE:
|
||||||
|
mode = DWC3_GCTL_PRTCAP_DEVICE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (dwc->role_switch_default_mode == USB_DR_MODE_HOST)
|
||||||
|
mode = DWC3_GCTL_PRTCAP_HOST;
|
||||||
|
else
|
||||||
|
mode = DWC3_GCTL_PRTCAP_DEVICE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dwc3_set_mode(dwc, mode);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw)
|
||||||
|
{
|
||||||
|
struct dwc3 *dwc = usb_role_switch_get_drvdata(sw);
|
||||||
|
unsigned long flags;
|
||||||
|
enum usb_role role;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dwc->lock, flags);
|
||||||
|
switch (dwc->current_dr_role) {
|
||||||
|
case DWC3_GCTL_PRTCAP_HOST:
|
||||||
|
role = USB_ROLE_HOST;
|
||||||
|
break;
|
||||||
|
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||||
|
role = USB_ROLE_DEVICE;
|
||||||
|
break;
|
||||||
|
case DWC3_GCTL_PRTCAP_OTG:
|
||||||
|
role = dwc->current_otg_role;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (dwc->role_switch_default_mode == USB_DR_MODE_HOST)
|
||||||
|
role = USB_ROLE_HOST;
|
||||||
|
else
|
||||||
|
role = USB_ROLE_DEVICE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dwc3_setup_role_switch(struct dwc3 *dwc)
|
||||||
|
{
|
||||||
|
struct usb_role_switch_desc dwc3_role_switch = {NULL};
|
||||||
|
const char *str;
|
||||||
|
u32 mode;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = device_property_read_string(dwc->dev, "role-switch-default-mode",
|
||||||
|
&str);
|
||||||
|
if (ret >= 0 && !strncmp(str, "host", strlen("host"))) {
|
||||||
|
dwc->role_switch_default_mode = USB_DR_MODE_HOST;
|
||||||
|
mode = DWC3_GCTL_PRTCAP_HOST;
|
||||||
|
} else {
|
||||||
|
dwc->role_switch_default_mode = USB_DR_MODE_PERIPHERAL;
|
||||||
|
mode = DWC3_GCTL_PRTCAP_DEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
dwc3_role_switch.fwnode = dev_fwnode(dwc->dev);
|
||||||
|
dwc3_role_switch.set = dwc3_usb_role_switch_set;
|
||||||
|
dwc3_role_switch.get = dwc3_usb_role_switch_get;
|
||||||
|
dwc3_role_switch.driver_data = dwc;
|
||||||
|
dwc->role_sw = usb_role_switch_register(dwc->dev, &dwc3_role_switch);
|
||||||
|
if (IS_ERR(dwc->role_sw))
|
||||||
|
return PTR_ERR(dwc->role_sw);
|
||||||
|
|
||||||
|
dwc3_set_mode(dwc, mode);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define ROLE_SWITCH 0
|
||||||
|
#define dwc3_setup_role_switch(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
int dwc3_drd_init(struct dwc3 *dwc)
|
int dwc3_drd_init(struct dwc3 *dwc)
|
||||||
{
|
{
|
||||||
int ret, irq;
|
int ret, irq;
|
||||||
@@ -484,7 +572,12 @@ int dwc3_drd_init(struct dwc3 *dwc)
|
|||||||
if (IS_ERR(dwc->edev))
|
if (IS_ERR(dwc->edev))
|
||||||
return PTR_ERR(dwc->edev);
|
return PTR_ERR(dwc->edev);
|
||||||
|
|
||||||
if (dwc->edev) {
|
if (ROLE_SWITCH &&
|
||||||
|
device_property_read_bool(dwc->dev, "usb-role-switch")) {
|
||||||
|
ret = dwc3_setup_role_switch(dwc);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
} else if (dwc->edev) {
|
||||||
dwc->edev_nb.notifier_call = dwc3_drd_notifier;
|
dwc->edev_nb.notifier_call = dwc3_drd_notifier;
|
||||||
ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
|
ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
|
||||||
&dwc->edev_nb);
|
&dwc->edev_nb);
|
||||||
@@ -531,6 +624,9 @@ void dwc3_drd_exit(struct dwc3 *dwc)
|
|||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (dwc->role_sw)
|
||||||
|
usb_role_switch_unregister(dwc->role_sw);
|
||||||
|
|
||||||
if (dwc->edev)
|
if (dwc->edev)
|
||||||
extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
|
extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
|
||||||
&dwc->edev_nb);
|
&dwc->edev_nb);
|
||||||
|
|||||||
@@ -162,6 +162,12 @@ static const struct dwc3_exynos_driverdata exynos5250_drvdata = {
|
|||||||
.suspend_clk_idx = -1,
|
.suspend_clk_idx = -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct dwc3_exynos_driverdata exynos5420_drvdata = {
|
||||||
|
.clk_names = { "usbdrd30", "usbdrd30_susp_clk"},
|
||||||
|
.num_clks = 2,
|
||||||
|
.suspend_clk_idx = 1,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct dwc3_exynos_driverdata exynos5433_drvdata = {
|
static const struct dwc3_exynos_driverdata exynos5433_drvdata = {
|
||||||
.clk_names = { "aclk", "susp_clk", "pipe_pclk", "phyclk" },
|
.clk_names = { "aclk", "susp_clk", "pipe_pclk", "phyclk" },
|
||||||
.num_clks = 4,
|
.num_clks = 4,
|
||||||
@@ -178,6 +184,9 @@ static const struct of_device_id exynos_dwc3_match[] = {
|
|||||||
{
|
{
|
||||||
.compatible = "samsung,exynos5250-dwusb3",
|
.compatible = "samsung,exynos5250-dwusb3",
|
||||||
.data = &exynos5250_drvdata,
|
.data = &exynos5250_drvdata,
|
||||||
|
}, {
|
||||||
|
.compatible = "samsung,exynos5420-dwusb3",
|
||||||
|
.data = &exynos5420_drvdata,
|
||||||
}, {
|
}, {
|
||||||
.compatible = "samsung,exynos5433-dwusb3",
|
.compatible = "samsung,exynos5433-dwusb3",
|
||||||
.data = &exynos5433_drvdata,
|
.data = &exynos5433_drvdata,
|
||||||
|
|||||||
@@ -107,10 +107,37 @@ static const char *phy_names[PHY_COUNT] = {
|
|||||||
"usb2-phy0", "usb2-phy1", "usb3-phy0",
|
"usb2-phy0", "usb2-phy1", "usb3-phy0",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct clk_bulk_data meson_g12a_clocks[] = {
|
||||||
|
{ .id = NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct clk_bulk_data meson_a1_clocks[] = {
|
||||||
|
{ .id = "usb_ctrl" },
|
||||||
|
{ .id = "usb_bus" },
|
||||||
|
{ .id = "xtal_usb_ctrl" },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dwc3_meson_g12a_drvdata {
|
||||||
|
bool otg_switch_supported;
|
||||||
|
struct clk_bulk_data *clks;
|
||||||
|
int num_clks;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dwc3_meson_g12a_drvdata g12a_drvdata = {
|
||||||
|
.otg_switch_supported = true,
|
||||||
|
.clks = meson_g12a_clocks,
|
||||||
|
.num_clks = ARRAY_SIZE(meson_g12a_clocks),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dwc3_meson_g12a_drvdata a1_drvdata = {
|
||||||
|
.otg_switch_supported = false,
|
||||||
|
.clks = meson_a1_clocks,
|
||||||
|
.num_clks = ARRAY_SIZE(meson_a1_clocks),
|
||||||
|
};
|
||||||
|
|
||||||
struct dwc3_meson_g12a {
|
struct dwc3_meson_g12a {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
struct clk *clk;
|
|
||||||
struct reset_control *reset;
|
struct reset_control *reset;
|
||||||
struct phy *phys[PHY_COUNT];
|
struct phy *phys[PHY_COUNT];
|
||||||
enum usb_dr_mode otg_mode;
|
enum usb_dr_mode otg_mode;
|
||||||
@@ -120,6 +147,7 @@ struct dwc3_meson_g12a {
|
|||||||
struct regulator *vbus;
|
struct regulator *vbus;
|
||||||
struct usb_role_switch_desc switch_desc;
|
struct usb_role_switch_desc switch_desc;
|
||||||
struct usb_role_switch *role_switch;
|
struct usb_role_switch *role_switch;
|
||||||
|
const struct dwc3_meson_g12a_drvdata *drvdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv,
|
static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv,
|
||||||
@@ -151,7 +179,7 @@ static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv)
|
|||||||
U2P_R0_POWER_ON_RESET,
|
U2P_R0_POWER_ON_RESET,
|
||||||
U2P_R0_POWER_ON_RESET);
|
U2P_R0_POWER_ON_RESET);
|
||||||
|
|
||||||
if (i == USB2_OTG_PHY) {
|
if (priv->drvdata->otg_switch_supported && i == USB2_OTG_PHY) {
|
||||||
regmap_update_bits(priv->regmap,
|
regmap_update_bits(priv->regmap,
|
||||||
U2P_R0 + (U2P_REG_SIZE * i),
|
U2P_R0 + (U2P_REG_SIZE * i),
|
||||||
U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS,
|
U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS,
|
||||||
@@ -295,7 +323,7 @@ static int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!priv->phys[USB2_OTG_PHY])
|
if (!priv->drvdata->otg_switch_supported || !priv->phys[USB2_OTG_PHY])
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (mode == PHY_MODE_USB_HOST)
|
if (mode == PHY_MODE_USB_HOST)
|
||||||
@@ -321,9 +349,10 @@ static int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dwc3_meson_g12a_role_set(struct device *dev, enum usb_role role)
|
static int dwc3_meson_g12a_role_set(struct usb_role_switch *sw,
|
||||||
|
enum usb_role role)
|
||||||
{
|
{
|
||||||
struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
|
struct dwc3_meson_g12a *priv = usb_role_switch_get_drvdata(sw);
|
||||||
enum phy_mode mode;
|
enum phy_mode mode;
|
||||||
|
|
||||||
if (role == USB_ROLE_NONE)
|
if (role == USB_ROLE_NONE)
|
||||||
@@ -338,9 +367,9 @@ static int dwc3_meson_g12a_role_set(struct device *dev, enum usb_role role)
|
|||||||
return dwc3_meson_g12a_otg_mode_set(priv, mode);
|
return dwc3_meson_g12a_otg_mode_set(priv, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum usb_role dwc3_meson_g12a_role_get(struct device *dev)
|
static enum usb_role dwc3_meson_g12a_role_get(struct usb_role_switch *sw)
|
||||||
{
|
{
|
||||||
struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
|
struct dwc3_meson_g12a *priv = usb_role_switch_get_drvdata(sw);
|
||||||
|
|
||||||
return priv->otg_phy_mode == PHY_MODE_USB_HOST ?
|
return priv->otg_phy_mode == PHY_MODE_USB_HOST ?
|
||||||
USB_ROLE_HOST : USB_ROLE_DEVICE;
|
USB_ROLE_HOST : USB_ROLE_DEVICE;
|
||||||
@@ -380,14 +409,61 @@ static struct device *dwc3_meson_g12_find_child(struct device *dev,
|
|||||||
return &pdev->dev;
|
return &pdev->dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dwc3_meson_g12a_otg_init(struct platform_device *pdev,
|
||||||
|
struct dwc3_meson_g12a *priv)
|
||||||
|
{
|
||||||
|
enum phy_mode otg_id;
|
||||||
|
int ret, irq;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
|
||||||
|
if (!priv->drvdata->otg_switch_supported)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (priv->otg_mode == USB_DR_MODE_OTG) {
|
||||||
|
/* Ack irq before registering */
|
||||||
|
regmap_update_bits(priv->regmap, USB_R5,
|
||||||
|
USB_R5_ID_DIG_IRQ, 0);
|
||||||
|
|
||||||
|
irq = platform_get_irq(pdev, 0);
|
||||||
|
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||||
|
dwc3_meson_g12a_irq_thread,
|
||||||
|
IRQF_ONESHOT, pdev->name, priv);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup OTG mode corresponding to the ID pin */
|
||||||
|
if (priv->otg_mode == USB_DR_MODE_OTG) {
|
||||||
|
otg_id = dwc3_meson_g12a_get_id(priv);
|
||||||
|
if (otg_id != priv->otg_phy_mode) {
|
||||||
|
if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
|
||||||
|
dev_warn(dev, "Failed to switch OTG mode\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup role switcher */
|
||||||
|
priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev,
|
||||||
|
"snps,dwc3");
|
||||||
|
priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2");
|
||||||
|
priv->switch_desc.allow_userspace_control = true;
|
||||||
|
priv->switch_desc.set = dwc3_meson_g12a_role_set;
|
||||||
|
priv->switch_desc.get = dwc3_meson_g12a_role_get;
|
||||||
|
priv->switch_desc.driver_data = priv;
|
||||||
|
|
||||||
|
priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc);
|
||||||
|
if (IS_ERR(priv->role_switch))
|
||||||
|
dev_warn(dev, "Unable to register Role Switch\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int dwc3_meson_g12a_probe(struct platform_device *pdev)
|
static int dwc3_meson_g12a_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct dwc3_meson_g12a *priv;
|
struct dwc3_meson_g12a *priv;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct device_node *np = dev->of_node;
|
struct device_node *np = dev->of_node;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
enum phy_mode otg_id;
|
int ret, i;
|
||||||
int ret, i, irq;
|
|
||||||
|
|
||||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
if (!priv)
|
if (!priv)
|
||||||
@@ -409,17 +485,18 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
|
|||||||
priv->vbus = NULL;
|
priv->vbus = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->clk = devm_clk_get(dev, NULL);
|
priv->drvdata = of_device_get_match_data(&pdev->dev);
|
||||||
if (IS_ERR(priv->clk))
|
|
||||||
return PTR_ERR(priv->clk);
|
|
||||||
|
|
||||||
ret = clk_prepare_enable(priv->clk);
|
ret = devm_clk_bulk_get(dev,
|
||||||
|
priv->drvdata->num_clks,
|
||||||
|
priv->drvdata->clks);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
devm_add_action_or_reset(dev,
|
ret = clk_bulk_prepare_enable(priv->drvdata->num_clks,
|
||||||
(void(*)(void *))clk_disable_unprepare,
|
priv->drvdata->clks);
|
||||||
priv->clk);
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, priv);
|
platform_set_drvdata(pdev, priv);
|
||||||
priv->dev = dev;
|
priv->dev = dev;
|
||||||
@@ -433,41 +510,28 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
ret = reset_control_reset(priv->reset);
|
ret = reset_control_reset(priv->reset);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto err_disable_clks;
|
||||||
|
|
||||||
ret = dwc3_meson_g12a_get_phys(priv);
|
ret = dwc3_meson_g12a_get_phys(priv);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto err_disable_clks;
|
||||||
|
|
||||||
if (priv->vbus) {
|
if (priv->vbus) {
|
||||||
ret = regulator_enable(priv->vbus);
|
ret = regulator_enable(priv->vbus);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto err_disable_clks;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get dr_mode */
|
/* Get dr_mode */
|
||||||
priv->otg_mode = usb_get_dr_mode(dev);
|
priv->otg_mode = usb_get_dr_mode(dev);
|
||||||
|
|
||||||
if (priv->otg_mode == USB_DR_MODE_OTG) {
|
|
||||||
/* Ack irq before registering */
|
|
||||||
regmap_update_bits(priv->regmap, USB_R5,
|
|
||||||
USB_R5_ID_DIG_IRQ, 0);
|
|
||||||
|
|
||||||
irq = platform_get_irq(pdev, 0);
|
|
||||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
|
||||||
dwc3_meson_g12a_irq_thread,
|
|
||||||
IRQF_ONESHOT, pdev->name, priv);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
dwc3_meson_g12a_usb_init(priv);
|
dwc3_meson_g12a_usb_init(priv);
|
||||||
|
|
||||||
/* Init PHYs */
|
/* Init PHYs */
|
||||||
for (i = 0 ; i < PHY_COUNT ; ++i) {
|
for (i = 0 ; i < PHY_COUNT ; ++i) {
|
||||||
ret = phy_init(priv->phys[i]);
|
ret = phy_init(priv->phys[i]);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto err_disable_clks;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set PHY Power */
|
/* Set PHY Power */
|
||||||
@@ -478,31 +542,12 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = of_platform_populate(np, NULL, NULL, dev);
|
ret = of_platform_populate(np, NULL, NULL, dev);
|
||||||
if (ret) {
|
if (ret)
|
||||||
clk_disable_unprepare(priv->clk);
|
|
||||||
goto err_phys_power;
|
goto err_phys_power;
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup OTG mode corresponding to the ID pin */
|
ret = dwc3_meson_g12a_otg_init(pdev, priv);
|
||||||
if (priv->otg_mode == USB_DR_MODE_OTG) {
|
if (ret)
|
||||||
otg_id = dwc3_meson_g12a_get_id(priv);
|
goto err_phys_power;
|
||||||
if (otg_id != priv->otg_phy_mode) {
|
|
||||||
if (dwc3_meson_g12a_otg_mode_set(priv, otg_id))
|
|
||||||
dev_warn(dev, "Failed to switch OTG mode\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup role switcher */
|
|
||||||
priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev,
|
|
||||||
"snps,dwc3");
|
|
||||||
priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2");
|
|
||||||
priv->switch_desc.allow_userspace_control = true;
|
|
||||||
priv->switch_desc.set = dwc3_meson_g12a_role_set;
|
|
||||||
priv->switch_desc.get = dwc3_meson_g12a_role_get;
|
|
||||||
|
|
||||||
priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc);
|
|
||||||
if (IS_ERR(priv->role_switch))
|
|
||||||
dev_warn(dev, "Unable to register Role Switch\n");
|
|
||||||
|
|
||||||
pm_runtime_set_active(dev);
|
pm_runtime_set_active(dev);
|
||||||
pm_runtime_enable(dev);
|
pm_runtime_enable(dev);
|
||||||
@@ -518,6 +563,10 @@ err_phys_exit:
|
|||||||
for (i = 0 ; i < PHY_COUNT ; ++i)
|
for (i = 0 ; i < PHY_COUNT ; ++i)
|
||||||
phy_exit(priv->phys[i]);
|
phy_exit(priv->phys[i]);
|
||||||
|
|
||||||
|
err_disable_clks:
|
||||||
|
clk_bulk_disable_unprepare(priv->drvdata->num_clks,
|
||||||
|
priv->drvdata->clks);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,7 +576,8 @@ static int dwc3_meson_g12a_remove(struct platform_device *pdev)
|
|||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
usb_role_switch_unregister(priv->role_switch);
|
if (priv->drvdata->otg_switch_supported)
|
||||||
|
usb_role_switch_unregister(priv->role_switch);
|
||||||
|
|
||||||
of_platform_depopulate(dev);
|
of_platform_depopulate(dev);
|
||||||
|
|
||||||
@@ -540,6 +590,9 @@ static int dwc3_meson_g12a_remove(struct platform_device *pdev)
|
|||||||
pm_runtime_put_noidle(dev);
|
pm_runtime_put_noidle(dev);
|
||||||
pm_runtime_set_suspended(dev);
|
pm_runtime_set_suspended(dev);
|
||||||
|
|
||||||
|
clk_bulk_disable_unprepare(priv->drvdata->num_clks,
|
||||||
|
priv->drvdata->clks);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -547,7 +600,8 @@ static int __maybe_unused dwc3_meson_g12a_runtime_suspend(struct device *dev)
|
|||||||
{
|
{
|
||||||
struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
|
struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
|
||||||
|
|
||||||
clk_disable(priv->clk);
|
clk_bulk_disable_unprepare(priv->drvdata->num_clks,
|
||||||
|
priv->drvdata->clks);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -556,7 +610,8 @@ static int __maybe_unused dwc3_meson_g12a_runtime_resume(struct device *dev)
|
|||||||
{
|
{
|
||||||
struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
|
struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
|
||||||
|
|
||||||
return clk_enable(priv->clk);
|
return clk_bulk_prepare_enable(priv->drvdata->num_clks,
|
||||||
|
priv->drvdata->clks);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev)
|
static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev)
|
||||||
@@ -619,7 +674,14 @@ static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id dwc3_meson_g12a_match[] = {
|
static const struct of_device_id dwc3_meson_g12a_match[] = {
|
||||||
{ .compatible = "amlogic,meson-g12a-usb-ctrl" },
|
{
|
||||||
|
.compatible = "amlogic,meson-g12a-usb-ctrl",
|
||||||
|
.data = &g12a_drvdata,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "amlogic,meson-a1-usb-ctrl",
|
||||||
|
.data = &a1_drvdata,
|
||||||
|
},
|
||||||
{ /* Sentinel */ }
|
{ /* Sentinel */ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match);
|
MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/clk-provider.h>
|
#include <linux/of_clk.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/extcon.h>
|
#include <linux/extcon.h>
|
||||||
|
|||||||
@@ -1521,7 +1521,7 @@ static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, struct dwc3_request *r
|
|||||||
for (i = 0; i < req->num_trbs; i++) {
|
for (i = 0; i < req->num_trbs; i++) {
|
||||||
struct dwc3_trb *trb;
|
struct dwc3_trb *trb;
|
||||||
|
|
||||||
trb = req->trb + i;
|
trb = &dep->trb_pool[dep->trb_dequeue];
|
||||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||||
dwc3_ep_inc_deq(dep);
|
dwc3_ep_inc_deq(dep);
|
||||||
}
|
}
|
||||||
@@ -2570,10 +2570,8 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep,
|
|||||||
|
|
||||||
dwc3_gadget_ep_cleanup_completed_requests(dep, event, status);
|
dwc3_gadget_ep_cleanup_completed_requests(dep, event, status);
|
||||||
|
|
||||||
if (stop) {
|
if (stop)
|
||||||
dwc3_stop_active_transfer(dep, true, true);
|
dwc3_stop_active_transfer(dep, true, true);
|
||||||
dep->flags = DWC3_EP_ENABLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
|
* WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user