mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 23:13:01 +02:00
phy-for-6.16
- New Support - Qualcomm IPQ5424 qusb2 support, IPQ5018 uniphy-pcie driver - Rockchip usb2 support for RK3562, RK3036 usb2 phy support - Samsung exynos2200 eusb2 phy support and driver refactoring for this support, exynos7870 USBDRD support - Mediatek MT7988 xs-phy support - Broadcom BCM74110 usb phy support - Renesas RZ/V2H(P) usb2 phy support - Updates - Freescale phy rate claculation updates, i.MX95 tuning support - Better error handling for amlogic pcie phy - Rockchip color depth configuration and management support - Yaml binding conversion for RK3399 Type-C and PCIe Phy -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmhBORsACgkQfBQHDyUj g0fz8BAA1ULmArQnbsgi12tBgYW8h4YgwDZtweGpvd25nqStCfNu4L4IVc7MdITc zWc1JeMvuv5X+A7OHGlq+he+nMm5VQPFzxjCN2nlvIONSKj4KxgHrP/HJChzIZhI FOGwpwhmBFAFrrbeEOnChBqDal9BFBVAmTmr8dM+Z3/fIpQS7yj5f5Foy7Jy39GQ eBzNRbzN8e1djVhyLUHOITvGhx1CtIoePZMUhyZcyjDxyFyyeoeLmN5ypeu3mebF HWqDsW4ZJr1yEkEe9DrnDFY7qmBdLYOmjxDpINFjkV3+35qBKK/QNX8aZtTrk5lH 6LJxdjUXWuaPRcJo5joU0FxHrGChEp2+QDliqdreQyrebs+VZHJi06dR2sPm6mSe oaRb/OhOaXhG/fH2U7skj5lR9o6SRv8J8c6SQ6/xtTHuNKun8saRSTL2RYkB+3BJ 4D9LoVLs8NP0Gc3LZIVXFyhLRW8OpHY+vqk4XASTgrTX6yjKrb7Lt/nNNfU/Z+/r 3yFcGTwFBa/YYZyXtCB3z5iFTTMjZB8SJwbcB80j6Y9vXv/u1tN20XdZN2jWEjWs bjWt3nSSw3b+UYB8XPtXXRdhXfsuOEnVQR+JyoYNFjlgChmmkYDW7M40lkw1UUte XzcZUV+gbZZWy6zpGyDRzEz23Eo4T5XXXo91bZ5zRDCJH4iIv2A= =VxLP -----END PGP SIGNATURE----- Merge tag 'phy-for-6.16' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy Pull phy updates from Vinod Koul: "As usual featuring couple of new driver and bunch of new device support and some driver changes to Freescale, rockchip driver along with couple of yaml binding conversions. New Support: - Qualcomm IPQ5424 qusb2 support, IPQ5018 uniphy-pcie driver - Rockchip usb2 support for RK3562, RK3036 usb2 phy support - Samsung exynos2200 eusb2 phy support and driver refactoring for this support, exynos7870 USBDRD support - Mediatek MT7988 xs-phy support - Broadcom BCM74110 usb phy support - Renesas RZ/V2H(P) usb2 phy support Updates: - Freescale phy rate claculation updates, i.MX95 tuning support - Better error handling for amlogic pcie phy - Rockchip color depth configuration and management support - Yaml binding conversion for RK3399 Type-C and PCIe Phy" * tag 'phy-for-6.16' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (77 commits) phy: tegra: p2u: Broaden architecture dependency phy: rockchip: inno-usb2: Add usb2 phy support for rk3562 dt-bindings: phy: rockchip,inno-usb2phy: add rk3562 phy: rockchip: inno-usb2: add phy definition for rk3036 dt-bindings: phy: rockchip,inno-usb2phy: add rk3036 compatible phy: freescale: fsl-samsung-hdmi: Improve LUT search for best clock phy: freescale: fsl-samsung-hdmi: Refactor finding PHY settings phy: freescale: fsl-samsung-hdmi: Rename phy_clk_round_rate phy: renesas: phy-rcar-gen3-usb2: Add USB2.0 PHY support for RZ/V2H(P) phy: renesas: phy-rcar-gen3-usb2: Sort compatible entries by SoC part number dt-bindings: phy: renesas,usb2-phy: Document RZ/V2H(P) SoC dt-bindings: phy: renesas,usb2-phy: Add clock constraint for RZ/G2L family phy: exynos5-usbdrd: support Exynos USBDRD 3.2 4nm controller phy: phy-snps-eusb2: add support for exynos2200 phy: phy-snps-eusb2: refactor reference clock init phy: phy-snps-eusb2: make reset control optional phy: phy-snps-eusb2: make repeater optional phy: phy-snps-eusb2: split phy init code phy: phy-snps-eusb2: refactor constructs names phy: move phy-qcom-snps-eusb2 out of its vendor sub-directory ...
This commit is contained in:
commit
d12ed2b7e1
|
@ -18,6 +18,7 @@ properties:
|
|||
- brcm,bcm4908-usb-phy
|
||||
- brcm,bcm7211-usb-phy
|
||||
- brcm,bcm7216-usb-phy
|
||||
- brcm,bcm74110-usb-phy
|
||||
- brcm,brcmstb-usb-phy
|
||||
|
||||
reg:
|
||||
|
@ -139,7 +140,9 @@ allOf:
|
|||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: brcm,bcm7216-usb-phy
|
||||
enum:
|
||||
- brcm,bcm7216-usb-phy
|
||||
- brcm,bcm74110-usb-phy
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
|
|
|
@ -43,15 +43,15 @@ properties:
|
|||
fsl,phy-tx-vref-tune-percent:
|
||||
description:
|
||||
Tunes the HS DC level relative to the nominal level
|
||||
minimum: 94
|
||||
minimum: 90
|
||||
maximum: 124
|
||||
|
||||
fsl,phy-tx-rise-tune-percent:
|
||||
description:
|
||||
Adjusts the rise/fall time duration of the HS waveform relative to
|
||||
its nominal value
|
||||
minimum: 97
|
||||
maximum: 103
|
||||
minimum: 90
|
||||
maximum: 120
|
||||
|
||||
fsl,phy-tx-preemp-amp-tune-microamp:
|
||||
description:
|
||||
|
@ -63,8 +63,7 @@ properties:
|
|||
fsl,phy-tx-vboost-level-microvolt:
|
||||
description:
|
||||
Adjust the boosted transmit launch pk-pk differential amplitude
|
||||
minimum: 880
|
||||
maximum: 1120
|
||||
enum: [844, 1008, 1156]
|
||||
|
||||
fsl,phy-comp-dis-tune-percent:
|
||||
description:
|
||||
|
@ -112,6 +111,34 @@ allOf:
|
|||
reg:
|
||||
maxItems: 1
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx8mq-usb-phy
|
||||
- fsl,imx8mp-usb-phy
|
||||
then:
|
||||
properties:
|
||||
fsl,phy-tx-vref-tune-percent:
|
||||
minimum: 94
|
||||
fsl,phy-tx-rise-tune-percent:
|
||||
minimum: 97
|
||||
maximum: 103
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- fsl,imx95-usb-phy
|
||||
then:
|
||||
properties:
|
||||
fsl,phy-tx-vref-tune-percent:
|
||||
maximum: 108
|
||||
fsl,phy-comp-dis-tune-percent:
|
||||
minimum: 94
|
||||
maximum: 104
|
||||
|
||||
- if:
|
||||
required:
|
||||
- orientation-switch
|
||||
|
|
|
@ -30,6 +30,7 @@ properties:
|
|||
- const: mediatek,mt8173-mipi-tx
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt6893-mipi-tx
|
||||
- mediatek,mt8188-mipi-tx
|
||||
- mediatek,mt8195-mipi-tx
|
||||
- mediatek,mt8365-mipi-tx
|
||||
|
|
|
@ -78,6 +78,7 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- mediatek,mt2712-tphy
|
||||
- mediatek,mt6893-tphy
|
||||
- mediatek,mt7629-tphy
|
||||
- mediatek,mt7986-tphy
|
||||
- mediatek,mt8183-tphy
|
||||
|
|
|
@ -49,6 +49,7 @@ properties:
|
|||
- enum:
|
||||
- mediatek,mt3611-xsphy
|
||||
- mediatek,mt3612-xsphy
|
||||
- mediatek,mt7988-xsphy
|
||||
- const: mediatek,xsphy
|
||||
|
||||
reg:
|
||||
|
@ -150,6 +151,21 @@ patternProperties:
|
|||
minimum: 1
|
||||
maximum: 31
|
||||
|
||||
mediatek,syscon-type:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
description:
|
||||
A phandle to syscon used to access the register of type switch,
|
||||
the field should always be 3 cells long.
|
||||
items:
|
||||
- items:
|
||||
- description:
|
||||
Phandle to phy type configuration system controller
|
||||
- description:
|
||||
Phy type configuration register offset
|
||||
- description:
|
||||
Index of config segment
|
||||
enum: [0, 1, 2, 3]
|
||||
|
||||
required:
|
||||
- reg
|
||||
- clocks
|
||||
|
|
|
@ -99,8 +99,7 @@ patternProperties:
|
|||
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.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 9
|
||||
enum: [1, 2, 3, 4, 5, 6, 7, 8, 9, 12]
|
||||
|
||||
cdns,num-lanes:
|
||||
description:
|
||||
|
|
|
@ -42,6 +42,9 @@ properties:
|
|||
- const: phy
|
||||
- const: apb
|
||||
|
||||
phy-supply:
|
||||
description: Single PHY regulator
|
||||
|
||||
rockchip,enable-ssc:
|
||||
type: boolean
|
||||
description:
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
* ROCKCHIP type-c PHY
|
||||
---------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : must be "rockchip,rk3399-typec-phy"
|
||||
- reg: Address and length of the usb phy control register set
|
||||
- rockchip,grf : phandle to the syscon managing the "general
|
||||
register files"
|
||||
- clocks : phandle + clock specifier for the phy clocks
|
||||
- clock-names : string, clock name, must be "tcpdcore", "tcpdphy-ref";
|
||||
- assigned-clocks: main clock, should be <&cru SCLK_UPHY0_TCPDCORE> or
|
||||
<&cru SCLK_UPHY1_TCPDCORE>;
|
||||
- assigned-clock-rates : the phy core clk frequency, shall be: 50000000
|
||||
- resets : a list of phandle + reset specifier pairs
|
||||
- reset-names : string reset name, must be:
|
||||
"uphy", "uphy-pipe", "uphy-tcphy"
|
||||
|
||||
Optional properties:
|
||||
- extcon : extcon specifier for the Power Delivery
|
||||
|
||||
Required nodes : a sub-node is required for each port the phy provides.
|
||||
The sub-node name is used to identify dp or usb3 port,
|
||||
and shall be the following entries:
|
||||
* "dp-port" : the name of DP port.
|
||||
* "usb3-port" : the name of USB3 port.
|
||||
|
||||
Required properties (port (child) node):
|
||||
- #phy-cells : must be 0, See ./phy-bindings.txt for details.
|
||||
|
||||
Deprecated properties, do not use in new device tree sources, these
|
||||
properties are determined by the compatible value:
|
||||
- rockchip,typec-conn-dir
|
||||
- rockchip,usb3tousb2-en
|
||||
- rockchip,external-psm
|
||||
- rockchip,pipe-status
|
||||
|
||||
Example:
|
||||
tcphy0: phy@ff7c0000 {
|
||||
compatible = "rockchip,rk3399-typec-phy";
|
||||
reg = <0x0 0xff7c0000 0x0 0x40000>;
|
||||
rockchip,grf = <&grf>;
|
||||
extcon = <&fusb0>;
|
||||
clocks = <&cru SCLK_UPHY0_TCPDCORE>,
|
||||
<&cru SCLK_UPHY0_TCPDPHY_REF>;
|
||||
clock-names = "tcpdcore", "tcpdphy-ref";
|
||||
assigned-clocks = <&cru SCLK_UPHY0_TCPDCORE>;
|
||||
assigned-clock-rates = <50000000>;
|
||||
resets = <&cru SRST_UPHY0>,
|
||||
<&cru SRST_UPHY0_PIPE_L00>,
|
||||
<&cru SRST_P_UPHY0_TCPHY>;
|
||||
reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
|
||||
|
||||
tcphy0_dp: dp-port {
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
tcphy0_usb3: usb3-port {
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
tcphy1: phy@ff800000 {
|
||||
compatible = "rockchip,rk3399-typec-phy";
|
||||
reg = <0x0 0xff800000 0x0 0x40000>;
|
||||
rockchip,grf = <&grf>;
|
||||
extcon = <&fusb1>;
|
||||
clocks = <&cru SCLK_UPHY1_TCPDCORE>,
|
||||
<&cru SCLK_UPHY1_TCPDPHY_REF>;
|
||||
clock-names = "tcpdcore", "tcpdphy-ref";
|
||||
assigned-clocks = <&cru SCLK_UPHY1_TCPDCORE>;
|
||||
assigned-clock-rates = <50000000>;
|
||||
resets = <&cru SRST_UPHY1>,
|
||||
<&cru SRST_UPHY1_PIPE_L00>,
|
||||
<&cru SRST_P_UPHY1_TCPHY>;
|
||||
reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
|
||||
|
||||
tcphy1_dp: dp-port {
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
tcphy1_usb3: usb3-port {
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
};
|
|
@ -47,6 +47,9 @@ properties:
|
|||
- const: pcs_apb
|
||||
- const: pma_apb
|
||||
|
||||
phy-supply:
|
||||
description: Single PHY regulator
|
||||
|
||||
rockchip,dp-lane-mux:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
minItems: 2
|
||||
|
|
|
@ -11,26 +11,24 @@ maintainers:
|
|||
- Varadarajan Narayanan <quic_varada@quicinc.com>
|
||||
|
||||
description:
|
||||
PCIe and USB combo PHY found in Qualcomm IPQ5332 SoC
|
||||
PCIe and USB combo PHY found in Qualcomm IPQ5018 & IPQ5332 SoCs
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,ipq5018-uniphy-pcie-phy
|
||||
- qcom,ipq5332-uniphy-pcie-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: pcie pipe clock
|
||||
- description: pcie ahb clock
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: phy reset
|
||||
- description: ahb reset
|
||||
- description: cfg reset
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
@ -53,6 +51,41 @@ required:
|
|||
|
||||
additionalProperties: false
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,ipq5018-uniphy-pcie-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: pcie pipe clock
|
||||
resets:
|
||||
items:
|
||||
- description: phy reset
|
||||
- description: cfg reset
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,ipq5332-uniphy-pcie-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: pcie pipe clock
|
||||
- description: pcie ahb clock
|
||||
resets:
|
||||
items:
|
||||
- description: phy reset
|
||||
- description: ahb reset
|
||||
- description: cfg reset
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,ipq5332-gcc.h>
|
||||
|
|
|
@ -16,6 +16,7 @@ properties:
|
|||
- enum:
|
||||
- renesas,usb2-phy-r8a77470 # RZ/G1C
|
||||
- renesas,usb2-phy-r9a08g045 # RZ/G3S
|
||||
- renesas,usb2-phy-r9a09g057 # RZ/V2H(P)
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
|
@ -105,8 +106,13 @@ allOf:
|
|||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,rzg2l-usb2-phy
|
||||
enum:
|
||||
- renesas,usb2-phy-r9a09g057
|
||||
- renesas,rzg2l-usb2-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
required:
|
||||
- resets
|
||||
|
||||
|
|
|
@ -13,12 +13,14 @@ properties:
|
|||
compatible:
|
||||
enum:
|
||||
- rockchip,px30-usb2phy
|
||||
- rockchip,rk3036-usb2phy
|
||||
- rockchip,rk3128-usb2phy
|
||||
- rockchip,rk3228-usb2phy
|
||||
- rockchip,rk3308-usb2phy
|
||||
- rockchip,rk3328-usb2phy
|
||||
- rockchip,rk3366-usb2phy
|
||||
- rockchip,rk3399-usb2phy
|
||||
- rockchip,rk3562-usb2phy
|
||||
- rockchip,rk3568-usb2phy
|
||||
- rockchip,rk3576-usb2phy
|
||||
- rockchip,rk3588-usb2phy
|
||||
|
@ -184,12 +186,14 @@ allOf:
|
|||
contains:
|
||||
enum:
|
||||
- rockchip,px30-usb2phy
|
||||
- rockchip,rk3036-usb2phy
|
||||
- rockchip,rk3128-usb2phy
|
||||
- rockchip,rk3228-usb2phy
|
||||
- rockchip,rk3308-usb2phy
|
||||
- rockchip,rk3328-usb2phy
|
||||
- rockchip,rk3366-usb2phy
|
||||
- rockchip,rk3399-usb2phy
|
||||
- rockchip,rk3562-usb2phy
|
||||
- rockchip,rk3568-usb2phy
|
||||
- rockchip,rk3588-usb2phy
|
||||
- rockchip,rv1108-usb2phy
|
||||
|
|
|
@ -46,6 +46,9 @@ properties:
|
|||
reset-names:
|
||||
const: phy
|
||||
|
||||
phy-supply:
|
||||
description: Single PHY regulator
|
||||
|
||||
rockchip,phy-grf:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: phandle to the syscon managing the phy "general register files"
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/rockchip,rk3399-pcie-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rockchip RK3399 PCIE PHY
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: rockchip,rk3399-pcie-phy
|
||||
|
||||
'#phy-cells':
|
||||
oneOf:
|
||||
- const: 0
|
||||
deprecated: true
|
||||
- const: 1
|
||||
description: One lane per phy mode
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: refclk
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
const: phy
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- '#phy-cells'
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
...
|
|
@ -0,0 +1,116 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/rockchip,rk3399-typec-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rockchip Type-C PHY
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: rockchip,rk3399-typec-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: tcpdcore
|
||||
- const: tcpdphy-ref
|
||||
|
||||
extcon: true
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 3
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: uphy
|
||||
- const: uphy-pipe
|
||||
- const: uphy-tcphy
|
||||
|
||||
rockchip,grf:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to the syscon managing the "general register files" (GRF).
|
||||
|
||||
dp-port:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
'#phy-cells':
|
||||
const: 0
|
||||
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: Connection to USB Type-C connector
|
||||
|
||||
required:
|
||||
- '#phy-cells'
|
||||
|
||||
usb3-port:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
'#phy-cells':
|
||||
const: 0
|
||||
|
||||
orientation-switch: true
|
||||
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: Connection to USB Type-C connector SS port
|
||||
|
||||
required:
|
||||
- '#phy-cells'
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- reset-names
|
||||
- dp-port
|
||||
- usb3-port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/rk3399-cru.h>
|
||||
|
||||
phy@ff7c0000 {
|
||||
compatible = "rockchip,rk3399-typec-phy";
|
||||
reg = <0xff7c0000 0x40000>;
|
||||
rockchip,grf = <&grf>;
|
||||
extcon = <&fusb0>;
|
||||
clocks = <&cru SCLK_UPHY0_TCPDCORE>,
|
||||
<&cru SCLK_UPHY0_TCPDPHY_REF>;
|
||||
clock-names = "tcpdcore", "tcpdphy-ref";
|
||||
resets = <&cru SRST_UPHY0>,
|
||||
<&cru SRST_UPHY0_PIPE_L00>,
|
||||
<&cru SRST_P_UPHY0_TCPHY>;
|
||||
reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
|
||||
|
||||
dp-port {
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
usb3-port {
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -1,36 +0,0 @@
|
|||
Rockchip PCIE PHY
|
||||
-----------------------
|
||||
|
||||
Required properties:
|
||||
- compatible: rockchip,rk3399-pcie-phy
|
||||
- clocks: Must contain an entry in clock-names.
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names: Must be "refclk"
|
||||
- resets: Must contain an entry in reset-names.
|
||||
See ../reset/reset.txt for details.
|
||||
- reset-names: Must be "phy"
|
||||
|
||||
Required properties for legacy PHY mode (deprecated):
|
||||
- #phy-cells: must be 0
|
||||
|
||||
Required properties for per-lane PHY mode (preferred):
|
||||
- #phy-cells: must be 1
|
||||
|
||||
Example:
|
||||
|
||||
grf: syscon@ff770000 {
|
||||
compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
...
|
||||
|
||||
pcie_phy: pcie-phy {
|
||||
compatible = "rockchip,rk3399-pcie-phy";
|
||||
#phy-cells = <0>;
|
||||
clocks = <&cru SCLK_PCIEPHY_REF>;
|
||||
clock-names = "refclk";
|
||||
resets = <&cru SRST_PCIEPHY>;
|
||||
reset-names = "phy";
|
||||
};
|
||||
};
|
|
@ -0,0 +1,80 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/samsung,exynos2200-eusb2-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Samsung Exynos2200 eUSB2 phy controller
|
||||
|
||||
maintainers:
|
||||
- Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>
|
||||
|
||||
description:
|
||||
Samsung Exynos2200 eUSB2 phy, based on Synopsys eUSB2 IP block, supports
|
||||
LS/FS/HS usb connectivity.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- samsung,exynos2200-eusb2-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Reference clock
|
||||
- description: Bus (APB) clock
|
||||
- description: Control clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ref
|
||||
- const: bus
|
||||
- const: ctrl
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
description:
|
||||
Phandle to eUSB2 to USB 2.0 repeater
|
||||
|
||||
vdd-supply:
|
||||
description:
|
||||
Phandle to 0.88V regulator supply to PHY digital circuit.
|
||||
|
||||
vdda12-supply:
|
||||
description:
|
||||
Phandle to 1.2V regulator supply to PHY refclk pll block.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#phy-cells"
|
||||
- clocks
|
||||
- clock-names
|
||||
- vdd-supply
|
||||
- vdda12-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
usb_hsphy: phy@10ab0000 {
|
||||
compatible = "samsung,exynos2200-eusb2-phy";
|
||||
reg = <0x10ab0000 0x10000>;
|
||||
#phy-cells = <0>;
|
||||
|
||||
clocks = <&cmu_hsi0 7>,
|
||||
<&cmu_hsi0 5>,
|
||||
<&cmu_hsi0 8>;
|
||||
clock-names = "ref", "bus", "ctrl";
|
||||
|
||||
vdd-supply = <&vreg_0p88>;
|
||||
vdda12-supply = <&vreg_1p2>;
|
||||
};
|
|
@ -26,31 +26,41 @@ properties:
|
|||
compatible:
|
||||
enum:
|
||||
- google,gs101-usb31drd-phy
|
||||
- samsung,exynos2200-usb32drd-phy
|
||||
- samsung,exynos5250-usbdrd-phy
|
||||
- samsung,exynos5420-usbdrd-phy
|
||||
- samsung,exynos5433-usbdrd-phy
|
||||
- samsung,exynos7-usbdrd-phy
|
||||
- samsung,exynos7870-usbdrd-phy
|
||||
- samsung,exynos850-usbdrd-phy
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
minItems: 1
|
||||
maxItems: 5
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
minItems: 1
|
||||
maxItems: 5
|
||||
description: |
|
||||
At least two clocks::
|
||||
Typically two clocks:
|
||||
- Main PHY clock (same as USB DRD controller i.e. DWC3 IP clock), used
|
||||
for register access.
|
||||
- PHY reference clock (usually crystal clock), used for PHY operations,
|
||||
associated by phy name. It is used to determine bit values for clock
|
||||
settings register. For Exynos5420 this is given as 'sclk_usbphy30'
|
||||
in the CMU.
|
||||
in the CMU. It's not needed for Exynos2200.
|
||||
|
||||
"#phy-cells":
|
||||
const: 1
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
description:
|
||||
USBDRD-underlying high-speed PHY
|
||||
|
||||
phy-names:
|
||||
const: hs
|
||||
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
|
@ -150,6 +160,27 @@ allOf:
|
|||
- vdda-usbdp-supply
|
||||
- vddh-usbdp-supply
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- samsung,exynos2200-usb32drd-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 1
|
||||
clock-names:
|
||||
items:
|
||||
- const: phy
|
||||
reg:
|
||||
maxItems: 1
|
||||
reg-names:
|
||||
maxItems: 1
|
||||
required:
|
||||
- phys
|
||||
- phy-names
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -184,6 +215,7 @@ allOf:
|
|||
enum:
|
||||
- samsung,exynos5250-usbdrd-phy
|
||||
- samsung,exynos5420-usbdrd-phy
|
||||
- samsung,exynos7870-usbdrd-phy
|
||||
- samsung,exynos850-usbdrd-phy
|
||||
then:
|
||||
properties:
|
||||
|
|
|
@ -208,8 +208,8 @@ allOf:
|
|||
|
||||
pcie-phy:
|
||||
type: object
|
||||
description:
|
||||
Documentation/devicetree/bindings/phy/rockchip-pcie-phy.txt
|
||||
$ref: /schemas/phy/rockchip,rk3399-pcie-phy.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
patternProperties:
|
||||
"^phy@[0-9a-f]+$":
|
||||
|
@ -333,6 +333,15 @@ examples:
|
|||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
pcie-phy {
|
||||
compatible = "rockchip,rk3399-pcie-phy";
|
||||
#phy-cells = <1>;
|
||||
clocks = <&cru SCLK_PCIEPHY_REF>;
|
||||
clock-names = "refclk";
|
||||
resets = <&cru SRST_PCIEPHY>;
|
||||
reset-names = "phy";
|
||||
};
|
||||
|
||||
phy@f780 {
|
||||
compatible = "rockchip,rk3399-emmc-phy";
|
||||
reg = <0xf780 0x20>;
|
||||
|
|
|
@ -18,7 +18,7 @@ description:
|
|||
Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml
|
||||
|
||||
Type-C PHY
|
||||
Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
|
||||
Documentation/devicetree/bindings/phy/rockchip,rk3399-typec-phy.yaml
|
||||
|
||||
select:
|
||||
properties:
|
||||
|
|
|
@ -43,6 +43,14 @@ config PHY_PISTACHIO_USB
|
|||
help
|
||||
Enable this to support the USB2.0 PHY on the IMG Pistachio SoC.
|
||||
|
||||
config PHY_SNPS_EUSB2
|
||||
tristate "SNPS eUSB2 PHY Driver"
|
||||
depends on OF && (ARCH_EXYNOS || ARCH_QCOM || COMPILE_TEST)
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable support for the USB high-speed SNPS eUSB2 phy on select
|
||||
SoCs. The PHY is usually paired with a Synopsys DWC3 USB controller.
|
||||
|
||||
config PHY_XGENE
|
||||
tristate "APM X-Gene 15Gbps PHY support"
|
||||
depends on HAS_IOMEM && OF && (ARCH_XGENE || COMPILE_TEST)
|
||||
|
|
|
@ -9,6 +9,7 @@ obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o
|
|||
obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o
|
||||
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
|
||||
obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
|
||||
obj-$(CONFIG_PHY_SNPS_EUSB2) += phy-snps-eusb2.o
|
||||
obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o
|
||||
obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o
|
||||
obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o
|
||||
|
|
|
@ -377,13 +377,9 @@ static int phy_meson_axg_mipi_dphy_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
|
||||
phy = devm_phy_create(dev, NULL, &phy_meson_axg_mipi_dphy_ops);
|
||||
if (IS_ERR(phy)) {
|
||||
ret = PTR_ERR(phy);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to create PHY\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(phy))
|
||||
return dev_err_probe(dev, PTR_ERR(phy),
|
||||
"failed to create PHY\n");
|
||||
|
||||
phy_set_drvdata(phy, priv);
|
||||
|
||||
|
|
|
@ -200,7 +200,6 @@ static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev)
|
|||
struct phy_axg_mipi_pcie_analog_priv *priv;
|
||||
struct device_node *np = dev->of_node, *parent_np;
|
||||
struct regmap *map;
|
||||
int ret;
|
||||
|
||||
priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
|
@ -219,12 +218,9 @@ static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev)
|
|||
priv->regmap = map;
|
||||
|
||||
priv->phy = devm_phy_create(dev, np, &phy_axg_mipi_pcie_analog_ops);
|
||||
if (IS_ERR(priv->phy)) {
|
||||
ret = PTR_ERR(priv->phy);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to create PHY\n");
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(priv->phy))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->phy),
|
||||
"failed to create PHY\n");
|
||||
|
||||
phy_set_drvdata(priv->phy, priv);
|
||||
dev_set_drvdata(dev, priv);
|
||||
|
|
|
@ -131,20 +131,11 @@ static int phy_axg_pcie_probe(struct platform_device *pdev)
|
|||
struct phy_axg_pcie_priv *priv;
|
||||
struct device_node *np = dev->of_node;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->phy = devm_phy_create(dev, np, &phy_axg_pcie_ops);
|
||||
if (IS_ERR(priv->phy)) {
|
||||
ret = PTR_ERR(priv->phy);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to create PHY\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
@ -162,6 +153,11 @@ static int phy_axg_pcie_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(priv->analog))
|
||||
return PTR_ERR(priv->analog);
|
||||
|
||||
priv->phy = devm_phy_create(dev, np, &phy_axg_pcie_ops);
|
||||
if (IS_ERR(priv->phy))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->phy),
|
||||
"failed to create PHY\n");
|
||||
|
||||
phy_set_drvdata(priv->phy, priv);
|
||||
dev_set_drvdata(dev, priv);
|
||||
pphy = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
|
|
|
@ -339,13 +339,9 @@ static int phy_meson_g12a_usb2_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
|
||||
phy = devm_phy_create(dev, NULL, &phy_meson_g12a_usb2_ops);
|
||||
if (IS_ERR(phy)) {
|
||||
ret = PTR_ERR(phy);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to create PHY\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(phy))
|
||||
return dev_err_probe(dev, PTR_ERR(phy),
|
||||
"failed to create PHY\n");
|
||||
|
||||
phy_set_bus_width(phy, 8);
|
||||
phy_set_drvdata(phy, priv);
|
||||
|
|
|
@ -237,7 +237,6 @@ static int phy_meson_gxl_usb2_probe(struct platform_device *pdev)
|
|||
struct phy_meson_gxl_usb2_priv *priv;
|
||||
struct phy *phy;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
|
@ -266,13 +265,9 @@ static int phy_meson_gxl_usb2_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(priv->reset);
|
||||
|
||||
phy = devm_phy_create(dev, NULL, &phy_meson_gxl_usb2_ops);
|
||||
if (IS_ERR(phy)) {
|
||||
ret = PTR_ERR(phy);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to create PHY\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(phy))
|
||||
return dev_err_probe(dev, PTR_ERR(phy),
|
||||
"failed to create PHY\n");
|
||||
|
||||
phy_set_drvdata(phy, priv);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -39,9 +40,7 @@
|
|||
#define REG_CTRL_TX_BITSTUFF_ENN BIT(18)
|
||||
#define REG_CTRL_COMMON_ON BIT(19)
|
||||
#define REG_CTRL_REF_CLK_SEL_MASK GENMASK(21, 20)
|
||||
#define REG_CTRL_REF_CLK_SEL_SHIFT 20
|
||||
#define REG_CTRL_FSEL_MASK GENMASK(24, 22)
|
||||
#define REG_CTRL_FSEL_SHIFT 22
|
||||
#define REG_CTRL_PORT_RESET BIT(25)
|
||||
#define REG_CTRL_THREAD_ID_MASK GENMASK(31, 26)
|
||||
|
||||
|
@ -166,33 +165,29 @@ static int phy_meson8b_usb2_power_on(struct phy *phy)
|
|||
return ret;
|
||||
}
|
||||
|
||||
regmap_update_bits(priv->regmap, REG_CONFIG, REG_CONFIG_CLK_32k_ALTSEL,
|
||||
REG_CONFIG_CLK_32k_ALTSEL);
|
||||
regmap_set_bits(priv->regmap, REG_CONFIG, REG_CONFIG_CLK_32k_ALTSEL);
|
||||
|
||||
regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_REF_CLK_SEL_MASK,
|
||||
0x2 << REG_CTRL_REF_CLK_SEL_SHIFT);
|
||||
FIELD_PREP(REG_CTRL_REF_CLK_SEL_MASK, 0x2));
|
||||
|
||||
regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_FSEL_MASK,
|
||||
0x5 << REG_CTRL_FSEL_SHIFT);
|
||||
FIELD_PREP(REG_CTRL_FSEL_MASK, 0x5));
|
||||
|
||||
/* reset the PHY */
|
||||
regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET,
|
||||
REG_CTRL_POWER_ON_RESET);
|
||||
regmap_set_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET);
|
||||
udelay(RESET_COMPLETE_TIME);
|
||||
regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET, 0);
|
||||
regmap_clear_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET);
|
||||
udelay(RESET_COMPLETE_TIME);
|
||||
|
||||
regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_SOF_TOGGLE_OUT,
|
||||
REG_CTRL_SOF_TOGGLE_OUT);
|
||||
regmap_set_bits(priv->regmap, REG_CTRL, REG_CTRL_SOF_TOGGLE_OUT);
|
||||
|
||||
if (priv->dr_mode == USB_DR_MODE_HOST) {
|
||||
regmap_update_bits(priv->regmap, REG_DBG_UART,
|
||||
REG_DBG_UART_SET_IDDQ, 0);
|
||||
regmap_clear_bits(priv->regmap, REG_DBG_UART,
|
||||
REG_DBG_UART_SET_IDDQ);
|
||||
|
||||
if (priv->match->host_enable_aca) {
|
||||
regmap_update_bits(priv->regmap, REG_ADP_BC,
|
||||
REG_ADP_BC_ACA_ENABLE,
|
||||
REG_ADP_BC_ACA_ENABLE);
|
||||
regmap_set_bits(priv->regmap, REG_ADP_BC,
|
||||
REG_ADP_BC_ACA_ENABLE);
|
||||
|
||||
udelay(ACA_ENABLE_COMPLETE_TIME);
|
||||
|
||||
|
@ -215,17 +210,15 @@ static int phy_meson8b_usb2_power_off(struct phy *phy)
|
|||
struct phy_meson8b_usb2_priv *priv = phy_get_drvdata(phy);
|
||||
|
||||
if (priv->dr_mode == USB_DR_MODE_HOST)
|
||||
regmap_update_bits(priv->regmap, REG_DBG_UART,
|
||||
REG_DBG_UART_SET_IDDQ,
|
||||
REG_DBG_UART_SET_IDDQ);
|
||||
regmap_set_bits(priv->regmap, REG_DBG_UART,
|
||||
REG_DBG_UART_SET_IDDQ);
|
||||
|
||||
clk_disable_unprepare(priv->clk_usb);
|
||||
clk_disable_unprepare(priv->clk_usb_general);
|
||||
reset_control_rearm(priv->reset);
|
||||
|
||||
/* power off the PHY by putting it into reset mode */
|
||||
regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET,
|
||||
REG_CTRL_POWER_ON_RESET);
|
||||
regmap_set_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
#define USB_CTRL_SETUP_tca_drv_sel_MASK BIT(24)
|
||||
#define USB_CTRL_SETUP_STRAP_IPP_SEL_MASK BIT(25)
|
||||
#define USB_CTRL_USB_PM 0x04
|
||||
#define USB_CTRL_USB_PM_REF_S2_CLK_SWITCH_EN_MASK BIT(1)
|
||||
#define USB_CTRL_USB_PM_UTMI_S2_CLK_SWITCH_EN_MASK BIT(2)
|
||||
#define USB_CTRL_USB_PM_XHC_S2_CLK_SWITCH_EN_MASK BIT(3)
|
||||
#define USB_CTRL_USB_PM_XHC_PME_EN_MASK BIT(4)
|
||||
#define USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK BIT(22)
|
||||
|
@ -61,6 +63,13 @@
|
|||
#define USB_CTRL_CTLR_CSHCR_ctl_pme_en_MASK BIT(18)
|
||||
#define USB_CTRL_P0_U2PHY_CFG1 0x68
|
||||
#define USB_CTRL_P0_U2PHY_CFG1_COMMONONN_MASK BIT(10)
|
||||
#define USB_CTRL_P0_U2PHY_CFG2 0x6c
|
||||
#define USB_CTRL_P0_U2PHY_CFG2_TXVREFTUNE0_MASK GENMASK(20, 17)
|
||||
#define USB_CTRL_P0_U2PHY_CFG2_TXVREFTUNE0_SHIFT 17
|
||||
#define USB_CTRL_P0_U2PHY_CFG2_TXRESTUNE0_MASK GENMASK(24, 23)
|
||||
#define USB_CTRL_P0_U2PHY_CFG2_TXRESTUNE0_SHIFT 23
|
||||
#define USB_CTRL_P0_U2PHY_CFG2_TXPREEMPAMPTUNE0_MASK GENMASK(26, 25)
|
||||
#define USB_CTRL_P0_U2PHY_CFG2_TXPREEMPAMPTUNE0_SHIFT 25
|
||||
|
||||
/* Register definitions for the USB_PHY block in 7211b0 */
|
||||
#define USB_PHY_PLL_CTL 0x00
|
||||
|
@ -369,6 +378,42 @@ static void usb_uninit_common_7216(struct brcm_usb_init_params *params)
|
|||
}
|
||||
}
|
||||
|
||||
static void usb_init_common_74110(struct brcm_usb_init_params *params)
|
||||
{
|
||||
void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
|
||||
u32 reg;
|
||||
|
||||
reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_PM));
|
||||
reg &= ~(USB_CTRL_MASK(USB_PM, REF_S2_CLK_SWITCH_EN) |
|
||||
USB_CTRL_MASK(USB_PM, UTMI_S2_CLK_SWITCH_EN));
|
||||
brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_PM));
|
||||
|
||||
usb_init_common_7216(params);
|
||||
|
||||
reg = brcm_usb_readl(USB_CTRL_REG(ctrl, P0_U2PHY_CFG2));
|
||||
reg &= ~(USB_CTRL_P0_U2PHY_CFG2_TXVREFTUNE0_MASK |
|
||||
USB_CTRL_P0_U2PHY_CFG2_TXRESTUNE0_MASK |
|
||||
USB_CTRL_P0_U2PHY_CFG2_TXPREEMPAMPTUNE0_MASK);
|
||||
reg |= (0x6 << USB_CTRL_P0_U2PHY_CFG2_TXVREFTUNE0_SHIFT) |
|
||||
(0x3 << USB_CTRL_P0_U2PHY_CFG2_TXRESTUNE0_SHIFT) |
|
||||
(0x2 << USB_CTRL_P0_U2PHY_CFG2_TXPREEMPAMPTUNE0_SHIFT);
|
||||
brcm_usb_writel(reg, USB_CTRL_REG(ctrl, P0_U2PHY_CFG2));
|
||||
}
|
||||
|
||||
static void usb_uninit_common_74110(struct brcm_usb_init_params *params)
|
||||
{
|
||||
void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
|
||||
u32 reg;
|
||||
|
||||
if (params->wake_enabled) {
|
||||
reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_PM));
|
||||
reg |= (USB_CTRL_MASK(USB_PM, REF_S2_CLK_SWITCH_EN) |
|
||||
USB_CTRL_MASK(USB_PM, UTMI_S2_CLK_SWITCH_EN));
|
||||
brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_PM));
|
||||
}
|
||||
usb_uninit_common_7216(params);
|
||||
}
|
||||
|
||||
static void usb_uninit_common_7211b0(struct brcm_usb_init_params *params)
|
||||
{
|
||||
void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
|
||||
|
@ -426,6 +471,16 @@ static void usb_set_dual_select(struct brcm_usb_init_params *params)
|
|||
brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
|
||||
}
|
||||
|
||||
static const struct brcm_usb_init_ops bcm74110_ops = {
|
||||
.init_ipp = usb_init_ipp,
|
||||
.init_common = usb_init_common_74110,
|
||||
.init_xhci = usb_init_xhci,
|
||||
.uninit_common = usb_uninit_common_74110,
|
||||
.uninit_xhci = usb_uninit_xhci,
|
||||
.get_dual_select = usb_get_dual_select,
|
||||
.set_dual_select = usb_set_dual_select,
|
||||
};
|
||||
|
||||
static const struct brcm_usb_init_ops bcm7216_ops = {
|
||||
.init_ipp = usb_init_ipp,
|
||||
.init_common = usb_init_common_7216,
|
||||
|
@ -446,6 +501,12 @@ static const struct brcm_usb_init_ops bcm7211b0_ops = {
|
|||
.set_dual_select = usb_set_dual_select,
|
||||
};
|
||||
|
||||
void brcm_usb_dvr_init_74110(struct brcm_usb_init_params *params)
|
||||
{
|
||||
params->family_name = "74110";
|
||||
params->ops = &bcm74110_ops;
|
||||
}
|
||||
|
||||
void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params)
|
||||
{
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ struct brcm_usb_init_params {
|
|||
bool wake_enabled;
|
||||
};
|
||||
|
||||
void brcm_usb_dvr_init_74110(struct brcm_usb_init_params *params);
|
||||
void brcm_usb_dvr_init_4908(struct brcm_usb_init_params *params);
|
||||
void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params);
|
||||
void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params);
|
||||
|
|
|
@ -283,6 +283,16 @@ static const struct attribute_group brcm_usb_phy_group = {
|
|||
.attrs = brcm_usb_phy_attrs,
|
||||
};
|
||||
|
||||
static const struct match_chip_info chip_info_74110 = {
|
||||
.init_func = &brcm_usb_dvr_init_74110,
|
||||
.required_regs = {
|
||||
BRCM_REGS_CTRL,
|
||||
BRCM_REGS_XHCI_EC,
|
||||
BRCM_REGS_XHCI_GBL,
|
||||
-1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct match_chip_info chip_info_4908 = {
|
||||
.init_func = &brcm_usb_dvr_init_4908,
|
||||
.required_regs = {
|
||||
|
@ -325,6 +335,10 @@ static const struct match_chip_info chip_info_7445 = {
|
|||
};
|
||||
|
||||
static const struct of_device_id brcm_usb_dt_ids[] = {
|
||||
{
|
||||
.compatible = "brcm,bcm74110-usb-phy",
|
||||
.data = &chip_info_74110,
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,bcm4908-usb-phy",
|
||||
.data = &chip_info_4908,
|
||||
|
|
|
@ -238,24 +238,21 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev)
|
|||
imx8_phy->clkreq_unused = false;
|
||||
|
||||
imx8_phy->clk = devm_clk_get(dev, "ref");
|
||||
if (IS_ERR(imx8_phy->clk)) {
|
||||
dev_err(dev, "failed to get imx pcie phy clock\n");
|
||||
return PTR_ERR(imx8_phy->clk);
|
||||
}
|
||||
if (IS_ERR(imx8_phy->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(imx8_phy->clk),
|
||||
"failed to get imx pcie phy clock\n");
|
||||
|
||||
/* Grab GPR config register range */
|
||||
imx8_phy->iomuxc_gpr =
|
||||
syscon_regmap_lookup_by_compatible(imx8_phy->drvdata->gpr);
|
||||
if (IS_ERR(imx8_phy->iomuxc_gpr)) {
|
||||
dev_err(dev, "unable to find iomuxc registers\n");
|
||||
return PTR_ERR(imx8_phy->iomuxc_gpr);
|
||||
}
|
||||
if (IS_ERR(imx8_phy->iomuxc_gpr))
|
||||
return dev_err_probe(dev, PTR_ERR(imx8_phy->iomuxc_gpr),
|
||||
"unable to find iomuxc registers\n");
|
||||
|
||||
imx8_phy->reset = devm_reset_control_get_exclusive(dev, "pciephy");
|
||||
if (IS_ERR(imx8_phy->reset)) {
|
||||
dev_err(dev, "Failed to get PCIEPHY reset control\n");
|
||||
return PTR_ERR(imx8_phy->reset);
|
||||
}
|
||||
if (IS_ERR(imx8_phy->reset))
|
||||
return dev_err_probe(dev, PTR_ERR(imx8_phy->reset),
|
||||
"Failed to get PCIEPHY reset control\n");
|
||||
|
||||
if (imx8_phy->drvdata->variant == IMX8MP) {
|
||||
imx8_phy->perst =
|
||||
|
|
|
@ -293,6 +293,28 @@ static u32 phy_tx_vref_tune_from_property(u32 percent)
|
|||
return DIV_ROUND_CLOSEST(percent - 94U, 2);
|
||||
}
|
||||
|
||||
static u32 imx95_phy_tx_vref_tune_from_property(u32 percent)
|
||||
{
|
||||
percent = clamp(percent, 90U, 108U);
|
||||
|
||||
switch (percent) {
|
||||
case 90 ... 91:
|
||||
percent = 0;
|
||||
break;
|
||||
case 92 ... 96:
|
||||
percent -= 91;
|
||||
break;
|
||||
case 97 ... 104:
|
||||
percent -= 92;
|
||||
break;
|
||||
case 105 ... 108:
|
||||
percent -= 93;
|
||||
break;
|
||||
}
|
||||
|
||||
return percent;
|
||||
}
|
||||
|
||||
static u32 phy_tx_rise_tune_from_property(u32 percent)
|
||||
{
|
||||
switch (percent) {
|
||||
|
@ -307,6 +329,22 @@ static u32 phy_tx_rise_tune_from_property(u32 percent)
|
|||
}
|
||||
}
|
||||
|
||||
static u32 imx95_phy_tx_rise_tune_from_property(u32 percent)
|
||||
{
|
||||
percent = clamp(percent, 90U, 120U);
|
||||
|
||||
switch (percent) {
|
||||
case 90 ... 99:
|
||||
return 3;
|
||||
case 101 ... 115:
|
||||
return 1;
|
||||
case 116 ... 120:
|
||||
return 0;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 phy_tx_preemp_amp_tune_from_property(u32 microamp)
|
||||
{
|
||||
microamp = min(microamp, 1800U);
|
||||
|
@ -317,12 +355,12 @@ static u32 phy_tx_preemp_amp_tune_from_property(u32 microamp)
|
|||
static u32 phy_tx_vboost_level_from_property(u32 microvolt)
|
||||
{
|
||||
switch (microvolt) {
|
||||
case 0 ... 960:
|
||||
return 0;
|
||||
case 961 ... 1160:
|
||||
return 2;
|
||||
default:
|
||||
case 1156:
|
||||
return 5;
|
||||
case 844:
|
||||
return 3;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,6 +390,29 @@ static u32 phy_comp_dis_tune_from_property(u32 percent)
|
|||
return 7;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 imx95_phy_comp_dis_tune_from_property(u32 percent)
|
||||
{
|
||||
percent = clamp(percent, 94, 104);
|
||||
|
||||
switch (percent) {
|
||||
case 94 ... 95:
|
||||
percent = 0;
|
||||
break;
|
||||
case 96 ... 98:
|
||||
percent -= 95;
|
||||
break;
|
||||
case 99 ... 102:
|
||||
percent -= 96;
|
||||
break;
|
||||
case 103 ... 104:
|
||||
percent -= 97;
|
||||
break;
|
||||
}
|
||||
|
||||
return percent;
|
||||
}
|
||||
|
||||
static u32 phy_pcs_tx_swing_full_from_property(u32 percent)
|
||||
{
|
||||
percent = min(percent, 100U);
|
||||
|
@ -362,10 +423,17 @@ static u32 phy_pcs_tx_swing_full_from_property(u32 percent)
|
|||
static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy)
|
||||
{
|
||||
struct device *dev = imx_phy->phy->dev.parent;
|
||||
bool is_imx95 = false;
|
||||
|
||||
if (device_is_compatible(dev, "fsl,imx95-usb-phy"))
|
||||
is_imx95 = true;
|
||||
|
||||
if (device_property_read_u32(dev, "fsl,phy-tx-vref-tune-percent",
|
||||
&imx_phy->tx_vref_tune))
|
||||
imx_phy->tx_vref_tune = PHY_TUNE_DEFAULT;
|
||||
else if (is_imx95)
|
||||
imx_phy->tx_vref_tune =
|
||||
imx95_phy_tx_vref_tune_from_property(imx_phy->tx_vref_tune);
|
||||
else
|
||||
imx_phy->tx_vref_tune =
|
||||
phy_tx_vref_tune_from_property(imx_phy->tx_vref_tune);
|
||||
|
@ -373,6 +441,9 @@ static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy)
|
|||
if (device_property_read_u32(dev, "fsl,phy-tx-rise-tune-percent",
|
||||
&imx_phy->tx_rise_tune))
|
||||
imx_phy->tx_rise_tune = PHY_TUNE_DEFAULT;
|
||||
else if (is_imx95)
|
||||
imx_phy->tx_rise_tune =
|
||||
imx95_phy_tx_rise_tune_from_property(imx_phy->tx_rise_tune);
|
||||
else
|
||||
imx_phy->tx_rise_tune =
|
||||
phy_tx_rise_tune_from_property(imx_phy->tx_rise_tune);
|
||||
|
@ -394,6 +465,9 @@ static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy)
|
|||
if (device_property_read_u32(dev, "fsl,phy-comp-dis-tune-percent",
|
||||
&imx_phy->comp_dis_tune))
|
||||
imx_phy->comp_dis_tune = PHY_TUNE_DEFAULT;
|
||||
else if (is_imx95)
|
||||
imx_phy->comp_dis_tune =
|
||||
imx95_phy_comp_dis_tune_from_property(imx_phy->comp_dis_tune);
|
||||
else
|
||||
imx_phy->comp_dis_tune =
|
||||
phy_comp_dis_tune_from_property(imx_phy->comp_dis_tune);
|
||||
|
|
|
@ -456,6 +456,8 @@ static int fsl_samsung_hdmi_phy_configure(struct fsl_samsung_hdmi_phy *phy,
|
|||
int i, ret;
|
||||
u8 val;
|
||||
|
||||
phy->cur_cfg = cfg;
|
||||
|
||||
/* HDMI PHY init */
|
||||
writeb(REG33_FIX_DA, phy->regs + PHY_REG(33));
|
||||
|
||||
|
@ -508,7 +510,14 @@ static const struct phy_config *fsl_samsung_hdmi_phy_lookup_rate(unsigned long r
|
|||
if (phy_pll_cfg[i].pixclk <= rate)
|
||||
break;
|
||||
|
||||
return &phy_pll_cfg[i];
|
||||
/* If there is an exact match, or the array has been searched, return the value*/
|
||||
if (phy_pll_cfg[i].pixclk == rate || i + 1 > ARRAY_SIZE(phy_pll_cfg) - 1)
|
||||
return &phy_pll_cfg[i];
|
||||
|
||||
/* See if the next entry is closer to nominal than this one */
|
||||
return (abs((long) rate - (long) phy_pll_cfg[i].pixclk) <
|
||||
abs((long) rate - (long) phy_pll_cfg[i+1].pixclk) ?
|
||||
&phy_pll_cfg[i] : &phy_pll_cfg[i+1]);
|
||||
}
|
||||
|
||||
static void fsl_samsung_hdmi_calculate_phy(struct phy_config *cal_phy, unsigned long rate,
|
||||
|
@ -521,18 +530,9 @@ static void fsl_samsung_hdmi_calculate_phy(struct phy_config *cal_phy, unsigned
|
|||
/* pll_div_regs 3-6 are fixed and pre-defined already */
|
||||
}
|
||||
|
||||
static u32 fsl_samsung_hdmi_phy_get_closest_rate(unsigned long rate,
|
||||
u32 int_div_clk, u32 frac_div_clk)
|
||||
{
|
||||
/* Calculate the absolute value of the differences and return whichever is closest */
|
||||
if (abs((long)rate - (long)int_div_clk) < abs((long)(rate - (long)frac_div_clk)))
|
||||
return int_div_clk;
|
||||
|
||||
return frac_div_clk;
|
||||
}
|
||||
|
||||
static long phy_clk_round_rate(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long *parent_rate)
|
||||
static
|
||||
const struct phy_config *fsl_samsung_hdmi_phy_find_settings(struct fsl_samsung_hdmi_phy *phy,
|
||||
unsigned long rate)
|
||||
{
|
||||
const struct phy_config *fract_div_phy;
|
||||
u32 int_div_clk;
|
||||
|
@ -541,83 +541,66 @@ static long phy_clk_round_rate(struct clk_hw *hw,
|
|||
|
||||
/* If the clock is out of range return error instead of searching */
|
||||
if (rate > 297000000 || rate < 22250000)
|
||||
return -EINVAL;
|
||||
return NULL;
|
||||
|
||||
/* Search the fractional divider lookup table */
|
||||
fract_div_phy = fsl_samsung_hdmi_phy_lookup_rate(rate);
|
||||
if (fract_div_phy->pixclk == rate) {
|
||||
dev_dbg(phy->dev, "fractional divider match = %u\n", fract_div_phy->pixclk);
|
||||
return fract_div_phy;
|
||||
}
|
||||
|
||||
/* If the rate is an exact match, return that value */
|
||||
if (rate == fract_div_phy->pixclk)
|
||||
return fract_div_phy->pixclk;
|
||||
|
||||
/* If the exact match isn't found, calculate the integer divider */
|
||||
/* Calculate the integer divider */
|
||||
int_div_clk = fsl_samsung_hdmi_phy_find_pms(rate, &p, &m, &s);
|
||||
fsl_samsung_hdmi_calculate_phy(&calculated_phy_pll_cfg, int_div_clk, p, m, s);
|
||||
if (int_div_clk == rate) {
|
||||
dev_dbg(phy->dev, "integer divider match = %u\n", calculated_phy_pll_cfg.pixclk);
|
||||
return &calculated_phy_pll_cfg;
|
||||
}
|
||||
|
||||
/* If the int_div_clk rate is an exact match, return that value */
|
||||
if (int_div_clk == rate)
|
||||
return int_div_clk;
|
||||
/* Calculate the absolute value of the differences and return whichever is closest */
|
||||
if (abs((long)rate - (long)int_div_clk) <
|
||||
abs((long)rate - (long)fract_div_phy->pixclk)) {
|
||||
dev_dbg(phy->dev, "integer divider = %u\n", calculated_phy_pll_cfg.pixclk);
|
||||
return &calculated_phy_pll_cfg;
|
||||
}
|
||||
|
||||
/* If neither rate is an exact match, use the value from the LUT */
|
||||
return fract_div_phy->pixclk;
|
||||
dev_dbg(phy->dev, "fractional divider = %u\n", phy->cur_cfg->pixclk);
|
||||
|
||||
return fract_div_phy;
|
||||
}
|
||||
|
||||
static int phy_use_fract_div(struct fsl_samsung_hdmi_phy *phy, const struct phy_config *fract_div_phy)
|
||||
static long fsl_samsung_hdmi_phy_clk_round_rate(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long *parent_rate)
|
||||
{
|
||||
phy->cur_cfg = fract_div_phy;
|
||||
dev_dbg(phy->dev, "fsl_samsung_hdmi_phy: using fractional divider rate = %u\n",
|
||||
phy->cur_cfg->pixclk);
|
||||
return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg);
|
||||
struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw);
|
||||
const struct phy_config *target_settings = fsl_samsung_hdmi_phy_find_settings(phy, rate);
|
||||
|
||||
if (target_settings == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(phy->dev, "round_rate, closest rate = %u\n", target_settings->pixclk);
|
||||
return target_settings->pixclk;
|
||||
}
|
||||
|
||||
static int phy_use_integer_div(struct fsl_samsung_hdmi_phy *phy,
|
||||
const struct phy_config *int_div_clk)
|
||||
{
|
||||
phy->cur_cfg = &calculated_phy_pll_cfg;
|
||||
dev_dbg(phy->dev, "fsl_samsung_hdmi_phy: integer divider rate = %u\n",
|
||||
phy->cur_cfg->pixclk);
|
||||
return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg);
|
||||
}
|
||||
|
||||
static int phy_clk_set_rate(struct clk_hw *hw,
|
||||
static int fsl_samsung_hdmi_phy_clk_set_rate(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw);
|
||||
const struct phy_config *fract_div_phy;
|
||||
u32 int_div_clk;
|
||||
u16 m;
|
||||
u8 p, s;
|
||||
const struct phy_config *target_settings = fsl_samsung_hdmi_phy_find_settings(phy, rate);
|
||||
|
||||
/* Search the fractional divider lookup table */
|
||||
fract_div_phy = fsl_samsung_hdmi_phy_lookup_rate(rate);
|
||||
if (target_settings == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/* If the rate is an exact match, use that value */
|
||||
if (fract_div_phy->pixclk == rate)
|
||||
return phy_use_fract_div(phy, fract_div_phy);
|
||||
dev_dbg(phy->dev, "set_rate, closest rate = %u\n", target_settings->pixclk);
|
||||
|
||||
/*
|
||||
* If the rate from the fractional divider is not exact, check the integer divider,
|
||||
* and use it if that value is an exact match.
|
||||
*/
|
||||
int_div_clk = fsl_samsung_hdmi_phy_find_pms(rate, &p, &m, &s);
|
||||
fsl_samsung_hdmi_calculate_phy(&calculated_phy_pll_cfg, int_div_clk, p, m, s);
|
||||
if (int_div_clk == rate)
|
||||
return phy_use_integer_div(phy, &calculated_phy_pll_cfg);
|
||||
|
||||
/*
|
||||
* Compare the difference between the integer clock and the fractional clock against
|
||||
* the desired clock and which whichever is closest.
|
||||
*/
|
||||
if (fsl_samsung_hdmi_phy_get_closest_rate(rate, int_div_clk,
|
||||
fract_div_phy->pixclk) == fract_div_phy->pixclk)
|
||||
return phy_use_fract_div(phy, fract_div_phy);
|
||||
else
|
||||
return phy_use_integer_div(phy, &calculated_phy_pll_cfg);
|
||||
return fsl_samsung_hdmi_phy_configure(phy, target_settings);
|
||||
}
|
||||
|
||||
static const struct clk_ops phy_clk_ops = {
|
||||
.recalc_rate = phy_clk_recalc_rate,
|
||||
.round_rate = phy_clk_round_rate,
|
||||
.set_rate = phy_clk_set_rate,
|
||||
.round_rate = fsl_samsung_hdmi_phy_clk_round_rate,
|
||||
.set_rate = fsl_samsung_hdmi_phy_clk_set_rate,
|
||||
};
|
||||
|
||||
static int phy_clk_register(struct fsl_samsung_hdmi_phy *phy)
|
||||
|
|
|
@ -29,7 +29,7 @@ config PHY_MVEBU_A3700_COMPHY
|
|||
depends on ARCH_MVEBU || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on HAVE_ARM_SMCCC
|
||||
default y
|
||||
default ARCH_MVEBU
|
||||
select GENERIC_PHY
|
||||
help
|
||||
This driver allows to control the comphy, a hardware block providing
|
||||
|
@ -40,7 +40,7 @@ config PHY_MVEBU_A3700_UTMI
|
|||
tristate "Marvell A3700 UTMI driver"
|
||||
depends on ARCH_MVEBU || COMPILE_TEST
|
||||
depends on OF
|
||||
default y
|
||||
default ARCH_MVEBU
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support Marvell A3700 UTMI PHY driver.
|
||||
|
|
|
@ -11,10 +11,12 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "phy-mtk-io.h"
|
||||
|
||||
|
@ -81,12 +83,22 @@
|
|||
#define XSP_SR_COEF_DIVISOR 1000
|
||||
#define XSP_FM_DET_CYCLE_CNT 1024
|
||||
|
||||
/* PHY switch between pcie/usb3/sgmii */
|
||||
#define USB_PHY_SWITCH_CTRL 0x0
|
||||
#define RG_PHY_SW_TYPE GENMASK(3, 0)
|
||||
#define RG_PHY_SW_PCIE 0x0
|
||||
#define RG_PHY_SW_USB3 0x1
|
||||
#define RG_PHY_SW_SGMII 0x2
|
||||
|
||||
struct xsphy_instance {
|
||||
struct phy *phy;
|
||||
void __iomem *port_base;
|
||||
struct clk *ref_clk; /* reference clock of anolog phy */
|
||||
u32 index;
|
||||
u32 type;
|
||||
struct regmap *type_sw;
|
||||
u32 type_sw_reg;
|
||||
u32 type_sw_index;
|
||||
/* only for HQA test */
|
||||
int efuse_intr;
|
||||
int efuse_tx_imp;
|
||||
|
@ -259,6 +271,10 @@ static void phy_parse_property(struct mtk_xsphy *xsphy,
|
|||
inst->efuse_intr, inst->efuse_tx_imp,
|
||||
inst->efuse_rx_imp);
|
||||
break;
|
||||
case PHY_TYPE_PCIE:
|
||||
case PHY_TYPE_SGMII:
|
||||
/* nothing to do */
|
||||
break;
|
||||
default:
|
||||
dev_err(xsphy->dev, "incompatible phy type\n");
|
||||
return;
|
||||
|
@ -305,6 +321,62 @@ static void u3_phy_props_set(struct mtk_xsphy *xsphy,
|
|||
RG_XTP_LN0_RX_IMPSEL, inst->efuse_rx_imp);
|
||||
}
|
||||
|
||||
/* type switch for usb3/pcie/sgmii */
|
||||
static int phy_type_syscon_get(struct xsphy_instance *instance,
|
||||
struct device_node *dn)
|
||||
{
|
||||
struct of_phandle_args args;
|
||||
int ret;
|
||||
|
||||
/* type switch function is optional */
|
||||
if (!of_property_present(dn, "mediatek,syscon-type"))
|
||||
return 0;
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type",
|
||||
2, 0, &args);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
instance->type_sw_reg = args.args[0];
|
||||
instance->type_sw_index = args.args[1] & 0x3; /* <=3 */
|
||||
instance->type_sw = syscon_node_to_regmap(args.np);
|
||||
of_node_put(args.np);
|
||||
dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n",
|
||||
instance->type_sw_reg, instance->type_sw_index);
|
||||
|
||||
return PTR_ERR_OR_ZERO(instance->type_sw);
|
||||
}
|
||||
|
||||
static int phy_type_set(struct xsphy_instance *instance)
|
||||
{
|
||||
int type;
|
||||
u32 offset;
|
||||
|
||||
if (!instance->type_sw)
|
||||
return 0;
|
||||
|
||||
switch (instance->type) {
|
||||
case PHY_TYPE_USB3:
|
||||
type = RG_PHY_SW_USB3;
|
||||
break;
|
||||
case PHY_TYPE_PCIE:
|
||||
type = RG_PHY_SW_PCIE;
|
||||
break;
|
||||
case PHY_TYPE_SGMII:
|
||||
type = RG_PHY_SW_SGMII;
|
||||
break;
|
||||
case PHY_TYPE_USB2:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset = instance->type_sw_index * BITS_PER_BYTE;
|
||||
regmap_update_bits(instance->type_sw, instance->type_sw_reg,
|
||||
RG_PHY_SW_TYPE << offset, type << offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_phy_init(struct phy *phy)
|
||||
{
|
||||
struct xsphy_instance *inst = phy_get_drvdata(phy);
|
||||
|
@ -325,6 +397,10 @@ static int mtk_phy_init(struct phy *phy)
|
|||
case PHY_TYPE_USB3:
|
||||
u3_phy_props_set(xsphy, inst);
|
||||
break;
|
||||
case PHY_TYPE_PCIE:
|
||||
case PHY_TYPE_SGMII:
|
||||
/* nothing to do, only used to set type */
|
||||
break;
|
||||
default:
|
||||
dev_err(xsphy->dev, "incompatible phy type\n");
|
||||
clk_disable_unprepare(inst->ref_clk);
|
||||
|
@ -403,12 +479,15 @@ static struct phy *mtk_phy_xlate(struct device *dev,
|
|||
|
||||
inst->type = args->args[0];
|
||||
if (!(inst->type == PHY_TYPE_USB2 ||
|
||||
inst->type == PHY_TYPE_USB3)) {
|
||||
inst->type == PHY_TYPE_USB3 ||
|
||||
inst->type == PHY_TYPE_PCIE ||
|
||||
inst->type == PHY_TYPE_SGMII)) {
|
||||
dev_err(dev, "unsupported phy type: %d\n", inst->type);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
phy_parse_property(xsphy, inst);
|
||||
phy_type_set(inst);
|
||||
|
||||
return inst->phy;
|
||||
}
|
||||
|
@ -510,6 +589,10 @@ static int mtk_xsphy_probe(struct platform_device *pdev)
|
|||
dev_err(dev, "failed to get ref_clk(id-%d)\n", port);
|
||||
return PTR_ERR(inst->ref_clk);
|
||||
}
|
||||
|
||||
retval = phy_type_syscon_get(inst, child_np);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);
|
||||
|
|
627
drivers/phy/phy-snps-eusb2.c
Normal file
627
drivers/phy/phy-snps-eusb2.c
Normal file
|
@ -0,0 +1,627 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2023, Linaro Limited
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#define EXYNOS_USB_PHY_HS_PHY_CTRL_RST (0x0)
|
||||
#define USB_PHY_RST_MASK GENMASK(1, 0)
|
||||
#define UTMI_PORT_RST_MASK GENMASK(5, 4)
|
||||
|
||||
#define EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON (0x4)
|
||||
#define RPTR_MODE BIT(10)
|
||||
#define FSEL_20_MHZ_VAL (0x1)
|
||||
#define FSEL_24_MHZ_VAL (0x2)
|
||||
#define FSEL_26_MHZ_VAL (0x3)
|
||||
#define FSEL_48_MHZ_VAL (0x2)
|
||||
|
||||
#define EXYNOS_USB_PHY_CFG_PLLCFG0 (0x8)
|
||||
#define PHY_CFG_PLL_FB_DIV_19_8_MASK GENMASK(19, 8)
|
||||
#define DIV_19_8_19_2_MHZ_VAL (0x170)
|
||||
#define DIV_19_8_20_MHZ_VAL (0x160)
|
||||
#define DIV_19_8_24_MHZ_VAL (0x120)
|
||||
#define DIV_19_8_26_MHZ_VAL (0x107)
|
||||
#define DIV_19_8_48_MHZ_VAL (0x120)
|
||||
|
||||
#define EXYNOS_USB_PHY_CFG_PLLCFG1 (0xc)
|
||||
#define EXYNOS_PHY_CFG_PLL_FB_DIV_11_8_MASK GENMASK(11, 8)
|
||||
#define EXYNOS_DIV_11_8_19_2_MHZ_VAL (0x0)
|
||||
#define EXYNOS_DIV_11_8_20_MHZ_VAL (0x0)
|
||||
#define EXYNOS_DIV_11_8_24_MHZ_VAL (0x0)
|
||||
#define EXYNOS_DIV_11_8_26_MHZ_VAL (0x0)
|
||||
#define EXYNOS_DIV_11_8_48_MHZ_VAL (0x1)
|
||||
|
||||
#define EXYNOS_PHY_CFG_TX (0x14)
|
||||
#define EXYNOS_PHY_CFG_TX_FSLS_VREF_TUNE_MASK GENMASK(2, 1)
|
||||
|
||||
#define EXYNOS_USB_PHY_UTMI_TESTSE (0x20)
|
||||
#define TEST_IDDQ BIT(6)
|
||||
|
||||
#define QCOM_USB_PHY_UTMI_CTRL0 (0x3c)
|
||||
#define SLEEPM BIT(0)
|
||||
#define OPMODE_MASK GENMASK(4, 3)
|
||||
#define OPMODE_NONDRIVING BIT(3)
|
||||
|
||||
#define QCOM_USB_PHY_UTMI_CTRL5 (0x50)
|
||||
#define POR BIT(1)
|
||||
|
||||
#define QCOM_USB_PHY_HS_PHY_CTRL_COMMON0 (0x54)
|
||||
#define PHY_ENABLE BIT(0)
|
||||
#define SIDDQ_SEL BIT(1)
|
||||
#define SIDDQ BIT(2)
|
||||
#define RETENABLEN BIT(3)
|
||||
#define FSEL_MASK GENMASK(6, 4)
|
||||
#define FSEL_19_2_MHZ_VAL (0x0)
|
||||
#define FSEL_38_4_MHZ_VAL (0x4)
|
||||
|
||||
#define QCOM_USB_PHY_CFG_CTRL_1 (0x58)
|
||||
#define PHY_CFG_PLL_CPBIAS_CNTRL_MASK GENMASK(7, 1)
|
||||
|
||||
#define QCOM_USB_PHY_CFG_CTRL_2 (0x5c)
|
||||
#define PHY_CFG_PLL_FB_DIV_7_0_MASK GENMASK(7, 0)
|
||||
#define DIV_7_0_19_2_MHZ_VAL (0x90)
|
||||
#define DIV_7_0_38_4_MHZ_VAL (0xc8)
|
||||
|
||||
#define QCOM_USB_PHY_CFG_CTRL_3 (0x60)
|
||||
#define PHY_CFG_PLL_FB_DIV_11_8_MASK GENMASK(3, 0)
|
||||
#define DIV_11_8_19_2_MHZ_VAL (0x1)
|
||||
#define DIV_11_8_38_4_MHZ_VAL (0x0)
|
||||
|
||||
#define PHY_CFG_PLL_REF_DIV GENMASK(7, 4)
|
||||
#define PLL_REF_DIV_VAL (0x0)
|
||||
|
||||
#define QCOM_USB_PHY_HS_PHY_CTRL2 (0x64)
|
||||
#define VBUSVLDEXT0 BIT(0)
|
||||
#define USB2_SUSPEND_N BIT(2)
|
||||
#define USB2_SUSPEND_N_SEL BIT(3)
|
||||
#define VBUS_DET_EXT_SEL BIT(4)
|
||||
|
||||
#define QCOM_USB_PHY_CFG_CTRL_4 (0x68)
|
||||
#define PHY_CFG_PLL_GMP_CNTRL_MASK GENMASK(1, 0)
|
||||
#define PHY_CFG_PLL_INT_CNTRL_MASK GENMASK(7, 2)
|
||||
|
||||
#define QCOM_USB_PHY_CFG_CTRL_5 (0x6c)
|
||||
#define PHY_CFG_PLL_PROP_CNTRL_MASK GENMASK(4, 0)
|
||||
#define PHY_CFG_PLL_VREF_TUNE_MASK GENMASK(7, 6)
|
||||
|
||||
#define QCOM_USB_PHY_CFG_CTRL_6 (0x70)
|
||||
#define PHY_CFG_PLL_VCO_CNTRL_MASK GENMASK(2, 0)
|
||||
|
||||
#define QCOM_USB_PHY_CFG_CTRL_7 (0x74)
|
||||
|
||||
#define QCOM_USB_PHY_CFG_CTRL_8 (0x78)
|
||||
#define PHY_CFG_TX_FSLS_VREF_TUNE_MASK GENMASK(1, 0)
|
||||
#define PHY_CFG_TX_FSLS_VREG_BYPASS BIT(2)
|
||||
#define PHY_CFG_TX_HS_VREF_TUNE_MASK GENMASK(5, 3)
|
||||
#define PHY_CFG_TX_HS_XV_TUNE_MASK GENMASK(7, 6)
|
||||
|
||||
#define QCOM_USB_PHY_CFG_CTRL_9 (0x7c)
|
||||
#define PHY_CFG_TX_PREEMP_TUNE_MASK GENMASK(2, 0)
|
||||
#define PHY_CFG_TX_RES_TUNE_MASK GENMASK(4, 3)
|
||||
#define PHY_CFG_TX_RISE_TUNE_MASK GENMASK(6, 5)
|
||||
#define PHY_CFG_RCAL_BYPASS BIT(7)
|
||||
|
||||
#define QCOM_USB_PHY_CFG_CTRL_10 (0x80)
|
||||
|
||||
#define QCOM_USB_PHY_CFG0 (0x94)
|
||||
#define DATAPATH_CTRL_OVERRIDE_EN BIT(0)
|
||||
#define CMN_CTRL_OVERRIDE_EN BIT(1)
|
||||
|
||||
#define QCOM_UTMI_PHY_CMN_CTRL0 (0x98)
|
||||
#define TESTBURNIN BIT(6)
|
||||
|
||||
#define QCOM_USB_PHY_FSEL_SEL (0xb8)
|
||||
#define FSEL_SEL BIT(0)
|
||||
|
||||
#define QCOM_USB_PHY_APB_ACCESS_CMD (0x130)
|
||||
#define RW_ACCESS BIT(0)
|
||||
#define APB_START_CMD BIT(1)
|
||||
#define APB_LOGIC_RESET BIT(2)
|
||||
|
||||
#define QCOM_USB_PHY_APB_ACCESS_STATUS (0x134)
|
||||
#define ACCESS_DONE BIT(0)
|
||||
#define TIMED_OUT BIT(1)
|
||||
#define ACCESS_ERROR BIT(2)
|
||||
#define ACCESS_IN_PROGRESS BIT(3)
|
||||
|
||||
#define QCOM_USB_PHY_APB_ADDRESS (0x138)
|
||||
#define APB_REG_ADDR_MASK GENMASK(7, 0)
|
||||
|
||||
#define QCOM_USB_PHY_APB_WRDATA_LSB (0x13c)
|
||||
#define APB_REG_WRDATA_7_0_MASK GENMASK(3, 0)
|
||||
|
||||
#define QCOM_USB_PHY_APB_WRDATA_MSB (0x140)
|
||||
#define APB_REG_WRDATA_15_8_MASK GENMASK(7, 4)
|
||||
|
||||
#define QCOM_USB_PHY_APB_RDDATA_LSB (0x144)
|
||||
#define APB_REG_RDDATA_7_0_MASK GENMASK(3, 0)
|
||||
|
||||
#define QCOM_USB_PHY_APB_RDDATA_MSB (0x148)
|
||||
#define APB_REG_RDDATA_15_8_MASK GENMASK(7, 4)
|
||||
|
||||
static const char * const eusb2_hsphy_vreg_names[] = {
|
||||
"vdd", "vdda12",
|
||||
};
|
||||
|
||||
#define EUSB2_NUM_VREGS ARRAY_SIZE(eusb2_hsphy_vreg_names)
|
||||
|
||||
struct snps_eusb2_phy_drvdata {
|
||||
int (*phy_init)(struct phy *p);
|
||||
const char * const *clk_names;
|
||||
int num_clks;
|
||||
};
|
||||
|
||||
struct snps_eusb2_hsphy {
|
||||
struct phy *phy;
|
||||
void __iomem *base;
|
||||
|
||||
struct clk *ref_clk;
|
||||
struct clk_bulk_data *clks;
|
||||
struct reset_control *phy_reset;
|
||||
|
||||
struct regulator_bulk_data vregs[EUSB2_NUM_VREGS];
|
||||
|
||||
enum phy_mode mode;
|
||||
|
||||
struct phy *repeater;
|
||||
|
||||
const struct snps_eusb2_phy_drvdata *data;
|
||||
};
|
||||
|
||||
static int snps_eusb2_hsphy_set_mode(struct phy *p, enum phy_mode mode, int submode)
|
||||
{
|
||||
struct snps_eusb2_hsphy *phy = phy_get_drvdata(p);
|
||||
|
||||
phy->mode = mode;
|
||||
|
||||
return phy_set_mode_ext(phy->repeater, mode, submode);
|
||||
}
|
||||
|
||||
static void snps_eusb2_hsphy_write_mask(void __iomem *base, u32 offset,
|
||||
u32 mask, u32 val)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = readl_relaxed(base + offset);
|
||||
reg &= ~mask;
|
||||
reg |= val & mask;
|
||||
writel_relaxed(reg, base + offset);
|
||||
|
||||
/* Ensure above write is completed */
|
||||
readl_relaxed(base + offset);
|
||||
}
|
||||
|
||||
static void qcom_eusb2_default_parameters(struct snps_eusb2_hsphy *phy)
|
||||
{
|
||||
/* default parameters: tx pre-emphasis */
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_9,
|
||||
PHY_CFG_TX_PREEMP_TUNE_MASK,
|
||||
FIELD_PREP(PHY_CFG_TX_PREEMP_TUNE_MASK, 0));
|
||||
|
||||
/* tx rise/fall time */
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_9,
|
||||
PHY_CFG_TX_RISE_TUNE_MASK,
|
||||
FIELD_PREP(PHY_CFG_TX_RISE_TUNE_MASK, 0x2));
|
||||
|
||||
/* source impedance adjustment */
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_9,
|
||||
PHY_CFG_TX_RES_TUNE_MASK,
|
||||
FIELD_PREP(PHY_CFG_TX_RES_TUNE_MASK, 0x1));
|
||||
|
||||
/* dc voltage level adjustement */
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_8,
|
||||
PHY_CFG_TX_HS_VREF_TUNE_MASK,
|
||||
FIELD_PREP(PHY_CFG_TX_HS_VREF_TUNE_MASK, 0x3));
|
||||
|
||||
/* transmitter HS crossover adjustement */
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_8,
|
||||
PHY_CFG_TX_HS_XV_TUNE_MASK,
|
||||
FIELD_PREP(PHY_CFG_TX_HS_XV_TUNE_MASK, 0x0));
|
||||
}
|
||||
|
||||
struct snps_eusb2_ref_clk {
|
||||
unsigned long freq;
|
||||
u32 fsel_val;
|
||||
u32 div_7_0_val;
|
||||
u32 div_11_8_val;
|
||||
};
|
||||
|
||||
static const struct snps_eusb2_ref_clk exynos_eusb2_ref_clk[] = {
|
||||
{ 19200000, FSEL_19_2_MHZ_VAL, DIV_19_8_19_2_MHZ_VAL, EXYNOS_DIV_11_8_19_2_MHZ_VAL },
|
||||
{ 20000000, FSEL_20_MHZ_VAL, DIV_19_8_20_MHZ_VAL, EXYNOS_DIV_11_8_20_MHZ_VAL },
|
||||
{ 24000000, FSEL_24_MHZ_VAL, DIV_19_8_24_MHZ_VAL, EXYNOS_DIV_11_8_24_MHZ_VAL },
|
||||
{ 26000000, FSEL_26_MHZ_VAL, DIV_19_8_26_MHZ_VAL, EXYNOS_DIV_11_8_26_MHZ_VAL },
|
||||
{ 48000000, FSEL_48_MHZ_VAL, DIV_19_8_48_MHZ_VAL, EXYNOS_DIV_11_8_48_MHZ_VAL },
|
||||
};
|
||||
|
||||
static int exynos_eusb2_ref_clk_init(struct snps_eusb2_hsphy *phy)
|
||||
{
|
||||
const struct snps_eusb2_ref_clk *config = NULL;
|
||||
unsigned long ref_clk_freq = clk_get_rate(phy->ref_clk);
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(exynos_eusb2_ref_clk); i++) {
|
||||
if (exynos_eusb2_ref_clk[i].freq == ref_clk_freq) {
|
||||
config = &exynos_eusb2_ref_clk[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
dev_err(&phy->phy->dev, "unsupported ref_clk_freq:%lu\n", ref_clk_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON,
|
||||
FSEL_MASK,
|
||||
FIELD_PREP(FSEL_MASK, config->fsel_val));
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_CFG_PLLCFG0,
|
||||
PHY_CFG_PLL_FB_DIV_19_8_MASK,
|
||||
FIELD_PREP(PHY_CFG_PLL_FB_DIV_19_8_MASK,
|
||||
config->div_7_0_val));
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_CFG_PLLCFG1,
|
||||
EXYNOS_PHY_CFG_PLL_FB_DIV_11_8_MASK,
|
||||
config->div_11_8_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snps_eusb2_ref_clk qcom_eusb2_ref_clk[] = {
|
||||
{ 19200000, FSEL_19_2_MHZ_VAL, DIV_7_0_19_2_MHZ_VAL, DIV_11_8_19_2_MHZ_VAL },
|
||||
{ 38400000, FSEL_38_4_MHZ_VAL, DIV_7_0_38_4_MHZ_VAL, DIV_11_8_38_4_MHZ_VAL },
|
||||
};
|
||||
|
||||
static int qcom_eusb2_ref_clk_init(struct snps_eusb2_hsphy *phy)
|
||||
{
|
||||
const struct snps_eusb2_ref_clk *config = NULL;
|
||||
unsigned long ref_clk_freq = clk_get_rate(phy->ref_clk);
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(qcom_eusb2_ref_clk); i++) {
|
||||
if (qcom_eusb2_ref_clk[i].freq == ref_clk_freq) {
|
||||
config = &qcom_eusb2_ref_clk[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
dev_err(&phy->phy->dev, "unsupported ref_clk_freq:%lu\n", ref_clk_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL_COMMON0,
|
||||
FSEL_MASK,
|
||||
FIELD_PREP(FSEL_MASK, config->fsel_val));
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_2,
|
||||
PHY_CFG_PLL_FB_DIV_7_0_MASK,
|
||||
config->div_7_0_val);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_3,
|
||||
PHY_CFG_PLL_FB_DIV_11_8_MASK,
|
||||
config->div_11_8_val);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_3,
|
||||
PHY_CFG_PLL_REF_DIV, PLL_REF_DIV_VAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos_snps_eusb2_hsphy_init(struct phy *p)
|
||||
{
|
||||
struct snps_eusb2_hsphy *phy = phy_get_drvdata(p);
|
||||
int ret;
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_RST,
|
||||
USB_PHY_RST_MASK | UTMI_PORT_RST_MASK,
|
||||
USB_PHY_RST_MASK | UTMI_PORT_RST_MASK);
|
||||
fsleep(50); /* required after holding phy in reset */
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON,
|
||||
RPTR_MODE, RPTR_MODE);
|
||||
|
||||
/* update ref_clk related registers */
|
||||
ret = exynos_eusb2_ref_clk_init(phy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* default parameter: tx fsls-vref */
|
||||
snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_PHY_CFG_TX,
|
||||
EXYNOS_PHY_CFG_TX_FSLS_VREF_TUNE_MASK,
|
||||
FIELD_PREP(EXYNOS_PHY_CFG_TX_FSLS_VREF_TUNE_MASK, 0x0));
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_UTMI_TESTSE,
|
||||
TEST_IDDQ, 0);
|
||||
fsleep(10); /* required after releasing test_iddq */
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_RST,
|
||||
USB_PHY_RST_MASK, 0);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON,
|
||||
PHY_ENABLE, PHY_ENABLE);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_RST,
|
||||
UTMI_PORT_RST_MASK, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const exynos_eusb2_hsphy_clock_names[] = {
|
||||
"ref", "bus", "ctrl",
|
||||
};
|
||||
|
||||
static const struct snps_eusb2_phy_drvdata exynos2200_snps_eusb2_phy = {
|
||||
.phy_init = exynos_snps_eusb2_hsphy_init,
|
||||
.clk_names = exynos_eusb2_hsphy_clock_names,
|
||||
.num_clks = ARRAY_SIZE(exynos_eusb2_hsphy_clock_names),
|
||||
};
|
||||
|
||||
static int qcom_snps_eusb2_hsphy_init(struct phy *p)
|
||||
{
|
||||
struct snps_eusb2_hsphy *phy = phy_get_drvdata(p);
|
||||
int ret;
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG0,
|
||||
CMN_CTRL_OVERRIDE_EN, CMN_CTRL_OVERRIDE_EN);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_UTMI_CTRL5, POR, POR);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL_COMMON0,
|
||||
PHY_ENABLE | RETENABLEN, PHY_ENABLE | RETENABLEN);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_APB_ACCESS_CMD,
|
||||
APB_LOGIC_RESET, APB_LOGIC_RESET);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_UTMI_PHY_CMN_CTRL0, TESTBURNIN, 0);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_FSEL_SEL,
|
||||
FSEL_SEL, FSEL_SEL);
|
||||
|
||||
/* update ref_clk related registers */
|
||||
ret = qcom_eusb2_ref_clk_init(phy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_1,
|
||||
PHY_CFG_PLL_CPBIAS_CNTRL_MASK,
|
||||
FIELD_PREP(PHY_CFG_PLL_CPBIAS_CNTRL_MASK, 0x1));
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_4,
|
||||
PHY_CFG_PLL_INT_CNTRL_MASK,
|
||||
FIELD_PREP(PHY_CFG_PLL_INT_CNTRL_MASK, 0x8));
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_4,
|
||||
PHY_CFG_PLL_GMP_CNTRL_MASK,
|
||||
FIELD_PREP(PHY_CFG_PLL_GMP_CNTRL_MASK, 0x1));
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_5,
|
||||
PHY_CFG_PLL_PROP_CNTRL_MASK,
|
||||
FIELD_PREP(PHY_CFG_PLL_PROP_CNTRL_MASK, 0x10));
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_6,
|
||||
PHY_CFG_PLL_VCO_CNTRL_MASK,
|
||||
FIELD_PREP(PHY_CFG_PLL_VCO_CNTRL_MASK, 0x0));
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_5,
|
||||
PHY_CFG_PLL_VREF_TUNE_MASK,
|
||||
FIELD_PREP(PHY_CFG_PLL_VREF_TUNE_MASK, 0x1));
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL2,
|
||||
VBUS_DET_EXT_SEL, VBUS_DET_EXT_SEL);
|
||||
|
||||
/* set default parameters */
|
||||
qcom_eusb2_default_parameters(phy);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL2,
|
||||
USB2_SUSPEND_N_SEL | USB2_SUSPEND_N,
|
||||
USB2_SUSPEND_N_SEL | USB2_SUSPEND_N);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_UTMI_CTRL0, SLEEPM, SLEEPM);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL_COMMON0,
|
||||
SIDDQ_SEL, SIDDQ_SEL);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL_COMMON0,
|
||||
SIDDQ, 0);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_UTMI_CTRL5, POR, 0);
|
||||
|
||||
snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL2,
|
||||
USB2_SUSPEND_N_SEL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const qcom_eusb2_hsphy_clock_names[] = {
|
||||
"ref",
|
||||
};
|
||||
|
||||
static const struct snps_eusb2_phy_drvdata sm8550_snps_eusb2_phy = {
|
||||
.phy_init = qcom_snps_eusb2_hsphy_init,
|
||||
.clk_names = qcom_eusb2_hsphy_clock_names,
|
||||
.num_clks = ARRAY_SIZE(qcom_eusb2_hsphy_clock_names),
|
||||
};
|
||||
|
||||
static int snps_eusb2_hsphy_init(struct phy *p)
|
||||
{
|
||||
struct snps_eusb2_hsphy *phy = phy_get_drvdata(p);
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(phy->vregs), phy->vregs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = phy_init(phy->repeater);
|
||||
if (ret) {
|
||||
dev_err(&p->dev, "repeater init failed. %d\n", ret);
|
||||
goto disable_vreg;
|
||||
}
|
||||
|
||||
ret = clk_bulk_prepare_enable(phy->data->num_clks, phy->clks);
|
||||
if (ret) {
|
||||
dev_err(&p->dev, "failed to enable ref clock, %d\n", ret);
|
||||
goto disable_vreg;
|
||||
}
|
||||
|
||||
ret = reset_control_assert(phy->phy_reset);
|
||||
if (ret) {
|
||||
dev_err(&p->dev, "failed to assert phy_reset, %d\n", ret);
|
||||
goto disable_ref_clk;
|
||||
}
|
||||
|
||||
usleep_range(100, 150);
|
||||
|
||||
ret = reset_control_deassert(phy->phy_reset);
|
||||
if (ret) {
|
||||
dev_err(&p->dev, "failed to de-assert phy_reset, %d\n", ret);
|
||||
goto disable_ref_clk;
|
||||
}
|
||||
|
||||
ret = phy->data->phy_init(p);
|
||||
if (ret)
|
||||
goto disable_ref_clk;
|
||||
|
||||
return 0;
|
||||
|
||||
disable_ref_clk:
|
||||
clk_bulk_disable_unprepare(phy->data->num_clks, phy->clks);
|
||||
|
||||
disable_vreg:
|
||||
regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int snps_eusb2_hsphy_exit(struct phy *p)
|
||||
{
|
||||
struct snps_eusb2_hsphy *phy = phy_get_drvdata(p);
|
||||
|
||||
clk_disable_unprepare(phy->ref_clk);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs);
|
||||
|
||||
phy_exit(phy->repeater);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops snps_eusb2_hsphy_ops = {
|
||||
.init = snps_eusb2_hsphy_init,
|
||||
.exit = snps_eusb2_hsphy_exit,
|
||||
.set_mode = snps_eusb2_hsphy_set_mode,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int snps_eusb2_hsphy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct snps_eusb2_hsphy *phy;
|
||||
struct phy_provider *phy_provider;
|
||||
struct phy *generic_phy;
|
||||
int ret, i;
|
||||
int num;
|
||||
|
||||
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
|
||||
if (!phy)
|
||||
return -ENOMEM;
|
||||
|
||||
phy->data = device_get_match_data(dev);
|
||||
if (!phy->data)
|
||||
return -EINVAL;
|
||||
|
||||
phy->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(phy->base))
|
||||
return PTR_ERR(phy->base);
|
||||
|
||||
phy->phy_reset = devm_reset_control_get_optional_exclusive(dev, NULL);
|
||||
if (IS_ERR(phy->phy_reset))
|
||||
return PTR_ERR(phy->phy_reset);
|
||||
|
||||
phy->clks = devm_kcalloc(dev, phy->data->num_clks, sizeof(*phy->clks),
|
||||
GFP_KERNEL);
|
||||
if (!phy->clks)
|
||||
return -ENOMEM;
|
||||
|
||||
for (int i = 0; i < phy->data->num_clks; ++i)
|
||||
phy->clks[i].id = phy->data->clk_names[i];
|
||||
|
||||
ret = devm_clk_bulk_get(dev, phy->data->num_clks, phy->clks);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to get phy clock(s)\n");
|
||||
|
||||
phy->ref_clk = NULL;
|
||||
for (int i = 0; i < phy->data->num_clks; ++i) {
|
||||
if (!strcmp(phy->clks[i].id, "ref")) {
|
||||
phy->ref_clk = phy->clks[i].clk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(phy->ref_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(phy->ref_clk),
|
||||
"failed to get ref clk\n");
|
||||
|
||||
num = ARRAY_SIZE(phy->vregs);
|
||||
for (i = 0; i < num; i++)
|
||||
phy->vregs[i].supply = eusb2_hsphy_vreg_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(dev, num, phy->vregs);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to get regulator supplies\n");
|
||||
|
||||
phy->repeater = devm_of_phy_optional_get(dev, np, 0);
|
||||
if (IS_ERR(phy->repeater))
|
||||
return dev_err_probe(dev, PTR_ERR(phy->repeater),
|
||||
"failed to get repeater\n");
|
||||
|
||||
generic_phy = devm_phy_create(dev, NULL, &snps_eusb2_hsphy_ops);
|
||||
if (IS_ERR(generic_phy)) {
|
||||
dev_err(dev, "failed to create phy %d\n", ret);
|
||||
return PTR_ERR(generic_phy);
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, phy);
|
||||
phy_set_drvdata(generic_phy, phy);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(phy_provider))
|
||||
return PTR_ERR(phy_provider);
|
||||
|
||||
dev_info(dev, "Registered Snps-eUSB2 phy\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id snps_eusb2_hsphy_of_match_table[] = {
|
||||
{
|
||||
.compatible = "qcom,sm8550-snps-eusb2-phy",
|
||||
.data = &sm8550_snps_eusb2_phy,
|
||||
}, {
|
||||
.compatible = "samsung,exynos2200-eusb2-phy",
|
||||
.data = &exynos2200_snps_eusb2_phy,
|
||||
}, { },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, snps_eusb2_hsphy_of_match_table);
|
||||
|
||||
static struct platform_driver snps_eusb2_hsphy_driver = {
|
||||
.probe = snps_eusb2_hsphy_probe,
|
||||
.driver = {
|
||||
.name = "snps-eusb2-hsphy",
|
||||
.of_match_table = snps_eusb2_hsphy_of_match_table,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(snps_eusb2_hsphy_driver);
|
||||
MODULE_DESCRIPTION("Synopsys eUSB2 HS PHY driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -125,15 +125,6 @@ config PHY_QCOM_QUSB2
|
|||
PHY which is usually paired with either the ChipIdea or Synopsys DWC3
|
||||
USB IPs on MSM SOCs.
|
||||
|
||||
config PHY_QCOM_SNPS_EUSB2
|
||||
tristate "Qualcomm SNPS eUSB2 PHY Driver"
|
||||
depends on OF && (ARCH_QCOM || COMPILE_TEST)
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable support for the USB high-speed SNPS eUSB2 phy on Qualcomm
|
||||
chipsets. The PHY is paired with a Synopsys DWC3 USB controller
|
||||
on Qualcomm SOCs.
|
||||
|
||||
config PHY_QCOM_EUSB2_REPEATER
|
||||
tristate "Qualcomm SNPS eUSB2 Repeater Driver"
|
||||
depends on OF && (ARCH_QCOM || COMPILE_TEST)
|
||||
|
|
|
@ -15,7 +15,6 @@ obj-$(CONFIG_PHY_QCOM_QMP_USB) += phy-qcom-qmp-usb.o
|
|||
obj-$(CONFIG_PHY_QCOM_QMP_USB_LEGACY) += phy-qcom-qmp-usb-legacy.o
|
||||
|
||||
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
|
||||
obj-$(CONFIG_PHY_QCOM_SNPS_EUSB2) += phy-qcom-snps-eusb2.o
|
||||
obj-$(CONFIG_PHY_QCOM_EUSB2_REPEATER) += phy-qcom-eusb2-repeater.o
|
||||
obj-$(CONFIG_PHY_QCOM_UNIPHY_PCIE_28LP) += phy-qcom-uniphy-pcie-28lp.o
|
||||
obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o
|
||||
|
|
|
@ -3021,8 +3021,6 @@ struct qmp_phy_cfg {
|
|||
|
||||
bool skip_start_delay;
|
||||
|
||||
bool has_nocsr_reset;
|
||||
|
||||
/* QMP PHY pipe clock interface rate */
|
||||
unsigned long pipe_clock_rate;
|
||||
|
||||
|
@ -3035,6 +3033,7 @@ struct qmp_pcie {
|
|||
|
||||
const struct qmp_phy_cfg *cfg;
|
||||
bool tcsr_4ln_config;
|
||||
bool skip_init;
|
||||
|
||||
void __iomem *serdes;
|
||||
void __iomem *pcs;
|
||||
|
@ -4020,7 +4019,6 @@ static const struct qmp_phy_cfg sm8550_qmp_gen4x2_pciephy_cfg = {
|
|||
|
||||
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
|
||||
.phy_status = PHYSTATUS_4_20,
|
||||
.has_nocsr_reset = true,
|
||||
|
||||
/* 20MHz PHY AUX Clock */
|
||||
.aux_clock_rate = 20000000,
|
||||
|
@ -4053,7 +4051,6 @@ static const struct qmp_phy_cfg sm8650_qmp_gen4x2_pciephy_cfg = {
|
|||
|
||||
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
|
||||
.phy_status = PHYSTATUS_4_20,
|
||||
.has_nocsr_reset = true,
|
||||
|
||||
/* 20MHz PHY AUX Clock */
|
||||
.aux_clock_rate = 20000000,
|
||||
|
@ -4173,7 +4170,6 @@ static const struct qmp_phy_cfg x1e80100_qmp_gen4x2_pciephy_cfg = {
|
|||
|
||||
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
|
||||
.phy_status = PHYSTATUS_4_20,
|
||||
.has_nocsr_reset = true,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg x1e80100_qmp_gen4x4_pciephy_cfg = {
|
||||
|
@ -4207,7 +4203,6 @@ static const struct qmp_phy_cfg x1e80100_qmp_gen4x4_pciephy_cfg = {
|
|||
|
||||
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
|
||||
.phy_status = PHYSTATUS_4_20,
|
||||
.has_nocsr_reset = true,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg x1e80100_qmp_gen4x8_pciephy_cfg = {
|
||||
|
@ -4233,13 +4228,12 @@ static const struct qmp_phy_cfg x1e80100_qmp_gen4x8_pciephy_cfg = {
|
|||
|
||||
.reset_list = sdm845_pciephy_reset_l,
|
||||
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
|
||||
.vreg_list = sm8550_qmp_phy_vreg_l,
|
||||
.num_vregs = ARRAY_SIZE(sm8550_qmp_phy_vreg_l),
|
||||
.vreg_list = qmp_phy_vreg_l,
|
||||
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||
.regs = pciephy_v6_regs_layout,
|
||||
|
||||
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
|
||||
.phy_status = PHYSTATUS_4_20,
|
||||
.has_nocsr_reset = true,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg qmp_v6_gen4x4_pciephy_cfg = {
|
||||
|
@ -4337,18 +4331,38 @@ static int qmp_pcie_init(struct phy *phy)
|
|||
{
|
||||
struct qmp_pcie *qmp = phy_get_drvdata(phy);
|
||||
const struct qmp_phy_cfg *cfg = qmp->cfg;
|
||||
void __iomem *pcs = qmp->pcs;
|
||||
bool phy_initialized = !!(readl(pcs + cfg->regs[QPHY_START_CTRL]));
|
||||
int ret;
|
||||
|
||||
qmp->skip_init = qmp->nocsr_reset && phy_initialized;
|
||||
/*
|
||||
* We need to check the existence of init sequences in two cases:
|
||||
* 1. The PHY doesn't support no_csr reset.
|
||||
* 2. The PHY supports no_csr reset but isn't initialized by bootloader.
|
||||
* As we can't skip init in these two cases.
|
||||
*/
|
||||
if (!qmp->skip_init && !cfg->tbls.serdes_num) {
|
||||
dev_err(qmp->dev, "Init sequence not available\n");
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
|
||||
if (ret) {
|
||||
dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = reset_control_bulk_assert(cfg->num_resets, qmp->resets);
|
||||
if (ret) {
|
||||
dev_err(qmp->dev, "reset assert failed\n");
|
||||
goto err_disable_regulators;
|
||||
/*
|
||||
* Toggle BCR reset for PHY that doesn't support no_csr reset or has not
|
||||
* been initialized.
|
||||
*/
|
||||
if (!qmp->skip_init) {
|
||||
ret = reset_control_bulk_assert(cfg->num_resets, qmp->resets);
|
||||
if (ret) {
|
||||
dev_err(qmp->dev, "reset assert failed\n");
|
||||
goto err_disable_regulators;
|
||||
}
|
||||
}
|
||||
|
||||
ret = reset_control_assert(qmp->nocsr_reset);
|
||||
|
@ -4359,10 +4373,12 @@ static int qmp_pcie_init(struct phy *phy)
|
|||
|
||||
usleep_range(200, 300);
|
||||
|
||||
ret = reset_control_bulk_deassert(cfg->num_resets, qmp->resets);
|
||||
if (ret) {
|
||||
dev_err(qmp->dev, "reset deassert failed\n");
|
||||
goto err_assert_reset;
|
||||
if (!qmp->skip_init) {
|
||||
ret = reset_control_bulk_deassert(cfg->num_resets, qmp->resets);
|
||||
if (ret) {
|
||||
dev_err(qmp->dev, "reset deassert failed\n");
|
||||
goto err_assert_reset;
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_bulk_prepare_enable(ARRAY_SIZE(qmp_pciephy_clk_l), qmp->clks);
|
||||
|
@ -4372,7 +4388,8 @@ static int qmp_pcie_init(struct phy *phy)
|
|||
return 0;
|
||||
|
||||
err_assert_reset:
|
||||
reset_control_bulk_assert(cfg->num_resets, qmp->resets);
|
||||
if (!qmp->skip_init)
|
||||
reset_control_bulk_assert(cfg->num_resets, qmp->resets);
|
||||
err_disable_regulators:
|
||||
regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
|
||||
|
||||
|
@ -4384,7 +4401,10 @@ static int qmp_pcie_exit(struct phy *phy)
|
|||
struct qmp_pcie *qmp = phy_get_drvdata(phy);
|
||||
const struct qmp_phy_cfg *cfg = qmp->cfg;
|
||||
|
||||
reset_control_bulk_assert(cfg->num_resets, qmp->resets);
|
||||
if (qmp->nocsr_reset)
|
||||
reset_control_assert(qmp->nocsr_reset);
|
||||
else
|
||||
reset_control_bulk_assert(cfg->num_resets, qmp->resets);
|
||||
|
||||
clk_bulk_disable_unprepare(ARRAY_SIZE(qmp_pciephy_clk_l), qmp->clks);
|
||||
|
||||
|
@ -4403,6 +4423,13 @@ static int qmp_pcie_power_on(struct phy *phy)
|
|||
unsigned int mask, val;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Write CSR register for PHY that doesn't support no_csr reset or has not
|
||||
* been initialized.
|
||||
*/
|
||||
if (qmp->skip_init)
|
||||
goto skip_tbls_init;
|
||||
|
||||
qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
|
||||
cfg->pwrdn_ctrl);
|
||||
|
||||
|
@ -4414,6 +4441,7 @@ static int qmp_pcie_power_on(struct phy *phy)
|
|||
qmp_pcie_init_registers(qmp, &cfg->tbls);
|
||||
qmp_pcie_init_registers(qmp, mode_tbls);
|
||||
|
||||
skip_tbls_init:
|
||||
ret = clk_bulk_prepare_enable(qmp->num_pipe_clks, qmp->pipe_clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -4424,6 +4452,9 @@ static int qmp_pcie_power_on(struct phy *phy)
|
|||
goto err_disable_pipe_clk;
|
||||
}
|
||||
|
||||
if (qmp->skip_init)
|
||||
goto skip_serdes_start;
|
||||
|
||||
/* Pull PHY out of reset state */
|
||||
qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
|
||||
|
||||
|
@ -4433,6 +4464,7 @@ static int qmp_pcie_power_on(struct phy *phy)
|
|||
if (!cfg->skip_start_delay)
|
||||
usleep_range(1000, 1200);
|
||||
|
||||
skip_serdes_start:
|
||||
status = pcs + cfg->regs[QPHY_PCS_STATUS];
|
||||
mask = cfg->phy_status;
|
||||
ret = readl_poll_timeout(status, val, !(val & mask), 200,
|
||||
|
@ -4457,6 +4489,15 @@ static int qmp_pcie_power_off(struct phy *phy)
|
|||
|
||||
clk_bulk_disable_unprepare(qmp->num_pipe_clks, qmp->pipe_clks);
|
||||
|
||||
/*
|
||||
* While powering off the PHY, only qmp->nocsr_reset needs to be checked. In
|
||||
* this way, no matter whether the PHY settings were initially programmed by
|
||||
* bootloader or PHY driver itself, we can reuse them when PHY is powered on
|
||||
* next time.
|
||||
*/
|
||||
if (qmp->nocsr_reset)
|
||||
goto skip_phy_deinit;
|
||||
|
||||
/* PHY reset */
|
||||
qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
|
||||
|
||||
|
@ -4468,6 +4509,7 @@ static int qmp_pcie_power_off(struct phy *phy)
|
|||
qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],
|
||||
cfg->pwrdn_ctrl);
|
||||
|
||||
skip_phy_deinit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -4557,12 +4599,10 @@ static int qmp_pcie_reset_init(struct qmp_pcie *qmp)
|
|||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to get resets\n");
|
||||
|
||||
if (cfg->has_nocsr_reset) {
|
||||
qmp->nocsr_reset = devm_reset_control_get_exclusive(dev, "phy_nocsr");
|
||||
if (IS_ERR(qmp->nocsr_reset))
|
||||
return dev_err_probe(dev, PTR_ERR(qmp->nocsr_reset),
|
||||
"failed to get no-csr reset\n");
|
||||
}
|
||||
qmp->nocsr_reset = devm_reset_control_get_optional_exclusive(dev, "phy_nocsr");
|
||||
if (IS_ERR(qmp->nocsr_reset))
|
||||
return dev_err_probe(dev, PTR_ERR(qmp->nocsr_reset),
|
||||
"failed to get no-csr reset\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2106,12 +2106,16 @@ static void __iomem *qmp_usb_iomap(struct device *dev, struct device_node *np,
|
|||
int index, bool exclusive)
|
||||
{
|
||||
struct resource res;
|
||||
void __iomem *mem;
|
||||
|
||||
if (!exclusive) {
|
||||
if (of_address_to_resource(np, index, &res))
|
||||
return IOMEM_ERR_PTR(-EINVAL);
|
||||
|
||||
return devm_ioremap(dev, res.start, resource_size(&res));
|
||||
mem = devm_ioremap(dev, res.start, resource_size(&res));
|
||||
if (!mem)
|
||||
return IOMEM_ERR_PTR(-ENOMEM);
|
||||
return mem;
|
||||
}
|
||||
|
||||
return devm_of_iomap(dev, np, index, NULL);
|
||||
|
|
|
@ -151,21 +151,6 @@ static const struct qusb2_phy_init_tbl ipq6018_init_tbl[] = {
|
|||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9F),
|
||||
};
|
||||
|
||||
static const struct qusb2_phy_init_tbl ipq5424_init_tbl[] = {
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL, 0x14),
|
||||
QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0x00),
|
||||
QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0x53),
|
||||
QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0xc3),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),
|
||||
QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE5, 0x00),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
|
||||
QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TEST2, 0x14),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TEST, 0x80),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),
|
||||
};
|
||||
|
||||
static const struct qusb2_phy_init_tbl qcs615_init_tbl[] = {
|
||||
QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xc8),
|
||||
QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0xb3),
|
||||
|
@ -359,16 +344,6 @@ static const struct qusb2_phy_cfg ipq6018_phy_cfg = {
|
|||
.autoresume_en = BIT(0),
|
||||
};
|
||||
|
||||
static const struct qusb2_phy_cfg ipq5424_phy_cfg = {
|
||||
.tbl = ipq5424_init_tbl,
|
||||
.tbl_num = ARRAY_SIZE(ipq5424_init_tbl),
|
||||
.regs = ipq6018_regs_layout,
|
||||
|
||||
.disable_ctrl = POWER_DOWN,
|
||||
.mask_core_ready = PLL_LOCKED,
|
||||
.autoresume_en = BIT(0),
|
||||
};
|
||||
|
||||
static const struct qusb2_phy_cfg qcs615_phy_cfg = {
|
||||
.tbl = qcs615_init_tbl,
|
||||
.tbl_num = ARRAY_SIZE(qcs615_init_tbl),
|
||||
|
@ -955,7 +930,7 @@ static const struct phy_ops qusb2_phy_gen_ops = {
|
|||
static const struct of_device_id qusb2_phy_of_match_table[] = {
|
||||
{
|
||||
.compatible = "qcom,ipq5424-qusb2-phy",
|
||||
.data = &ipq5424_phy_cfg,
|
||||
.data = &ipq6018_phy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,ipq6018-qusb2-phy",
|
||||
.data = &ipq6018_phy_cfg,
|
||||
|
|
|
@ -1,442 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2023, Linaro Limited
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#define USB_PHY_UTMI_CTRL0 (0x3c)
|
||||
#define SLEEPM BIT(0)
|
||||
#define OPMODE_MASK GENMASK(4, 3)
|
||||
#define OPMODE_NONDRIVING BIT(3)
|
||||
|
||||
#define USB_PHY_UTMI_CTRL5 (0x50)
|
||||
#define POR BIT(1)
|
||||
|
||||
#define USB_PHY_HS_PHY_CTRL_COMMON0 (0x54)
|
||||
#define PHY_ENABLE BIT(0)
|
||||
#define SIDDQ_SEL BIT(1)
|
||||
#define SIDDQ BIT(2)
|
||||
#define RETENABLEN BIT(3)
|
||||
#define FSEL_MASK GENMASK(6, 4)
|
||||
#define FSEL_19_2_MHZ_VAL (0x0)
|
||||
#define FSEL_38_4_MHZ_VAL (0x4)
|
||||
|
||||
#define USB_PHY_CFG_CTRL_1 (0x58)
|
||||
#define PHY_CFG_PLL_CPBIAS_CNTRL_MASK GENMASK(7, 1)
|
||||
|
||||
#define USB_PHY_CFG_CTRL_2 (0x5c)
|
||||
#define PHY_CFG_PLL_FB_DIV_7_0_MASK GENMASK(7, 0)
|
||||
#define DIV_7_0_19_2_MHZ_VAL (0x90)
|
||||
#define DIV_7_0_38_4_MHZ_VAL (0xc8)
|
||||
|
||||
#define USB_PHY_CFG_CTRL_3 (0x60)
|
||||
#define PHY_CFG_PLL_FB_DIV_11_8_MASK GENMASK(3, 0)
|
||||
#define DIV_11_8_19_2_MHZ_VAL (0x1)
|
||||
#define DIV_11_8_38_4_MHZ_VAL (0x0)
|
||||
|
||||
#define PHY_CFG_PLL_REF_DIV GENMASK(7, 4)
|
||||
#define PLL_REF_DIV_VAL (0x0)
|
||||
|
||||
#define USB_PHY_HS_PHY_CTRL2 (0x64)
|
||||
#define VBUSVLDEXT0 BIT(0)
|
||||
#define USB2_SUSPEND_N BIT(2)
|
||||
#define USB2_SUSPEND_N_SEL BIT(3)
|
||||
#define VBUS_DET_EXT_SEL BIT(4)
|
||||
|
||||
#define USB_PHY_CFG_CTRL_4 (0x68)
|
||||
#define PHY_CFG_PLL_GMP_CNTRL_MASK GENMASK(1, 0)
|
||||
#define PHY_CFG_PLL_INT_CNTRL_MASK GENMASK(7, 2)
|
||||
|
||||
#define USB_PHY_CFG_CTRL_5 (0x6c)
|
||||
#define PHY_CFG_PLL_PROP_CNTRL_MASK GENMASK(4, 0)
|
||||
#define PHY_CFG_PLL_VREF_TUNE_MASK GENMASK(7, 6)
|
||||
|
||||
#define USB_PHY_CFG_CTRL_6 (0x70)
|
||||
#define PHY_CFG_PLL_VCO_CNTRL_MASK GENMASK(2, 0)
|
||||
|
||||
#define USB_PHY_CFG_CTRL_7 (0x74)
|
||||
|
||||
#define USB_PHY_CFG_CTRL_8 (0x78)
|
||||
#define PHY_CFG_TX_FSLS_VREF_TUNE_MASK GENMASK(1, 0)
|
||||
#define PHY_CFG_TX_FSLS_VREG_BYPASS BIT(2)
|
||||
#define PHY_CFG_TX_HS_VREF_TUNE_MASK GENMASK(5, 3)
|
||||
#define PHY_CFG_TX_HS_XV_TUNE_MASK GENMASK(7, 6)
|
||||
|
||||
#define USB_PHY_CFG_CTRL_9 (0x7c)
|
||||
#define PHY_CFG_TX_PREEMP_TUNE_MASK GENMASK(2, 0)
|
||||
#define PHY_CFG_TX_RES_TUNE_MASK GENMASK(4, 3)
|
||||
#define PHY_CFG_TX_RISE_TUNE_MASK GENMASK(6, 5)
|
||||
#define PHY_CFG_RCAL_BYPASS BIT(7)
|
||||
|
||||
#define USB_PHY_CFG_CTRL_10 (0x80)
|
||||
|
||||
#define USB_PHY_CFG0 (0x94)
|
||||
#define DATAPATH_CTRL_OVERRIDE_EN BIT(0)
|
||||
#define CMN_CTRL_OVERRIDE_EN BIT(1)
|
||||
|
||||
#define UTMI_PHY_CMN_CTRL0 (0x98)
|
||||
#define TESTBURNIN BIT(6)
|
||||
|
||||
#define USB_PHY_FSEL_SEL (0xb8)
|
||||
#define FSEL_SEL BIT(0)
|
||||
|
||||
#define USB_PHY_APB_ACCESS_CMD (0x130)
|
||||
#define RW_ACCESS BIT(0)
|
||||
#define APB_START_CMD BIT(1)
|
||||
#define APB_LOGIC_RESET BIT(2)
|
||||
|
||||
#define USB_PHY_APB_ACCESS_STATUS (0x134)
|
||||
#define ACCESS_DONE BIT(0)
|
||||
#define TIMED_OUT BIT(1)
|
||||
#define ACCESS_ERROR BIT(2)
|
||||
#define ACCESS_IN_PROGRESS BIT(3)
|
||||
|
||||
#define USB_PHY_APB_ADDRESS (0x138)
|
||||
#define APB_REG_ADDR_MASK GENMASK(7, 0)
|
||||
|
||||
#define USB_PHY_APB_WRDATA_LSB (0x13c)
|
||||
#define APB_REG_WRDATA_7_0_MASK GENMASK(3, 0)
|
||||
|
||||
#define USB_PHY_APB_WRDATA_MSB (0x140)
|
||||
#define APB_REG_WRDATA_15_8_MASK GENMASK(7, 4)
|
||||
|
||||
#define USB_PHY_APB_RDDATA_LSB (0x144)
|
||||
#define APB_REG_RDDATA_7_0_MASK GENMASK(3, 0)
|
||||
|
||||
#define USB_PHY_APB_RDDATA_MSB (0x148)
|
||||
#define APB_REG_RDDATA_15_8_MASK GENMASK(7, 4)
|
||||
|
||||
static const char * const eusb2_hsphy_vreg_names[] = {
|
||||
"vdd", "vdda12",
|
||||
};
|
||||
|
||||
#define EUSB2_NUM_VREGS ARRAY_SIZE(eusb2_hsphy_vreg_names)
|
||||
|
||||
struct qcom_snps_eusb2_hsphy {
|
||||
struct phy *phy;
|
||||
void __iomem *base;
|
||||
|
||||
struct clk *ref_clk;
|
||||
struct reset_control *phy_reset;
|
||||
|
||||
struct regulator_bulk_data vregs[EUSB2_NUM_VREGS];
|
||||
|
||||
enum phy_mode mode;
|
||||
|
||||
struct phy *repeater;
|
||||
};
|
||||
|
||||
static int qcom_snps_eusb2_hsphy_set_mode(struct phy *p, enum phy_mode mode, int submode)
|
||||
{
|
||||
struct qcom_snps_eusb2_hsphy *phy = phy_get_drvdata(p);
|
||||
|
||||
phy->mode = mode;
|
||||
|
||||
return phy_set_mode_ext(phy->repeater, mode, submode);
|
||||
}
|
||||
|
||||
static void qcom_snps_eusb2_hsphy_write_mask(void __iomem *base, u32 offset,
|
||||
u32 mask, u32 val)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = readl_relaxed(base + offset);
|
||||
reg &= ~mask;
|
||||
reg |= val & mask;
|
||||
writel_relaxed(reg, base + offset);
|
||||
|
||||
/* Ensure above write is completed */
|
||||
readl_relaxed(base + offset);
|
||||
}
|
||||
|
||||
static void qcom_eusb2_default_parameters(struct qcom_snps_eusb2_hsphy *phy)
|
||||
{
|
||||
/* default parameters: tx pre-emphasis */
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_9,
|
||||
PHY_CFG_TX_PREEMP_TUNE_MASK,
|
||||
FIELD_PREP(PHY_CFG_TX_PREEMP_TUNE_MASK, 0));
|
||||
|
||||
/* tx rise/fall time */
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_9,
|
||||
PHY_CFG_TX_RISE_TUNE_MASK,
|
||||
FIELD_PREP(PHY_CFG_TX_RISE_TUNE_MASK, 0x2));
|
||||
|
||||
/* source impedance adjustment */
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_9,
|
||||
PHY_CFG_TX_RES_TUNE_MASK,
|
||||
FIELD_PREP(PHY_CFG_TX_RES_TUNE_MASK, 0x1));
|
||||
|
||||
/* dc voltage level adjustement */
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_8,
|
||||
PHY_CFG_TX_HS_VREF_TUNE_MASK,
|
||||
FIELD_PREP(PHY_CFG_TX_HS_VREF_TUNE_MASK, 0x3));
|
||||
|
||||
/* transmitter HS crossover adjustement */
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_8,
|
||||
PHY_CFG_TX_HS_XV_TUNE_MASK,
|
||||
FIELD_PREP(PHY_CFG_TX_HS_XV_TUNE_MASK, 0x0));
|
||||
}
|
||||
|
||||
static int qcom_eusb2_ref_clk_init(struct qcom_snps_eusb2_hsphy *phy)
|
||||
{
|
||||
unsigned long ref_clk_freq = clk_get_rate(phy->ref_clk);
|
||||
|
||||
switch (ref_clk_freq) {
|
||||
case 19200000:
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0,
|
||||
FSEL_MASK,
|
||||
FIELD_PREP(FSEL_MASK, FSEL_19_2_MHZ_VAL));
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_2,
|
||||
PHY_CFG_PLL_FB_DIV_7_0_MASK,
|
||||
DIV_7_0_19_2_MHZ_VAL);
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_3,
|
||||
PHY_CFG_PLL_FB_DIV_11_8_MASK,
|
||||
DIV_11_8_19_2_MHZ_VAL);
|
||||
break;
|
||||
|
||||
case 38400000:
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0,
|
||||
FSEL_MASK,
|
||||
FIELD_PREP(FSEL_MASK, FSEL_38_4_MHZ_VAL));
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_2,
|
||||
PHY_CFG_PLL_FB_DIV_7_0_MASK,
|
||||
DIV_7_0_38_4_MHZ_VAL);
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_3,
|
||||
PHY_CFG_PLL_FB_DIV_11_8_MASK,
|
||||
DIV_11_8_38_4_MHZ_VAL);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(&phy->phy->dev, "unsupported ref_clk_freq:%lu\n", ref_clk_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_3,
|
||||
PHY_CFG_PLL_REF_DIV, PLL_REF_DIV_VAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_snps_eusb2_hsphy_init(struct phy *p)
|
||||
{
|
||||
struct qcom_snps_eusb2_hsphy *phy = phy_get_drvdata(p);
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(phy->vregs), phy->vregs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = phy_init(phy->repeater);
|
||||
if (ret) {
|
||||
dev_err(&p->dev, "repeater init failed. %d\n", ret);
|
||||
goto disable_vreg;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(phy->ref_clk);
|
||||
if (ret) {
|
||||
dev_err(&p->dev, "failed to enable ref clock, %d\n", ret);
|
||||
goto disable_vreg;
|
||||
}
|
||||
|
||||
ret = reset_control_assert(phy->phy_reset);
|
||||
if (ret) {
|
||||
dev_err(&p->dev, "failed to assert phy_reset, %d\n", ret);
|
||||
goto disable_ref_clk;
|
||||
}
|
||||
|
||||
usleep_range(100, 150);
|
||||
|
||||
ret = reset_control_deassert(phy->phy_reset);
|
||||
if (ret) {
|
||||
dev_err(&p->dev, "failed to de-assert phy_reset, %d\n", ret);
|
||||
goto disable_ref_clk;
|
||||
}
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG0,
|
||||
CMN_CTRL_OVERRIDE_EN, CMN_CTRL_OVERRIDE_EN);
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_UTMI_CTRL5, POR, POR);
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0,
|
||||
PHY_ENABLE | RETENABLEN, PHY_ENABLE | RETENABLEN);
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_APB_ACCESS_CMD,
|
||||
APB_LOGIC_RESET, APB_LOGIC_RESET);
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, UTMI_PHY_CMN_CTRL0, TESTBURNIN, 0);
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_FSEL_SEL,
|
||||
FSEL_SEL, FSEL_SEL);
|
||||
|
||||
/* update ref_clk related registers */
|
||||
ret = qcom_eusb2_ref_clk_init(phy);
|
||||
if (ret)
|
||||
goto disable_ref_clk;
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_1,
|
||||
PHY_CFG_PLL_CPBIAS_CNTRL_MASK,
|
||||
FIELD_PREP(PHY_CFG_PLL_CPBIAS_CNTRL_MASK, 0x1));
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_4,
|
||||
PHY_CFG_PLL_INT_CNTRL_MASK,
|
||||
FIELD_PREP(PHY_CFG_PLL_INT_CNTRL_MASK, 0x8));
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_4,
|
||||
PHY_CFG_PLL_GMP_CNTRL_MASK,
|
||||
FIELD_PREP(PHY_CFG_PLL_GMP_CNTRL_MASK, 0x1));
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_5,
|
||||
PHY_CFG_PLL_PROP_CNTRL_MASK,
|
||||
FIELD_PREP(PHY_CFG_PLL_PROP_CNTRL_MASK, 0x10));
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_6,
|
||||
PHY_CFG_PLL_VCO_CNTRL_MASK,
|
||||
FIELD_PREP(PHY_CFG_PLL_VCO_CNTRL_MASK, 0x0));
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_5,
|
||||
PHY_CFG_PLL_VREF_TUNE_MASK,
|
||||
FIELD_PREP(PHY_CFG_PLL_VREF_TUNE_MASK, 0x1));
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL2,
|
||||
VBUS_DET_EXT_SEL, VBUS_DET_EXT_SEL);
|
||||
|
||||
/* set default parameters */
|
||||
qcom_eusb2_default_parameters(phy);
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL2,
|
||||
USB2_SUSPEND_N_SEL | USB2_SUSPEND_N,
|
||||
USB2_SUSPEND_N_SEL | USB2_SUSPEND_N);
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_UTMI_CTRL0, SLEEPM, SLEEPM);
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0,
|
||||
SIDDQ_SEL, SIDDQ_SEL);
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0,
|
||||
SIDDQ, 0);
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_UTMI_CTRL5, POR, 0);
|
||||
|
||||
qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL2,
|
||||
USB2_SUSPEND_N_SEL, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
disable_ref_clk:
|
||||
clk_disable_unprepare(phy->ref_clk);
|
||||
|
||||
disable_vreg:
|
||||
regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_snps_eusb2_hsphy_exit(struct phy *p)
|
||||
{
|
||||
struct qcom_snps_eusb2_hsphy *phy = phy_get_drvdata(p);
|
||||
|
||||
clk_disable_unprepare(phy->ref_clk);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs);
|
||||
|
||||
phy_exit(phy->repeater);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops qcom_snps_eusb2_hsphy_ops = {
|
||||
.init = qcom_snps_eusb2_hsphy_init,
|
||||
.exit = qcom_snps_eusb2_hsphy_exit,
|
||||
.set_mode = qcom_snps_eusb2_hsphy_set_mode,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int qcom_snps_eusb2_hsphy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct qcom_snps_eusb2_hsphy *phy;
|
||||
struct phy_provider *phy_provider;
|
||||
struct phy *generic_phy;
|
||||
int ret, i;
|
||||
int num;
|
||||
|
||||
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
|
||||
if (!phy)
|
||||
return -ENOMEM;
|
||||
|
||||
phy->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(phy->base))
|
||||
return PTR_ERR(phy->base);
|
||||
|
||||
phy->phy_reset = devm_reset_control_get_exclusive(dev, NULL);
|
||||
if (IS_ERR(phy->phy_reset))
|
||||
return PTR_ERR(phy->phy_reset);
|
||||
|
||||
phy->ref_clk = devm_clk_get(dev, "ref");
|
||||
if (IS_ERR(phy->ref_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(phy->ref_clk),
|
||||
"failed to get ref clk\n");
|
||||
|
||||
num = ARRAY_SIZE(phy->vregs);
|
||||
for (i = 0; i < num; i++)
|
||||
phy->vregs[i].supply = eusb2_hsphy_vreg_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(dev, num, phy->vregs);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to get regulator supplies\n");
|
||||
|
||||
phy->repeater = devm_of_phy_get_by_index(dev, np, 0);
|
||||
if (IS_ERR(phy->repeater))
|
||||
return dev_err_probe(dev, PTR_ERR(phy->repeater),
|
||||
"failed to get repeater\n");
|
||||
|
||||
generic_phy = devm_phy_create(dev, NULL, &qcom_snps_eusb2_hsphy_ops);
|
||||
if (IS_ERR(generic_phy)) {
|
||||
dev_err(dev, "failed to create phy %d\n", ret);
|
||||
return PTR_ERR(generic_phy);
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, phy);
|
||||
phy_set_drvdata(generic_phy, phy);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(phy_provider))
|
||||
return PTR_ERR(phy_provider);
|
||||
|
||||
dev_info(dev, "Registered Qcom-eUSB2 phy\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id qcom_snps_eusb2_hsphy_of_match_table[] = {
|
||||
{ .compatible = "qcom,sm8550-snps-eusb2-phy", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qcom_snps_eusb2_hsphy_of_match_table);
|
||||
|
||||
static struct platform_driver qcom_snps_eusb2_hsphy_driver = {
|
||||
.probe = qcom_snps_eusb2_hsphy_probe,
|
||||
.driver = {
|
||||
.name = "qcom-snps-eusb2-hsphy",
|
||||
.of_match_table = qcom_snps_eusb2_hsphy_of_match_table,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(qcom_snps_eusb2_hsphy_driver);
|
||||
MODULE_DESCRIPTION("Qualcomm SNPS eUSB2 HS PHY driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -75,6 +75,40 @@ struct qcom_uniphy_pcie {
|
|||
|
||||
#define phy_to_dw_phy(x) container_of((x), struct qca_uni_pcie_phy, phy)
|
||||
|
||||
static const struct qcom_uniphy_pcie_regs ipq5018_regs[] = {
|
||||
{
|
||||
.offset = SSCG_CTRL_REG_4,
|
||||
.val = 0x1cb9,
|
||||
}, {
|
||||
.offset = SSCG_CTRL_REG_5,
|
||||
.val = 0x023a,
|
||||
}, {
|
||||
.offset = SSCG_CTRL_REG_3,
|
||||
.val = 0xd360,
|
||||
}, {
|
||||
.offset = SSCG_CTRL_REG_1,
|
||||
.val = 0x1,
|
||||
}, {
|
||||
.offset = SSCG_CTRL_REG_2,
|
||||
.val = 0xeb,
|
||||
}, {
|
||||
.offset = CDR_CTRL_REG_4,
|
||||
.val = 0x3f9,
|
||||
}, {
|
||||
.offset = CDR_CTRL_REG_5,
|
||||
.val = 0x1c9,
|
||||
}, {
|
||||
.offset = CDR_CTRL_REG_2,
|
||||
.val = 0x419,
|
||||
}, {
|
||||
.offset = CDR_CTRL_REG_1,
|
||||
.val = 0x200,
|
||||
}, {
|
||||
.offset = PCS_INTERNAL_CONTROL_2,
|
||||
.val = 0xf101,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct qcom_uniphy_pcie_regs ipq5332_regs[] = {
|
||||
{
|
||||
.offset = PHY_CFG_PLLCFG,
|
||||
|
@ -88,6 +122,14 @@ static const struct qcom_uniphy_pcie_regs ipq5332_regs[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct qcom_uniphy_pcie_data ipq5018_data = {
|
||||
.lane_offset = 0x800,
|
||||
.phy_type = PHY_TYPE_PCIE_GEN2,
|
||||
.init_seq = ipq5018_regs,
|
||||
.init_seq_num = ARRAY_SIZE(ipq5018_regs),
|
||||
.pipe_clk_rate = 125 * MEGA,
|
||||
};
|
||||
|
||||
static const struct qcom_uniphy_pcie_data ipq5332_data = {
|
||||
.lane_offset = 0x800,
|
||||
.phy_type = PHY_TYPE_PCIE_GEN3,
|
||||
|
@ -212,6 +254,9 @@ static inline int phy_pipe_clk_register(struct qcom_uniphy_pcie *phy, int id)
|
|||
|
||||
static const struct of_device_id qcom_uniphy_pcie_id_table[] = {
|
||||
{
|
||||
.compatible = "qcom,ipq5018-uniphy-pcie-phy",
|
||||
.data = &ipq5018_data,
|
||||
}, {
|
||||
.compatible = "qcom,ipq5332-uniphy-pcie-phy",
|
||||
.data = &ipq5332_data,
|
||||
}, {
|
||||
|
|
|
@ -29,8 +29,10 @@
|
|||
#define USB2_INT_ENABLE 0x000
|
||||
#define USB2_AHB_BUS_CTR 0x008
|
||||
#define USB2_USBCTR 0x00c
|
||||
#define USB2_REGEN_CG_CTRL 0x104 /* RZ/V2H(P) only */
|
||||
#define USB2_SPD_RSM_TIMSET 0x10c
|
||||
#define USB2_OC_TIMSET 0x110
|
||||
#define USB2_UTMI_CTRL 0x118 /* RZ/V2H(P) only */
|
||||
#define USB2_COMMCTRL 0x600
|
||||
#define USB2_OBINTSTA 0x604
|
||||
#define USB2_OBINTEN 0x608
|
||||
|
@ -51,12 +53,18 @@
|
|||
#define USB2_USBCTR_DIRPD BIT(2)
|
||||
#define USB2_USBCTR_PLL_RST BIT(1)
|
||||
|
||||
/* REGEN_CG_CTRL*/
|
||||
#define USB2_REGEN_CG_CTRL_UPHY_WEN BIT(0)
|
||||
|
||||
/* SPD_RSM_TIMSET */
|
||||
#define USB2_SPD_RSM_TIMSET_INIT 0x014e029b
|
||||
|
||||
/* OC_TIMSET */
|
||||
#define USB2_OC_TIMSET_INIT 0x000209ab
|
||||
|
||||
/* UTMI_CTRL */
|
||||
#define USB2_UTMI_CTRL_INIT 0x8000018f
|
||||
|
||||
/* COMMCTRL */
|
||||
#define USB2_COMMCTRL_OTG_PERI BIT(31) /* 1 = Peripheral mode */
|
||||
|
||||
|
@ -126,12 +134,14 @@ struct rcar_gen3_chan {
|
|||
bool is_otg_channel;
|
||||
bool uses_otg_pins;
|
||||
bool soc_no_adp_ctrl;
|
||||
bool utmi_ctrl;
|
||||
};
|
||||
|
||||
struct rcar_gen3_phy_drv_data {
|
||||
const struct phy_ops *phy_usb2_ops;
|
||||
bool no_adp_ctrl;
|
||||
bool init_bus;
|
||||
bool utmi_ctrl;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -477,6 +487,14 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
|
|||
if (rphy->int_enable_bits)
|
||||
rcar_gen3_init_otg(channel);
|
||||
|
||||
if (channel->utmi_ctrl) {
|
||||
val = readl(usb2_base + USB2_REGEN_CG_CTRL) | USB2_REGEN_CG_CTRL_UPHY_WEN;
|
||||
writel(val, usb2_base + USB2_REGEN_CG_CTRL);
|
||||
|
||||
writel(USB2_UTMI_CTRL_INIT, usb2_base + USB2_UTMI_CTRL);
|
||||
writel(val & ~USB2_REGEN_CG_CTRL_UPHY_WEN, usb2_base + USB2_REGEN_CG_CTRL);
|
||||
}
|
||||
|
||||
rphy->initialized = true;
|
||||
|
||||
return 0;
|
||||
|
@ -592,6 +610,12 @@ static const struct rcar_gen3_phy_drv_data rz_g3s_phy_usb2_data = {
|
|||
.init_bus = true,
|
||||
};
|
||||
|
||||
static const struct rcar_gen3_phy_drv_data rz_v2h_phy_usb2_data = {
|
||||
.phy_usb2_ops = &rcar_gen3_phy_usb2_ops,
|
||||
.no_adp_ctrl = true,
|
||||
.utmi_ctrl = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
|
||||
{
|
||||
.compatible = "renesas,usb2-phy-r8a77470",
|
||||
|
@ -609,14 +633,18 @@ static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
|
|||
.compatible = "renesas,usb2-phy-r8a77965",
|
||||
.data = &rcar_gen3_phy_usb2_data,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,rzg2l-usb2-phy",
|
||||
.data = &rz_g2l_phy_usb2_data,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,usb2-phy-r9a08g045",
|
||||
.data = &rz_g3s_phy_usb2_data,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,usb2-phy-r9a09g057",
|
||||
.data = &rz_v2h_phy_usb2_data,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,rzg2l-usb2-phy",
|
||||
.data = &rz_g2l_phy_usb2_data,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,rcar-gen3-usb2-phy",
|
||||
.data = &rcar_gen3_phy_usb2_data,
|
||||
|
@ -764,6 +792,8 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
|||
if (phy_data->no_adp_ctrl)
|
||||
channel->obint_enable_bits = USB2_OBINT_IDCHG_EN;
|
||||
|
||||
channel->utmi_ctrl = phy_data->utmi_ctrl;
|
||||
|
||||
spin_lock_init(&channel->lock);
|
||||
for (i = 0; i < NUM_OF_PHYS; i++) {
|
||||
channel->rphys[i].phy = devm_phy_create(dev, NULL,
|
||||
|
|
|
@ -1583,6 +1583,37 @@ static int rk3588_usb2phy_tuning(struct rockchip_usb2phy *rphy)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct rockchip_usb2phy_cfg rk3036_phy_cfgs[] = {
|
||||
{
|
||||
.reg = 0x17c,
|
||||
.num_ports = 2,
|
||||
.phy_tuning = rk3128_usb2phy_tuning,
|
||||
.clkout_ctl = { 0x017c, 11, 11, 1, 0 },
|
||||
.port_cfgs = {
|
||||
[USB2PHY_PORT_OTG] = {
|
||||
.phy_sus = { 0x017c, 8, 0, 0, 0x1d1 },
|
||||
.bvalid_det_en = { 0x017c, 14, 14, 0, 1 },
|
||||
.bvalid_det_st = { 0x017c, 15, 15, 0, 1 },
|
||||
.bvalid_det_clr = { 0x017c, 15, 15, 0, 1 },
|
||||
.ls_det_en = { 0x017c, 12, 12, 0, 1 },
|
||||
.ls_det_st = { 0x017c, 13, 13, 0, 1 },
|
||||
.ls_det_clr = { 0x017c, 13, 13, 0, 1 },
|
||||
.utmi_bvalid = { 0x014c, 8, 8, 0, 1 },
|
||||
.utmi_id = { 0x014c, 11, 11, 0, 1 },
|
||||
.utmi_ls = { 0x014c, 10, 9, 0, 1 },
|
||||
|
||||
},
|
||||
[USB2PHY_PORT_HOST] = {
|
||||
.phy_sus = { 0x0194, 8, 0, 0, 0x1d1 },
|
||||
.ls_det_en = { 0x0194, 14, 14, 0, 1 },
|
||||
.ls_det_st = { 0x0194, 15, 15, 0, 1 },
|
||||
.ls_det_clr = { 0x0194, 15, 15, 0, 1 }
|
||||
}
|
||||
},
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct rockchip_usb2phy_cfg rk3128_phy_cfgs[] = {
|
||||
{
|
||||
.reg = 0x17c,
|
||||
|
@ -1892,6 +1923,54 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
|
|||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct rockchip_usb2phy_cfg rk3562_phy_cfgs[] = {
|
||||
{
|
||||
.reg = 0xff740000,
|
||||
.num_ports = 2,
|
||||
.clkout_ctl = { 0x0108, 4, 4, 1, 0 },
|
||||
.port_cfgs = {
|
||||
[USB2PHY_PORT_OTG] = {
|
||||
.phy_sus = { 0x0100, 8, 0, 0, 0x1d1 },
|
||||
.bvalid_det_en = { 0x0110, 2, 2, 0, 1 },
|
||||
.bvalid_det_st = { 0x0114, 2, 2, 0, 1 },
|
||||
.bvalid_det_clr = { 0x0118, 2, 2, 0, 1 },
|
||||
.idfall_det_en = { 0x0110, 5, 5, 0, 1 },
|
||||
.idfall_det_st = { 0x0114, 5, 5, 0, 1 },
|
||||
.idfall_det_clr = { 0x0118, 5, 5, 0, 1 },
|
||||
.idrise_det_en = { 0x0110, 4, 4, 0, 1 },
|
||||
.idrise_det_st = { 0x0114, 4, 4, 0, 1 },
|
||||
.idrise_det_clr = { 0x0118, 4, 4, 0, 1 },
|
||||
.ls_det_en = { 0x0110, 0, 0, 0, 1 },
|
||||
.ls_det_st = { 0x0114, 0, 0, 0, 1 },
|
||||
.ls_det_clr = { 0x0118, 0, 0, 0, 1 },
|
||||
.utmi_avalid = { 0x0120, 10, 10, 0, 1 },
|
||||
.utmi_bvalid = { 0x0120, 9, 9, 0, 1 },
|
||||
.utmi_ls = { 0x0120, 5, 4, 0, 1 },
|
||||
},
|
||||
[USB2PHY_PORT_HOST] = {
|
||||
.phy_sus = { 0x0104, 8, 0, 0x1d2, 0x1d1 },
|
||||
.ls_det_en = { 0x0110, 1, 1, 0, 1 },
|
||||
.ls_det_st = { 0x0114, 1, 1, 0, 1 },
|
||||
.ls_det_clr = { 0x0118, 1, 1, 0, 1 },
|
||||
.utmi_ls = { 0x0120, 17, 16, 0, 1 },
|
||||
.utmi_hstdet = { 0x0120, 19, 19, 0, 1 }
|
||||
}
|
||||
},
|
||||
.chg_det = {
|
||||
.cp_det = { 0x0120, 24, 24, 0, 1 },
|
||||
.dcp_det = { 0x0120, 23, 23, 0, 1 },
|
||||
.dp_det = { 0x0120, 25, 25, 0, 1 },
|
||||
.idm_sink_en = { 0x0108, 8, 8, 0, 1 },
|
||||
.idp_sink_en = { 0x0108, 7, 7, 0, 1 },
|
||||
.idp_src_en = { 0x0108, 9, 9, 0, 1 },
|
||||
.rdm_pdwn_en = { 0x0108, 10, 10, 0, 1 },
|
||||
.vdm_src_en = { 0x0108, 12, 12, 0, 1 },
|
||||
.vdp_src_en = { 0x0108, 11, 11, 0, 1 },
|
||||
},
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = {
|
||||
{
|
||||
.reg = 0xfe8a0000,
|
||||
|
@ -2204,12 +2283,14 @@ static const struct rockchip_usb2phy_cfg rv1108_phy_cfgs[] = {
|
|||
|
||||
static const struct of_device_id rockchip_usb2phy_dt_match[] = {
|
||||
{ .compatible = "rockchip,px30-usb2phy", .data = &rk3328_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3036-usb2phy", .data = &rk3036_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3128-usb2phy", .data = &rk3128_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3228-usb2phy", .data = &rk3228_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3308-usb2phy", .data = &rk3308_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3328-usb2phy", .data = &rk3328_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3562-usb2phy", .data = &rk3562_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3568-usb2phy", .data = &rk3568_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3576-usb2phy", .data = &rk3576_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3588-usb2phy", .data = &rk3588_phy_cfgs },
|
||||
|
|
|
@ -320,6 +320,7 @@
|
|||
#define LN3_TX_SER_RATE_SEL_HBR2_MASK BIT(3)
|
||||
#define LN3_TX_SER_RATE_SEL_HBR3_MASK BIT(2)
|
||||
|
||||
#define HDMI14_MAX_RATE 340000000
|
||||
#define HDMI20_MAX_RATE 600000000
|
||||
|
||||
enum dp_link_rate {
|
||||
|
@ -328,39 +329,8 @@ enum dp_link_rate {
|
|||
DP_BW_HBR2,
|
||||
};
|
||||
|
||||
struct lcpll_config {
|
||||
u32 bit_rate;
|
||||
u8 lcvco_mode_en;
|
||||
u8 pi_en;
|
||||
u8 clk_en_100m;
|
||||
u8 pms_mdiv;
|
||||
u8 pms_mdiv_afc;
|
||||
u8 pms_pdiv;
|
||||
u8 pms_refdiv;
|
||||
u8 pms_sdiv;
|
||||
u8 pi_cdiv_rstn;
|
||||
u8 pi_cdiv_sel;
|
||||
u8 sdm_en;
|
||||
u8 sdm_rstn;
|
||||
u8 sdc_frac_en;
|
||||
u8 sdc_rstn;
|
||||
u8 sdm_deno;
|
||||
u8 sdm_num_sign;
|
||||
u8 sdm_num;
|
||||
u8 sdc_n;
|
||||
u8 sdc_n2;
|
||||
u8 sdc_num;
|
||||
u8 sdc_deno;
|
||||
u8 sdc_ndiv_rstn;
|
||||
u8 ssc_en;
|
||||
u8 ssc_fm_dev;
|
||||
u8 ssc_fm_freq;
|
||||
u8 ssc_clk_div_sel;
|
||||
u8 cd_tx_ser_rate_sel;
|
||||
};
|
||||
|
||||
struct ropll_config {
|
||||
u32 bit_rate;
|
||||
unsigned long long rate;
|
||||
u8 pms_mdiv;
|
||||
u8 pms_mdiv_afc;
|
||||
u8 pms_pdiv;
|
||||
|
@ -422,19 +392,17 @@ struct rk_hdptx_phy {
|
|||
struct regmap *regmap;
|
||||
struct regmap *grf;
|
||||
|
||||
/* PHY const config */
|
||||
const struct rk_hdptx_phy_cfg *cfgs;
|
||||
int phy_id;
|
||||
|
||||
struct phy *phy;
|
||||
struct phy_config *phy_cfg;
|
||||
struct phy_configure_opts_hdmi hdmi_cfg;
|
||||
struct clk_bulk_data *clks;
|
||||
int nr_clks;
|
||||
struct reset_control_bulk_data rsts[RST_MAX];
|
||||
|
||||
/* clk provider */
|
||||
struct clk_hw hw;
|
||||
unsigned long rate;
|
||||
unsigned long hw_rate;
|
||||
bool restrict_rate_change;
|
||||
|
||||
atomic_t usage_count;
|
||||
|
||||
|
@ -444,47 +412,47 @@ struct rk_hdptx_phy {
|
|||
};
|
||||
|
||||
static const struct ropll_config ropll_tmds_cfg[] = {
|
||||
{ 5940000, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
{ 594000000ULL, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 3712500, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
{ 371250000ULL, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 2970000, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
{ 297000000ULL, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 1620000, 135, 135, 1, 1, 3, 1, 1, 0, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10,
|
||||
{ 162000000ULL, 135, 135, 1, 1, 3, 1, 1, 0, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10,
|
||||
1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 1856250, 155, 155, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
{ 185625000ULL, 155, 155, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 1540000, 193, 193, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 193, 1, 32, 2, 1,
|
||||
{ 154000000ULL, 193, 193, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 193, 1, 32, 2, 1,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 1485000, 0x7b, 0x7b, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 4, 0, 3, 5, 5,
|
||||
{ 148500000ULL, 0x7b, 0x7b, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 4, 0, 3, 5, 5,
|
||||
0x10, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 1462500, 122, 122, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 244, 1, 16, 2, 1, 1,
|
||||
{ 146250000ULL, 122, 122, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 244, 1, 16, 2, 1, 1,
|
||||
1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 1190000, 149, 149, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 149, 1, 16, 2, 1, 1,
|
||||
{ 119000000ULL, 149, 149, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 149, 1, 16, 2, 1, 1,
|
||||
1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 1065000, 89, 89, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 89, 1, 16, 1, 0, 1,
|
||||
{ 106500000ULL, 89, 89, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 89, 1, 16, 1, 0, 1,
|
||||
1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 1080000, 135, 135, 1, 1, 5, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
|
||||
{ 108000000ULL, 135, 135, 1, 1, 5, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
|
||||
0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 855000, 214, 214, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 214, 1, 16, 2, 1,
|
||||
{ 85500000ULL, 214, 214, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 214, 1, 16, 2, 1,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 835000, 105, 105, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 42, 1, 16, 1, 0,
|
||||
{ 83500000ULL, 105, 105, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 42, 1, 16, 1, 0,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 928125, 155, 155, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
{ 92812500ULL, 155, 155, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 742500, 124, 124, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
{ 74250000ULL, 124, 124, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 650000, 162, 162, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 54, 0, 16, 4, 1,
|
||||
{ 65000000ULL, 162, 162, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 54, 0, 16, 4, 1,
|
||||
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 502500, 84, 84, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 11, 1, 4, 5,
|
||||
{ 50250000ULL, 84, 84, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 11, 1, 4, 5,
|
||||
4, 11, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 337500, 0x70, 0x70, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 0x2, 0, 0x01, 5,
|
||||
{ 33750000ULL, 0x70, 0x70, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 0x2, 0, 0x01, 5,
|
||||
1, 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 400000, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
|
||||
{ 40000000ULL, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
|
||||
0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 270000, 0x5a, 0x5a, 1, 1, 0xf, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
|
||||
{ 27000000ULL, 0x5a, 0x5a, 1, 1, 0xf, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
|
||||
0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
{ 251750, 84, 84, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 168, 1, 16, 4, 1, 1,
|
||||
{ 25175000ULL, 84, 84, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 168, 1, 16, 4, 1, 1,
|
||||
1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
|
||||
};
|
||||
|
||||
|
@ -930,10 +898,10 @@ static void rk_hdptx_phy_disable(struct rk_hdptx_phy *hdptx)
|
|||
regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
|
||||
}
|
||||
|
||||
static bool rk_hdptx_phy_clk_pll_calc(unsigned int data_rate,
|
||||
static bool rk_hdptx_phy_clk_pll_calc(unsigned long long rate,
|
||||
struct ropll_config *cfg)
|
||||
{
|
||||
const unsigned int fout = data_rate / 2, fref = 24000;
|
||||
const unsigned int fout = div_u64(rate, 200), fref = 24000;
|
||||
unsigned long k = 0, lc, k_sub, lc_sub;
|
||||
unsigned int fvco, sdc;
|
||||
u32 mdiv, sdiv, n = 8;
|
||||
|
@ -1002,33 +970,34 @@ static bool rk_hdptx_phy_clk_pll_calc(unsigned int data_rate,
|
|||
return true;
|
||||
}
|
||||
|
||||
static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx,
|
||||
unsigned int rate)
|
||||
static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx)
|
||||
{
|
||||
const struct ropll_config *cfg = NULL;
|
||||
struct ropll_config rc = {0};
|
||||
int i;
|
||||
int ret, i;
|
||||
|
||||
hdptx->rate = rate * 100;
|
||||
if (!hdptx->hdmi_cfg.tmds_char_rate)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
|
||||
if (rate == ropll_tmds_cfg[i].bit_rate) {
|
||||
if (hdptx->hdmi_cfg.tmds_char_rate == ropll_tmds_cfg[i].rate) {
|
||||
cfg = &ropll_tmds_cfg[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if (!cfg) {
|
||||
if (rk_hdptx_phy_clk_pll_calc(rate, &rc)) {
|
||||
cfg = &rc;
|
||||
} else {
|
||||
dev_err(hdptx->dev, "%s cannot find pll cfg\n", __func__);
|
||||
if (!rk_hdptx_phy_clk_pll_calc(hdptx->hdmi_cfg.tmds_char_rate, &rc)) {
|
||||
dev_err(hdptx->dev, "%s cannot find pll cfg for rate=%llu\n",
|
||||
__func__, hdptx->hdmi_cfg.tmds_char_rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cfg = &rc;
|
||||
}
|
||||
|
||||
dev_dbg(hdptx->dev, "mdiv=%u, sdiv=%u, sdm_en=%u, k_sign=%u, k=%u, lc=%u\n",
|
||||
cfg->pms_mdiv, cfg->pms_sdiv + 1, cfg->sdm_en,
|
||||
cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno);
|
||||
dev_dbg(hdptx->dev, "%s rate=%llu mdiv=%u sdiv=%u sdm_en=%u k_sign=%u k=%u lc=%u\n",
|
||||
__func__, hdptx->hdmi_cfg.tmds_char_rate, cfg->pms_mdiv, cfg->pms_sdiv + 1,
|
||||
cfg->sdm_en, cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno);
|
||||
|
||||
rk_hdptx_pre_power_up(hdptx);
|
||||
|
||||
|
@ -1061,20 +1030,26 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx,
|
|||
regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_POSTDIV_SEL_MASK,
|
||||
FIELD_PREP(PLL_PCG_POSTDIV_SEL_MASK, cfg->pms_sdiv));
|
||||
|
||||
regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_SEL_MASK,
|
||||
FIELD_PREP(PLL_PCG_CLK_SEL_MASK, (hdptx->hdmi_cfg.bpc - 8) >> 1));
|
||||
|
||||
regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN_MASK,
|
||||
FIELD_PREP(PLL_PCG_CLK_EN_MASK, 0x1));
|
||||
|
||||
return rk_hdptx_post_enable_pll(hdptx);
|
||||
ret = rk_hdptx_post_enable_pll(hdptx);
|
||||
if (!ret)
|
||||
hdptx->hw_rate = hdptx->hdmi_cfg.tmds_char_rate;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx,
|
||||
unsigned int rate)
|
||||
static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx)
|
||||
{
|
||||
rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_sb_init_seq);
|
||||
|
||||
regmap_write(hdptx->regmap, LNTOP_REG(0200), 0x06);
|
||||
|
||||
if (rate >= 3400000) {
|
||||
if (hdptx->hdmi_cfg.tmds_char_rate > HDMI14_MAX_RATE) {
|
||||
/* For 1/40 bitrate clk */
|
||||
rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_highbr_seq);
|
||||
} else {
|
||||
|
@ -1126,8 +1101,7 @@ static void rk_hdptx_dp_reset(struct rk_hdptx_phy *hdptx)
|
|||
HDPTX_I_BGR_EN << 16 | FIELD_PREP(HDPTX_I_BGR_EN, 0x0));
|
||||
}
|
||||
|
||||
static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx,
|
||||
unsigned int rate)
|
||||
static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx)
|
||||
{
|
||||
enum phy_mode mode = phy_get_mode(hdptx->phy);
|
||||
u32 status;
|
||||
|
@ -1146,11 +1120,9 @@ static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx,
|
|||
if (mode == PHY_MODE_DP) {
|
||||
rk_hdptx_dp_reset(hdptx);
|
||||
} else {
|
||||
if (rate) {
|
||||
ret = rk_hdptx_ropll_tmds_cmn_config(hdptx, rate);
|
||||
if (ret)
|
||||
goto dec_usage;
|
||||
}
|
||||
ret = rk_hdptx_ropll_tmds_cmn_config(hdptx);
|
||||
if (ret)
|
||||
goto dec_usage;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1445,21 +1417,26 @@ static int rk_hdptx_dp_aux_init(struct rk_hdptx_phy *hdptx)
|
|||
static int rk_hdptx_phy_power_on(struct phy *phy)
|
||||
{
|
||||
struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
|
||||
int bus_width = phy_get_bus_width(hdptx->phy);
|
||||
enum phy_mode mode = phy_get_mode(phy);
|
||||
int ret, lane;
|
||||
|
||||
/*
|
||||
* FIXME: Temporary workaround to pass pixel_clk_rate
|
||||
* from the HDMI bridge driver until phy_configure_opts_hdmi
|
||||
* becomes available in the PHY API.
|
||||
*/
|
||||
unsigned int rate = bus_width & 0xfffffff;
|
||||
if (mode != PHY_MODE_DP) {
|
||||
if (!hdptx->hdmi_cfg.tmds_char_rate) {
|
||||
/*
|
||||
* FIXME: Temporary workaround to setup TMDS char rate
|
||||
* from the RK DW HDMI QP bridge driver.
|
||||
* Will be removed as soon the switch to the HDMI PHY
|
||||
* configuration API has been completed on both ends.
|
||||
*/
|
||||
hdptx->hdmi_cfg.tmds_char_rate = phy_get_bus_width(hdptx->phy) & 0xfffffff;
|
||||
hdptx->hdmi_cfg.tmds_char_rate *= 100;
|
||||
}
|
||||
|
||||
dev_dbg(hdptx->dev, "%s bus_width=%x rate=%u\n",
|
||||
__func__, bus_width, rate);
|
||||
dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
|
||||
hdptx->hdmi_cfg.tmds_char_rate, hdptx->hdmi_cfg.bpc);
|
||||
}
|
||||
|
||||
ret = rk_hdptx_phy_consumer_get(hdptx, rate);
|
||||
ret = rk_hdptx_phy_consumer_get(hdptx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1490,7 +1467,7 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
|
|||
regmap_write(hdptx->grf, GRF_HDPTX_CON0,
|
||||
HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0));
|
||||
|
||||
ret = rk_hdptx_ropll_tmds_mode_config(hdptx, rate);
|
||||
ret = rk_hdptx_ropll_tmds_mode_config(hdptx);
|
||||
if (ret)
|
||||
rk_hdptx_phy_consumer_put(hdptx, true);
|
||||
}
|
||||
|
@ -1505,8 +1482,40 @@ static int rk_hdptx_phy_power_off(struct phy *phy)
|
|||
return rk_hdptx_phy_consumer_put(hdptx, false);
|
||||
}
|
||||
|
||||
static int rk_hdptx_phy_verify_config(struct rk_hdptx_phy *hdptx,
|
||||
struct phy_configure_opts_dp *dp)
|
||||
static int rk_hdptx_phy_verify_hdmi_config(struct rk_hdptx_phy *hdptx,
|
||||
struct phy_configure_opts_hdmi *hdmi)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!hdmi->tmds_char_rate || hdmi->tmds_char_rate > HDMI20_MAX_RATE)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
|
||||
if (hdmi->tmds_char_rate == ropll_tmds_cfg[i].rate)
|
||||
break;
|
||||
|
||||
if (i == ARRAY_SIZE(ropll_tmds_cfg) &&
|
||||
!rk_hdptx_phy_clk_pll_calc(hdmi->tmds_char_rate, NULL))
|
||||
return -EINVAL;
|
||||
|
||||
if (!hdmi->bpc)
|
||||
hdmi->bpc = 8;
|
||||
|
||||
switch (hdmi->bpc) {
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
case 16:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk_hdptx_phy_verify_dp_config(struct rk_hdptx_phy *hdptx,
|
||||
struct phy_configure_opts_dp *dp)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -1766,12 +1775,23 @@ static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opt
|
|||
enum phy_mode mode = phy_get_mode(phy);
|
||||
int ret;
|
||||
|
||||
if (mode != PHY_MODE_DP)
|
||||
return 0;
|
||||
if (mode != PHY_MODE_DP) {
|
||||
ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi);
|
||||
if (ret) {
|
||||
dev_err(hdptx->dev, "invalid hdmi params for phy configure\n");
|
||||
} else {
|
||||
hdptx->hdmi_cfg = opts->hdmi;
|
||||
hdptx->restrict_rate_change = true;
|
||||
}
|
||||
|
||||
ret = rk_hdptx_phy_verify_config(hdptx, &opts->dp);
|
||||
dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
|
||||
hdptx->hdmi_cfg.tmds_char_rate, hdptx->hdmi_cfg.bpc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rk_hdptx_phy_verify_dp_config(hdptx, &opts->dp);
|
||||
if (ret) {
|
||||
dev_err(hdptx->dev, "invalid params for phy configure\n");
|
||||
dev_err(hdptx->dev, "invalid dp params for phy configure\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1803,10 +1823,22 @@ static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opt
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rk_hdptx_phy_validate(struct phy *phy, enum phy_mode mode,
|
||||
int submode, union phy_configure_opts *opts)
|
||||
{
|
||||
struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
|
||||
|
||||
if (mode != PHY_MODE_DP)
|
||||
return rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi);
|
||||
|
||||
return rk_hdptx_phy_verify_dp_config(hdptx, &opts->dp);
|
||||
}
|
||||
|
||||
static const struct phy_ops rk_hdptx_phy_ops = {
|
||||
.power_on = rk_hdptx_phy_power_on,
|
||||
.power_off = rk_hdptx_phy_power_off,
|
||||
.configure = rk_hdptx_phy_configure,
|
||||
.validate = rk_hdptx_phy_validate,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
@ -1819,7 +1851,7 @@ static int rk_hdptx_phy_clk_prepare(struct clk_hw *hw)
|
|||
{
|
||||
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
|
||||
|
||||
return rk_hdptx_phy_consumer_get(hdptx, hdptx->rate / 100);
|
||||
return rk_hdptx_phy_consumer_get(hdptx);
|
||||
}
|
||||
|
||||
static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw)
|
||||
|
@ -1834,27 +1866,37 @@ static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw,
|
|||
{
|
||||
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
|
||||
|
||||
return hdptx->rate;
|
||||
return hdptx->hw_rate;
|
||||
}
|
||||
|
||||
static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
u32 bit_rate = rate / 100;
|
||||
int i;
|
||||
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
|
||||
|
||||
if (rate > HDMI20_MAX_RATE)
|
||||
return rate;
|
||||
/*
|
||||
* FIXME: Temporarily allow altering TMDS char rate via CCF.
|
||||
* To be dropped as soon as the RK DW HDMI QP bridge driver
|
||||
* switches to make use of phy_configure().
|
||||
*/
|
||||
if (!hdptx->restrict_rate_change && rate != hdptx->hdmi_cfg.tmds_char_rate) {
|
||||
struct phy_configure_opts_hdmi hdmi = {
|
||||
.tmds_char_rate = rate,
|
||||
};
|
||||
int ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &hdmi);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
|
||||
if (bit_rate == ropll_tmds_cfg[i].bit_rate)
|
||||
break;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (i == ARRAY_SIZE(ropll_tmds_cfg) &&
|
||||
!rk_hdptx_phy_clk_pll_calc(bit_rate, NULL))
|
||||
return -EINVAL;
|
||||
hdptx->hdmi_cfg = hdmi;
|
||||
}
|
||||
|
||||
return rate;
|
||||
/*
|
||||
* The TMDS char rate shall be adjusted via phy_configure() only,
|
||||
* hence ensure rk_hdptx_phy_clk_set_rate() won't be invoked with
|
||||
* a different rate argument.
|
||||
*/
|
||||
return hdptx->hdmi_cfg.tmds_char_rate;
|
||||
}
|
||||
|
||||
static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
@ -1862,7 +1904,21 @@ static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
{
|
||||
struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
|
||||
|
||||
return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate / 100);
|
||||
/* Revert any unlikely TMDS char rate change since round_rate() */
|
||||
if (hdptx->hdmi_cfg.tmds_char_rate != rate) {
|
||||
dev_warn(hdptx->dev, "Reverting unexpected rate change from %lu to %llu\n",
|
||||
rate, hdptx->hdmi_cfg.tmds_char_rate);
|
||||
hdptx->hdmi_cfg.tmds_char_rate = rate;
|
||||
}
|
||||
|
||||
/*
|
||||
* The TMDS char rate would be normally programmed in HW during
|
||||
* phy_ops.power_on() or clk_ops.prepare() callbacks, but it might
|
||||
* happen that the former gets fired too late, i.e. after this call,
|
||||
* while the latter being executed only once, i.e. when clock remains
|
||||
* in the prepared state during rate changes.
|
||||
*/
|
||||
return rk_hdptx_ropll_tmds_cmn_config(hdptx);
|
||||
}
|
||||
|
||||
static const struct clk_ops hdptx_phy_clk_ops = {
|
||||
|
@ -1925,6 +1981,7 @@ static int rk_hdptx_phy_runtime_resume(struct device *dev)
|
|||
|
||||
static int rk_hdptx_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct rk_hdptx_phy_cfg *cfgs;
|
||||
struct phy_provider *phy_provider;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rk_hdptx_phy *hdptx;
|
||||
|
@ -1937,20 +1994,21 @@ static int rk_hdptx_phy_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
hdptx->dev = dev;
|
||||
hdptx->hdmi_cfg.bpc = 8;
|
||||
|
||||
regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(regs))
|
||||
return dev_err_probe(dev, PTR_ERR(regs),
|
||||
"Failed to ioremap resource\n");
|
||||
|
||||
hdptx->cfgs = device_get_match_data(dev);
|
||||
if (!hdptx->cfgs)
|
||||
cfgs = device_get_match_data(dev);
|
||||
if (!cfgs)
|
||||
return dev_err_probe(dev, -EINVAL, "missing match data\n");
|
||||
|
||||
/* find the phy-id from the io address */
|
||||
hdptx->phy_id = -ENODEV;
|
||||
for (id = 0; id < hdptx->cfgs->num_phys; id++) {
|
||||
if (res->start == hdptx->cfgs->phy_ids[id]) {
|
||||
for (id = 0; id < cfgs->num_phys; id++) {
|
||||
if (res->start == cfgs->phy_ids[id]) {
|
||||
hdptx->phy_id = id;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ config PHY_EXYNOS5_USBDRD
|
|||
depends on USB_DWC3_EXYNOS
|
||||
select GENERIC_PHY
|
||||
select MFD_SYSCON
|
||||
default y
|
||||
default ARCH_EXYNOS
|
||||
help
|
||||
Enable USB DRD PHY support for Exynos 5 SoC series.
|
||||
This driver provides PHY interface for USB 3.0 DRD controller
|
||||
|
|
|
@ -36,14 +36,40 @@
|
|||
#define EXYNOS5_FSEL_26MHZ 0x6
|
||||
#define EXYNOS5_FSEL_50MHZ 0x7
|
||||
|
||||
/* USB 3.2 DRD 4nm PHY link controller registers */
|
||||
#define EXYNOS2200_DRD_CLKRST 0x0c
|
||||
#define EXYNOS2200_CLKRST_LINK_PCLK_SEL BIT(1)
|
||||
|
||||
#define EXYNOS2200_DRD_UTMI 0x10
|
||||
#define EXYNOS2200_UTMI_FORCE_VBUSVALID BIT(1)
|
||||
#define EXYNOS2200_UTMI_FORCE_BVALID BIT(0)
|
||||
|
||||
#define EXYNOS2200_DRD_HSP_MISC 0x114
|
||||
#define HSP_MISC_SET_REQ_IN2 BIT(4)
|
||||
#define HSP_MISC_RES_TUNE GENMASK(1, 0)
|
||||
#define RES_TUNE_PHY1_PHY2 0x1
|
||||
#define RES_TUNE_PHY1 0x2
|
||||
#define RES_TUNE_PHY2 0x3
|
||||
|
||||
/* Exynos5: USB 3.0 DRD PHY registers */
|
||||
#define EXYNOS5_DRD_LINKSYSTEM 0x04
|
||||
#define LINKSYSTEM_XHCI_VERSION_CONTROL BIT(27)
|
||||
#define LINKSYSTEM_FLADJ_MASK (0x3f << 1)
|
||||
#define LINKSYSTEM_FLADJ(_x) ((_x) << 1)
|
||||
#define LINKSYSTEM_FORCE_VBUSVALID BIT(8)
|
||||
#define LINKSYSTEM_FORCE_BVALID BIT(7)
|
||||
#define LINKSYSTEM_FLADJ GENMASK(6, 1)
|
||||
|
||||
#define EXYNOS5_DRD_PHYUTMI 0x08
|
||||
#define PHYUTMI_UTMI_SUSPEND_COM_N BIT(12)
|
||||
#define PHYUTMI_UTMI_L1_SUSPEND_COM_N BIT(11)
|
||||
#define PHYUTMI_VBUSVLDEXTSEL BIT(10)
|
||||
#define PHYUTMI_VBUSVLDEXT BIT(9)
|
||||
#define PHYUTMI_TXBITSTUFFENH BIT(8)
|
||||
#define PHYUTMI_TXBITSTUFFEN BIT(7)
|
||||
#define PHYUTMI_OTGDISABLE BIT(6)
|
||||
#define PHYUTMI_IDPULLUP BIT(5)
|
||||
#define PHYUTMI_DRVVBUS BIT(4)
|
||||
#define PHYUTMI_DPPULLDOWN BIT(3)
|
||||
#define PHYUTMI_DMPULLDOWN BIT(2)
|
||||
#define PHYUTMI_FORCESUSPEND BIT(1)
|
||||
#define PHYUTMI_FORCESLEEP BIT(0)
|
||||
|
||||
|
@ -51,30 +77,27 @@
|
|||
|
||||
#define EXYNOS5_DRD_PHYCLKRST 0x10
|
||||
#define PHYCLKRST_EN_UTMISUSPEND BIT(31)
|
||||
#define PHYCLKRST_SSC_REFCLKSEL_MASK (0xff << 23)
|
||||
#define PHYCLKRST_SSC_REFCLKSEL(_x) ((_x) << 23)
|
||||
#define PHYCLKRST_SSC_RANGE_MASK (0x03 << 21)
|
||||
#define PHYCLKRST_SSC_RANGE(_x) ((_x) << 21)
|
||||
#define PHYCLKRST_SSC_REFCLKSEL GENMASK(30, 23)
|
||||
#define PHYCLKRST_SSC_RANGE GENMASK(22, 21)
|
||||
#define PHYCLKRST_SSC_EN BIT(20)
|
||||
#define PHYCLKRST_REF_SSP_EN BIT(19)
|
||||
#define PHYCLKRST_REF_CLKDIV2 BIT(18)
|
||||
#define PHYCLKRST_MPLL_MULTIPLIER_MASK (0x7f << 11)
|
||||
#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF (0x19 << 11)
|
||||
#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF (0x32 << 11)
|
||||
#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF (0x68 << 11)
|
||||
#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF (0x7d << 11)
|
||||
#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF (0x02 << 11)
|
||||
#define PHYCLKRST_FSEL_PIPE_MASK (0x7 << 8)
|
||||
#define PHYCLKRST_FSEL_UTMI_MASK (0x7 << 5)
|
||||
#define PHYCLKRST_FSEL(_x) ((_x) << 5)
|
||||
#define PHYCLKRST_FSEL_PAD_100MHZ (0x27 << 5)
|
||||
#define PHYCLKRST_FSEL_PAD_24MHZ (0x2a << 5)
|
||||
#define PHYCLKRST_FSEL_PAD_20MHZ (0x31 << 5)
|
||||
#define PHYCLKRST_FSEL_PAD_19_2MHZ (0x38 << 5)
|
||||
#define PHYCLKRST_MPLL_MULTIPLIER GENMASK(17, 11)
|
||||
#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF 0x19
|
||||
#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF 0x32
|
||||
#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF 0x68
|
||||
#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF 0x7d
|
||||
#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF 0x02
|
||||
#define PHYCLKRST_FSEL_PIPE GENMASK(10, 8)
|
||||
#define PHYCLKRST_FSEL_UTMI GENMASK(7, 5)
|
||||
#define PHYCLKRST_FSEL_PAD_100MHZ 0x27
|
||||
#define PHYCLKRST_FSEL_PAD_24MHZ 0x2a
|
||||
#define PHYCLKRST_FSEL_PAD_20MHZ 0x31
|
||||
#define PHYCLKRST_FSEL_PAD_19_2MHZ 0x38
|
||||
#define PHYCLKRST_RETENABLEN BIT(4)
|
||||
#define PHYCLKRST_REFCLKSEL_MASK (0x03 << 2)
|
||||
#define PHYCLKRST_REFCLKSEL_PAD_REFCLK (0x2 << 2)
|
||||
#define PHYCLKRST_REFCLKSEL_EXT_REFCLK (0x3 << 2)
|
||||
#define PHYCLKRST_REFCLKSEL GENMASK(3, 2)
|
||||
#define PHYCLKRST_REFCLKSEL_PAD_REFCLK 0x2
|
||||
#define PHYCLKRST_REFCLKSEL_EXT_REFCLK 0x3
|
||||
#define PHYCLKRST_PORTRESET BIT(1)
|
||||
#define PHYCLKRST_COMMONONN BIT(0)
|
||||
|
||||
|
@ -83,22 +106,32 @@
|
|||
#define PHYREG0_SSC_RANGE BIT(20)
|
||||
#define PHYREG0_CR_WRITE BIT(19)
|
||||
#define PHYREG0_CR_READ BIT(18)
|
||||
#define PHYREG0_CR_DATA_IN(_x) ((_x) << 2)
|
||||
#define PHYREG0_CR_DATA_IN GENMASK(17, 2)
|
||||
#define PHYREG0_CR_CAP_DATA BIT(1)
|
||||
#define PHYREG0_CR_CAP_ADDR BIT(0)
|
||||
|
||||
#define EXYNOS5_DRD_PHYREG1 0x18
|
||||
#define PHYREG1_CR_DATA_OUT(_x) ((_x) << 1)
|
||||
#define PHYREG0_CR_DATA_OUT GENMASK(16, 1)
|
||||
#define PHYREG1_CR_ACK BIT(0)
|
||||
|
||||
#define EXYNOS5_DRD_PHYPARAM0 0x1c
|
||||
#define PHYPARAM0_REF_USE_PAD BIT(31)
|
||||
#define PHYPARAM0_REF_LOSLEVEL_MASK (0x1f << 26)
|
||||
#define PHYPARAM0_REF_LOSLEVEL (0x9 << 26)
|
||||
#define PHYPARAM0_REF_LOSLEVEL GENMASK(30, 26)
|
||||
#define PHYPARAM0_REF_LOSLEVEL_VAL 0x9
|
||||
#define PHYPARAM0_TXVREFTUNE GENMASK(25, 22)
|
||||
#define PHYPARAM0_TXRISETUNE GENMASK(21, 20)
|
||||
#define PHYPARAM0_TXRESTUNE GENMASK(19, 18)
|
||||
#define PHYPARAM0_TXPREEMPPULSETUNE BIT(17)
|
||||
#define PHYPARAM0_TXPREEMPAMPTUNE GENMASK(16, 15)
|
||||
#define PHYPARAM0_TXHSXVTUNE GENMASK(14, 13)
|
||||
#define PHYPARAM0_TXFSLSTUNE GENMASK(12, 9)
|
||||
#define PHYPARAM0_SQRXTUNE GENMASK(8, 6)
|
||||
#define PHYPARAM0_OTGTUNE GENMASK(5, 3)
|
||||
#define PHYPARAM0_COMPDISTUNE GENMASK(2, 0)
|
||||
|
||||
#define EXYNOS5_DRD_PHYPARAM1 0x20
|
||||
#define PHYPARAM1_PCS_TXDEEMPH_MASK (0x1f << 0)
|
||||
#define PHYPARAM1_PCS_TXDEEMPH (0x1c)
|
||||
#define PHYPARAM1_PCS_TXDEEMPH GENMASK(4, 0)
|
||||
#define PHYPARAM1_PCS_TXDEEMPH_VAL 0x1c
|
||||
|
||||
#define EXYNOS5_DRD_PHYTERM 0x24
|
||||
|
||||
|
@ -114,6 +147,12 @@
|
|||
#define EXYNOS5_DRD_PHYRESUME 0x34
|
||||
|
||||
#define EXYNOS5_DRD_LINKPORT 0x44
|
||||
#define LINKPORT_HOST_U3_PORT_DISABLE BIT(8)
|
||||
#define LINKPORT_HOST_U2_PORT_DISABLE BIT(7)
|
||||
#define LINKPORT_HOST_PORT_OVCR_U3 BIT(5)
|
||||
#define LINKPORT_HOST_PORT_OVCR_U2 BIT(4)
|
||||
#define LINKPORT_HOST_PORT_OVCR_U3_SEL BIT(3)
|
||||
#define LINKPORT_HOST_PORT_OVCR_U2_SEL BIT(2)
|
||||
|
||||
/* USB 3.0 DRD PHY SS Function Control Reg; accessed by CR_PORT */
|
||||
#define EXYNOS5_DRD_PHYSS_LOSLEVEL_OVRD_IN (0x15)
|
||||
|
@ -134,13 +173,31 @@
|
|||
#define LANE0_TX_DEBUG_RXDET_MEAS_TIME_62M5 (0x20 << 4)
|
||||
#define LANE0_TX_DEBUG_RXDET_MEAS_TIME_96M_100M (0x40 << 4)
|
||||
|
||||
/* Exynos7870: USB DRD PHY registers */
|
||||
#define EXYNOS7870_DRD_PHYPCSVAL 0x3C
|
||||
#define PHYPCSVAL_PCS_RX_LOS_MASK GENMASK(9, 0)
|
||||
|
||||
#define EXYNOS7870_DRD_PHYPARAM2 0x50
|
||||
#define PHYPARAM2_TX_VBOOST_LVL GENMASK(6, 4)
|
||||
#define PHYPARAM2_LOS_BIAS GENMASK(2, 0)
|
||||
|
||||
#define EXYNOS7870_DRD_HSPHYCTRL 0x54
|
||||
#define HSPHYCTRL_PHYSWRSTALL BIT(31)
|
||||
#define HSPHYCTRL_SIDDQ BIT(6)
|
||||
#define HSPHYCTRL_PHYSWRST BIT(0)
|
||||
|
||||
#define EXYNOS7870_DRD_HSPHYPLLTUNE 0x70
|
||||
#define HSPHYPLLTUNE_PLL_B_TUNE BIT(6)
|
||||
#define HSPHYPLLTUNE_PLL_I_TUNE GENMASK(5, 4)
|
||||
#define HSPHYPLLTUNE_PLL_P_TUNE GENMASK(3, 0)
|
||||
|
||||
/* Exynos850: USB DRD PHY registers */
|
||||
#define EXYNOS850_DRD_LINKCTRL 0x04
|
||||
#define LINKCTRL_FORCE_RXELECIDLE BIT(18)
|
||||
#define LINKCTRL_FORCE_PHYSTATUS BIT(17)
|
||||
#define LINKCTRL_FORCE_PIPE_EN BIT(16)
|
||||
#define LINKCTRL_FORCE_QACT BIT(8)
|
||||
#define LINKCTRL_BUS_FILTER_BYPASS(_x) ((_x) << 4)
|
||||
#define LINKCTRL_BUS_FILTER_BYPASS GENMASK(7, 4)
|
||||
|
||||
#define EXYNOS850_DRD_LINKPORT 0x08
|
||||
#define LINKPORT_HOST_NUM_U3 GENMASK(19, 16)
|
||||
|
@ -389,6 +446,7 @@ struct exynos5_usbdrd_phy_drvdata {
|
|||
* @clks: clocks for register access
|
||||
* @core_clks: core clocks for phy (ref, pipe3, utmi+, ITP, etc. as required)
|
||||
* @drv_data: pointer to SoC level driver data structure
|
||||
* @hs_phy: pointer to non-Samsung IP high-speed phy controller
|
||||
* @phy_mutex: mutex protecting phy_init/exit & TCPC callbacks
|
||||
* @phys: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY
|
||||
* instances each with its 'phy' and 'phy_cfg'.
|
||||
|
@ -406,6 +464,7 @@ struct exynos5_usbdrd_phy {
|
|||
struct clk_bulk_data *clks;
|
||||
struct clk_bulk_data *core_clks;
|
||||
const struct exynos5_usbdrd_phy_drvdata *drv_data;
|
||||
struct phy *hs_phy;
|
||||
struct mutex phy_mutex;
|
||||
struct phy_usb_instance {
|
||||
struct phy *phy;
|
||||
|
@ -497,29 +556,33 @@ exynos5_usbdrd_pipe3_set_refclk(struct phy_usb_instance *inst)
|
|||
reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
|
||||
|
||||
/* Use EXTREFCLK as ref clock */
|
||||
reg &= ~PHYCLKRST_REFCLKSEL_MASK;
|
||||
reg |= PHYCLKRST_REFCLKSEL_EXT_REFCLK;
|
||||
reg &= ~PHYCLKRST_REFCLKSEL;
|
||||
reg |= FIELD_PREP(PHYCLKRST_REFCLKSEL, PHYCLKRST_REFCLKSEL_EXT_REFCLK);
|
||||
|
||||
/* FSEL settings corresponding to reference clock */
|
||||
reg &= ~(PHYCLKRST_FSEL_PIPE_MASK |
|
||||
PHYCLKRST_MPLL_MULTIPLIER_MASK |
|
||||
PHYCLKRST_SSC_REFCLKSEL_MASK);
|
||||
reg &= ~(PHYCLKRST_FSEL_PIPE |
|
||||
PHYCLKRST_MPLL_MULTIPLIER |
|
||||
PHYCLKRST_SSC_REFCLKSEL);
|
||||
switch (phy_drd->extrefclk) {
|
||||
case EXYNOS5_FSEL_50MHZ:
|
||||
reg |= (PHYCLKRST_MPLL_MULTIPLIER_50M_REF |
|
||||
PHYCLKRST_SSC_REFCLKSEL(0x00));
|
||||
reg |= (FIELD_PREP(PHYCLKRST_SSC_REFCLKSEL, 0x00) |
|
||||
FIELD_PREP(PHYCLKRST_MPLL_MULTIPLIER,
|
||||
PHYCLKRST_MPLL_MULTIPLIER_50M_REF));
|
||||
break;
|
||||
case EXYNOS5_FSEL_24MHZ:
|
||||
reg |= (PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
|
||||
PHYCLKRST_SSC_REFCLKSEL(0x88));
|
||||
reg |= (FIELD_PREP(PHYCLKRST_SSC_REFCLKSEL, 0x88) |
|
||||
FIELD_PREP(PHYCLKRST_MPLL_MULTIPLIER,
|
||||
PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF));
|
||||
break;
|
||||
case EXYNOS5_FSEL_20MHZ:
|
||||
reg |= (PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF |
|
||||
PHYCLKRST_SSC_REFCLKSEL(0x00));
|
||||
reg |= (FIELD_PREP(PHYCLKRST_SSC_REFCLKSEL, 0x00) |
|
||||
FIELD_PREP(PHYCLKRST_MPLL_MULTIPLIER,
|
||||
PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF));
|
||||
break;
|
||||
case EXYNOS5_FSEL_19MHZ2:
|
||||
reg |= (PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF |
|
||||
PHYCLKRST_SSC_REFCLKSEL(0x88));
|
||||
reg |= (FIELD_PREP(PHYCLKRST_SSC_REFCLKSEL, 0x88) |
|
||||
FIELD_PREP(PHYCLKRST_MPLL_MULTIPLIER,
|
||||
PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF));
|
||||
break;
|
||||
default:
|
||||
dev_dbg(phy_drd->dev, "unsupported ref clk\n");
|
||||
|
@ -542,13 +605,13 @@ exynos5_usbdrd_utmi_set_refclk(struct phy_usb_instance *inst)
|
|||
/* restore any previous reference clock settings */
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
|
||||
|
||||
reg &= ~PHYCLKRST_REFCLKSEL_MASK;
|
||||
reg |= PHYCLKRST_REFCLKSEL_EXT_REFCLK;
|
||||
reg &= ~PHYCLKRST_REFCLKSEL;
|
||||
reg |= FIELD_PREP(PHYCLKRST_REFCLKSEL, PHYCLKRST_REFCLKSEL_EXT_REFCLK);
|
||||
|
||||
reg &= ~(PHYCLKRST_FSEL_UTMI_MASK |
|
||||
PHYCLKRST_MPLL_MULTIPLIER_MASK |
|
||||
PHYCLKRST_SSC_REFCLKSEL_MASK);
|
||||
reg |= PHYCLKRST_FSEL(phy_drd->extrefclk);
|
||||
reg &= ~(PHYCLKRST_FSEL_UTMI |
|
||||
PHYCLKRST_MPLL_MULTIPLIER |
|
||||
PHYCLKRST_SSC_REFCLKSEL);
|
||||
reg |= FIELD_PREP(PHYCLKRST_FSEL_UTMI, phy_drd->extrefclk);
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
@ -598,8 +661,8 @@ static void exynos5_usbdrd_pipe3_init(struct exynos5_usbdrd_phy *phy_drd)
|
|||
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1);
|
||||
/* Set Tx De-Emphasis level */
|
||||
reg &= ~PHYPARAM1_PCS_TXDEEMPH_MASK;
|
||||
reg |= PHYPARAM1_PCS_TXDEEMPH;
|
||||
reg &= ~PHYPARAM1_PCS_TXDEEMPH;
|
||||
reg |= FIELD_PREP(PHYPARAM1_PCS_TXDEEMPH, PHYPARAM1_PCS_TXDEEMPH_VAL);
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1);
|
||||
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST);
|
||||
|
@ -749,14 +812,14 @@ static void exynos5_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
|
|||
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0);
|
||||
/* Set Loss-of-Signal Detector sensitivity */
|
||||
reg &= ~PHYPARAM0_REF_LOSLEVEL_MASK;
|
||||
reg |= PHYPARAM0_REF_LOSLEVEL;
|
||||
reg &= ~PHYPARAM0_REF_LOSLEVEL;
|
||||
reg |= FIELD_PREP(PHYPARAM0_REF_LOSLEVEL, PHYPARAM0_REF_LOSLEVEL_VAL);
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0);
|
||||
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1);
|
||||
/* Set Tx De-Emphasis level */
|
||||
reg &= ~PHYPARAM1_PCS_TXDEEMPH_MASK;
|
||||
reg |= PHYPARAM1_PCS_TXDEEMPH;
|
||||
reg &= ~PHYPARAM1_PCS_TXDEEMPH;
|
||||
reg |= FIELD_PREP(PHYPARAM1_PCS_TXDEEMPH, PHYPARAM1_PCS_TXDEEMPH_VAL);
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1);
|
||||
|
||||
/* UTMI Power Control */
|
||||
|
@ -787,7 +850,7 @@ static int exynos5_usbdrd_phy_init(struct phy *phy)
|
|||
* See xHCI 1.0 spec, 5.2.4
|
||||
*/
|
||||
reg = LINKSYSTEM_XHCI_VERSION_CONTROL |
|
||||
LINKSYSTEM_FLADJ(0x20);
|
||||
FIELD_PREP(LINKSYSTEM_FLADJ, 0x20);
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_LINKSYSTEM);
|
||||
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0);
|
||||
|
@ -946,26 +1009,24 @@ static int crport_handshake(struct exynos5_usbdrd_phy *phy_drd,
|
|||
static int crport_ctrl_write(struct exynos5_usbdrd_phy *phy_drd,
|
||||
u32 addr, u32 data)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
/* Write Address */
|
||||
writel(PHYREG0_CR_DATA_IN(addr),
|
||||
phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0);
|
||||
ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(addr),
|
||||
PHYREG0_CR_CAP_ADDR);
|
||||
val = FIELD_PREP(PHYREG0_CR_DATA_IN, addr);
|
||||
writel(val, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0);
|
||||
ret = crport_handshake(phy_drd, val, PHYREG0_CR_CAP_ADDR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Write Data */
|
||||
writel(PHYREG0_CR_DATA_IN(data),
|
||||
phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0);
|
||||
ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(data),
|
||||
PHYREG0_CR_CAP_DATA);
|
||||
val = FIELD_PREP(PHYREG0_CR_DATA_IN, data);
|
||||
writel(val, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0);
|
||||
ret = crport_handshake(phy_drd, val, PHYREG0_CR_CAP_DATA);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(data),
|
||||
PHYREG0_CR_WRITE);
|
||||
ret = crport_handshake(phy_drd, val, PHYREG0_CR_WRITE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1075,6 +1136,315 @@ static const struct phy_ops exynos5_usbdrd_phy_ops = {
|
|||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void exynos7870_usbdrd_phy_isol(struct phy_usb_instance *inst,
|
||||
bool isolate)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (!inst->reg_pmu)
|
||||
return;
|
||||
|
||||
val = isolate ? 0 : EXYNOS7870_USB2PHY_ENABLE;
|
||||
|
||||
regmap_update_bits(inst->reg_pmu, inst->pmu_offset,
|
||||
EXYNOS7870_USB2PHY_ENABLE, val);
|
||||
}
|
||||
|
||||
static void exynos7870_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
|
||||
/* Use PADREFCLK as ref clock */
|
||||
reg &= ~PHYCLKRST_REFCLKSEL;
|
||||
reg |= FIELD_PREP(PHYCLKRST_REFCLKSEL, PHYCLKRST_REFCLKSEL_PAD_REFCLK);
|
||||
/* Select ref clock rate */
|
||||
reg &= ~PHYCLKRST_FSEL_UTMI;
|
||||
reg &= ~PHYCLKRST_FSEL_PIPE;
|
||||
reg |= FIELD_PREP(PHYCLKRST_FSEL_UTMI, phy_drd->extrefclk);
|
||||
/* Enable suspend and reset the port */
|
||||
reg |= PHYCLKRST_EN_UTMISUSPEND;
|
||||
reg |= PHYCLKRST_COMMONONN;
|
||||
reg |= PHYCLKRST_PORTRESET;
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
|
||||
udelay(10);
|
||||
|
||||
/* Clear the port reset bit */
|
||||
reg &= ~PHYCLKRST_PORTRESET;
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST);
|
||||
|
||||
/* Change PHY PLL tune value */
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYPLLTUNE);
|
||||
if (phy_drd->extrefclk == EXYNOS5_FSEL_24MHZ)
|
||||
reg |= HSPHYPLLTUNE_PLL_B_TUNE;
|
||||
else
|
||||
reg &= ~HSPHYPLLTUNE_PLL_B_TUNE;
|
||||
reg &= ~HSPHYPLLTUNE_PLL_P_TUNE;
|
||||
reg |= FIELD_PREP(HSPHYPLLTUNE_PLL_P_TUNE, 14);
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYPLLTUNE);
|
||||
|
||||
/* High-Speed PHY control */
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL);
|
||||
reg &= ~HSPHYCTRL_SIDDQ;
|
||||
reg &= ~HSPHYCTRL_PHYSWRST;
|
||||
reg &= ~HSPHYCTRL_PHYSWRSTALL;
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL);
|
||||
udelay(500);
|
||||
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_LINKSYSTEM);
|
||||
/*
|
||||
* Setting the Frame length Adj value[6:1] to default 0x20
|
||||
* See xHCI 1.0 spec, 5.2.4
|
||||
*/
|
||||
reg |= LINKSYSTEM_XHCI_VERSION_CONTROL;
|
||||
reg &= ~LINKSYSTEM_FLADJ;
|
||||
reg |= FIELD_PREP(LINKSYSTEM_FLADJ, 0x20);
|
||||
/* Set VBUSVALID signal as the VBUS pad is not used */
|
||||
reg |= LINKSYSTEM_FORCE_BVALID;
|
||||
reg |= LINKSYSTEM_FORCE_VBUSVALID;
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_LINKSYSTEM);
|
||||
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI);
|
||||
/* Release force_sleep & force_suspend */
|
||||
reg &= ~PHYUTMI_FORCESLEEP;
|
||||
reg &= ~PHYUTMI_FORCESUSPEND;
|
||||
/* DP/DM pull down control */
|
||||
reg &= ~PHYUTMI_DMPULLDOWN;
|
||||
reg &= ~PHYUTMI_DPPULLDOWN;
|
||||
reg &= ~PHYUTMI_DRVVBUS;
|
||||
/* Set DP-pull up as the VBUS pad is not used */
|
||||
reg |= PHYUTMI_VBUSVLDEXTSEL;
|
||||
reg |= PHYUTMI_VBUSVLDEXT;
|
||||
/* Disable OTG block and VBUS valid comparator */
|
||||
reg |= PHYUTMI_OTGDISABLE;
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI);
|
||||
|
||||
/* Configure OVC IO usage */
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_LINKPORT);
|
||||
reg |= LINKPORT_HOST_PORT_OVCR_U3_SEL | LINKPORT_HOST_PORT_OVCR_U2_SEL;
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_LINKPORT);
|
||||
|
||||
/* High-Speed PHY swrst */
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL);
|
||||
reg |= HSPHYCTRL_PHYSWRST;
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL);
|
||||
udelay(20);
|
||||
|
||||
/* Clear the PHY swrst bit */
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL);
|
||||
reg &= ~HSPHYCTRL_PHYSWRST;
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL);
|
||||
|
||||
if (phy_drd->drv_data->phy_tunes)
|
||||
exynos5_usbdrd_apply_phy_tunes(phy_drd,
|
||||
PTS_UTMI_POSTINIT);
|
||||
}
|
||||
|
||||
static int exynos7870_usbdrd_phy_init(struct phy *phy)
|
||||
{
|
||||
struct phy_usb_instance *inst = phy_get_drvdata(phy);
|
||||
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
|
||||
int ret;
|
||||
|
||||
ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* UTMI or PIPE3 specific init */
|
||||
inst->phy_cfg->phy_init(phy_drd);
|
||||
|
||||
clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos7870_usbdrd_phy_exit(struct phy *phy)
|
||||
{
|
||||
int ret;
|
||||
u32 reg;
|
||||
struct phy_usb_instance *inst = phy_get_drvdata(phy);
|
||||
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
|
||||
|
||||
ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Disable the VBUS signal and the ID pull-up resistor.
|
||||
* Enable force-suspend and force-sleep modes.
|
||||
*/
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI);
|
||||
reg &= ~(PHYUTMI_DRVVBUS | PHYUTMI_VBUSVLDEXT | PHYUTMI_VBUSVLDEXTSEL);
|
||||
reg &= ~PHYUTMI_IDPULLUP;
|
||||
reg |= PHYUTMI_FORCESUSPEND | PHYUTMI_FORCESLEEP;
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI);
|
||||
|
||||
/* Power down PHY analog blocks */
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL);
|
||||
reg |= HSPHYCTRL_SIDDQ;
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL);
|
||||
|
||||
/* Clear VBUSVALID signal as the VBUS pad is not used */
|
||||
reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_LINKSYSTEM);
|
||||
reg &= ~(LINKSYSTEM_FORCE_BVALID | LINKSYSTEM_FORCE_VBUSVALID);
|
||||
writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_LINKSYSTEM);
|
||||
|
||||
clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops exynos7870_usbdrd_phy_ops = {
|
||||
.init = exynos7870_usbdrd_phy_init,
|
||||
.exit = exynos7870_usbdrd_phy_exit,
|
||||
.power_on = exynos5_usbdrd_phy_power_on,
|
||||
.power_off = exynos5_usbdrd_phy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void exynos2200_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
|
||||
{
|
||||
/* Configure non-Samsung IP PHY, responsible for UTMI */
|
||||
phy_init(phy_drd->hs_phy);
|
||||
}
|
||||
|
||||
static void exynos2200_usbdrd_link_init(struct exynos5_usbdrd_phy *phy_drd)
|
||||
{
|
||||
void __iomem *regs_base = phy_drd->reg_phy;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Disable HWACG (hardware auto clock gating control). This will force
|
||||
* QACTIVE signal in Q-Channel interface to HIGH level, to make sure
|
||||
* the PHY clock is not gated by the hardware.
|
||||
*/
|
||||
reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL);
|
||||
reg |= LINKCTRL_FORCE_QACT;
|
||||
writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL);
|
||||
|
||||
/* De-assert link reset */
|
||||
reg = readl(regs_base + EXYNOS2200_DRD_CLKRST);
|
||||
reg &= ~CLKRST_LINK_SW_RST;
|
||||
writel(reg, regs_base + EXYNOS2200_DRD_CLKRST);
|
||||
|
||||
/* Set link VBUS Valid */
|
||||
reg = readl(regs_base + EXYNOS2200_DRD_UTMI);
|
||||
reg |= EXYNOS2200_UTMI_FORCE_BVALID | EXYNOS2200_UTMI_FORCE_VBUSVALID;
|
||||
writel(reg, regs_base + EXYNOS2200_DRD_UTMI);
|
||||
}
|
||||
|
||||
static void
|
||||
exynos2200_usbdrd_link_attach_detach_pipe3_phy(struct phy_usb_instance *inst)
|
||||
{
|
||||
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
|
||||
void __iomem *regs_base = phy_drd->reg_phy;
|
||||
u32 reg;
|
||||
|
||||
reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL);
|
||||
if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI) {
|
||||
/* force pipe3 signal for link */
|
||||
reg &= ~LINKCTRL_FORCE_PHYSTATUS;
|
||||
reg |= LINKCTRL_FORCE_PIPE_EN | LINKCTRL_FORCE_RXELECIDLE;
|
||||
} else {
|
||||
/* disable forcing pipe interface */
|
||||
reg &= ~LINKCTRL_FORCE_PIPE_EN;
|
||||
}
|
||||
writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL);
|
||||
|
||||
reg = readl(regs_base + EXYNOS2200_DRD_HSP_MISC);
|
||||
if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI) {
|
||||
/* calibrate only eUSB phy */
|
||||
reg |= FIELD_PREP(HSP_MISC_RES_TUNE, RES_TUNE_PHY1);
|
||||
reg |= HSP_MISC_SET_REQ_IN2;
|
||||
} else {
|
||||
/* calibrate for dual phy */
|
||||
reg |= FIELD_PREP(HSP_MISC_RES_TUNE, RES_TUNE_PHY1_PHY2);
|
||||
reg &= ~HSP_MISC_SET_REQ_IN2;
|
||||
}
|
||||
writel(reg, regs_base + EXYNOS2200_DRD_HSP_MISC);
|
||||
|
||||
reg = readl(regs_base + EXYNOS2200_DRD_CLKRST);
|
||||
if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI)
|
||||
reg &= ~EXYNOS2200_CLKRST_LINK_PCLK_SEL;
|
||||
else
|
||||
reg |= EXYNOS2200_CLKRST_LINK_PCLK_SEL;
|
||||
|
||||
writel(reg, regs_base + EXYNOS2200_DRD_CLKRST);
|
||||
}
|
||||
|
||||
static int exynos2200_usbdrd_phy_init(struct phy *phy)
|
||||
{
|
||||
struct phy_usb_instance *inst = phy_get_drvdata(phy);
|
||||
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
|
||||
int ret;
|
||||
|
||||
if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI) {
|
||||
/* Power-on PHY ... */
|
||||
ret = regulator_bulk_enable(phy_drd->drv_data->n_regulators,
|
||||
phy_drd->regulators);
|
||||
if (ret) {
|
||||
dev_err(phy_drd->dev,
|
||||
"Failed to enable PHY regulator(s)\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* ... and ungate power via PMU. Without this here, we get an SError
|
||||
* trying to access PMA registers
|
||||
*/
|
||||
exynos5_usbdrd_phy_isol(inst, false);
|
||||
|
||||
ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set up the link controller */
|
||||
exynos2200_usbdrd_link_init(phy_drd);
|
||||
|
||||
/* UTMI or PIPE3 link preparation */
|
||||
exynos2200_usbdrd_link_attach_detach_pipe3_phy(inst);
|
||||
|
||||
/* UTMI or PIPE3 specific init */
|
||||
inst->phy_cfg->phy_init(phy_drd);
|
||||
|
||||
clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos2200_usbdrd_phy_exit(struct phy *phy)
|
||||
{
|
||||
struct phy_usb_instance *inst = phy_get_drvdata(phy);
|
||||
struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
|
||||
void __iomem *regs_base = phy_drd->reg_phy;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
reg = readl(regs_base + EXYNOS2200_DRD_UTMI);
|
||||
reg &= ~(EXYNOS2200_UTMI_FORCE_BVALID | EXYNOS2200_UTMI_FORCE_VBUSVALID);
|
||||
writel(reg, regs_base + EXYNOS2200_DRD_UTMI);
|
||||
|
||||
reg = readl(regs_base + EXYNOS2200_DRD_CLKRST);
|
||||
reg |= CLKRST_LINK_SW_RST;
|
||||
writel(reg, regs_base + EXYNOS2200_DRD_CLKRST);
|
||||
|
||||
clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
|
||||
|
||||
exynos5_usbdrd_phy_isol(inst, true);
|
||||
return regulator_bulk_disable(phy_drd->drv_data->n_regulators,
|
||||
phy_drd->regulators);
|
||||
}
|
||||
|
||||
static const struct phy_ops exynos2200_usbdrd_phy_ops = {
|
||||
.init = exynos2200_usbdrd_phy_init,
|
||||
.exit = exynos2200_usbdrd_phy_exit,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void
|
||||
exynos5_usbdrd_usb_v3p1_pipe_override(struct exynos5_usbdrd_phy *phy_drd)
|
||||
{
|
||||
|
@ -1134,7 +1504,7 @@ static void exynos850_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
|
|||
|
||||
/* Set VBUS Valid and D+ pull-up control by VBUS pad usage */
|
||||
reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL);
|
||||
reg |= LINKCTRL_BUS_FILTER_BYPASS(0xf);
|
||||
reg |= FIELD_PREP(LINKCTRL_BUS_FILTER_BYPASS, 0xf);
|
||||
writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL);
|
||||
|
||||
if (!phy_drd->sw) {
|
||||
|
@ -1384,27 +1754,37 @@ static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd)
|
|||
return dev_err_probe(phy_drd->dev, ret,
|
||||
"failed to get phy core clock(s)\n");
|
||||
|
||||
ref_clk = NULL;
|
||||
for (int i = 0; i < phy_drd->drv_data->n_core_clks; ++i) {
|
||||
if (!strcmp(phy_drd->core_clks[i].id, "ref")) {
|
||||
ref_clk = phy_drd->core_clks[i].clk;
|
||||
break;
|
||||
if (phy_drd->drv_data->n_core_clks) {
|
||||
ref_clk = NULL;
|
||||
for (int i = 0; i < phy_drd->drv_data->n_core_clks; ++i) {
|
||||
if (!strcmp(phy_drd->core_clks[i].id, "ref")) {
|
||||
ref_clk = phy_drd->core_clks[i].clk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ref_clk)
|
||||
return dev_err_probe(phy_drd->dev, -ENODEV,
|
||||
"failed to find phy reference clock\n");
|
||||
if (!ref_clk)
|
||||
return dev_err_probe(phy_drd->dev, -ENODEV,
|
||||
"failed to find phy reference clock\n");
|
||||
|
||||
ref_rate = clk_get_rate(ref_clk);
|
||||
ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk);
|
||||
if (ret)
|
||||
return dev_err_probe(phy_drd->dev, ret,
|
||||
"clock rate (%ld) not supported\n",
|
||||
ref_rate);
|
||||
ref_rate = clk_get_rate(ref_clk);
|
||||
ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk);
|
||||
if (ret)
|
||||
return dev_err_probe(phy_drd->dev, ret,
|
||||
"clock rate (%ld) not supported\n",
|
||||
ref_rate);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct exynos5_usbdrd_phy_config phy_cfg_exynos2200[] = {
|
||||
{
|
||||
.id = EXYNOS5_DRDPHY_UTMI,
|
||||
.phy_isol = exynos5_usbdrd_phy_isol,
|
||||
.phy_init = exynos2200_usbdrd_utmi_init,
|
||||
},
|
||||
};
|
||||
|
||||
static int exynos5_usbdrd_orien_sw_set(struct typec_switch_dev *sw,
|
||||
enum typec_orientation orientation)
|
||||
{
|
||||
|
@ -1501,6 +1881,14 @@ static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct exynos5_usbdrd_phy_config phy_cfg_exynos7870[] = {
|
||||
{
|
||||
.id = EXYNOS5_DRDPHY_UTMI,
|
||||
.phy_isol = exynos7870_usbdrd_phy_isol,
|
||||
.phy_init = exynos7870_usbdrd_utmi_init,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct exynos5_usbdrd_phy_config phy_cfg_exynos850[] = {
|
||||
{
|
||||
.id = EXYNOS5_DRDPHY_UTMI,
|
||||
|
@ -1509,6 +1897,30 @@ static const struct exynos5_usbdrd_phy_config phy_cfg_exynos850[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static
|
||||
const struct exynos5_usbdrd_phy_tuning exynos7870_tunes_utmi_postinit[] = {
|
||||
PHY_TUNING_ENTRY_PHY(EXYNOS5_DRD_PHYPARAM0,
|
||||
(PHYPARAM0_TXVREFTUNE | PHYPARAM0_TXRISETUNE |
|
||||
PHYPARAM0_TXRESTUNE | PHYPARAM0_TXPREEMPPULSETUNE |
|
||||
PHYPARAM0_TXPREEMPAMPTUNE | PHYPARAM0_TXHSXVTUNE |
|
||||
PHYPARAM0_TXFSLSTUNE | PHYPARAM0_SQRXTUNE |
|
||||
PHYPARAM0_OTGTUNE | PHYPARAM0_COMPDISTUNE),
|
||||
(FIELD_PREP_CONST(PHYPARAM0_TXVREFTUNE, 14) |
|
||||
FIELD_PREP_CONST(PHYPARAM0_TXRISETUNE, 1) |
|
||||
FIELD_PREP_CONST(PHYPARAM0_TXRESTUNE, 3) |
|
||||
FIELD_PREP_CONST(PHYPARAM0_TXPREEMPAMPTUNE, 0) |
|
||||
FIELD_PREP_CONST(PHYPARAM0_TXHSXVTUNE, 0) |
|
||||
FIELD_PREP_CONST(PHYPARAM0_TXFSLSTUNE, 3) |
|
||||
FIELD_PREP_CONST(PHYPARAM0_SQRXTUNE, 6) |
|
||||
FIELD_PREP_CONST(PHYPARAM0_OTGTUNE, 2) |
|
||||
FIELD_PREP_CONST(PHYPARAM0_COMPDISTUNE, 3))),
|
||||
PHY_TUNING_ENTRY_LAST
|
||||
};
|
||||
|
||||
static const struct exynos5_usbdrd_phy_tuning *exynos7870_tunes[PTS_MAX] = {
|
||||
[PTS_UTMI_POSTINIT] = exynos7870_tunes_utmi_postinit,
|
||||
};
|
||||
|
||||
static const char * const exynos5_clk_names[] = {
|
||||
"phy",
|
||||
};
|
||||
|
@ -1525,6 +1937,19 @@ static const char * const exynos5_regulator_names[] = {
|
|||
"vbus", "vbus-boost",
|
||||
};
|
||||
|
||||
static const struct exynos5_usbdrd_phy_drvdata exynos2200_usb32drd_phy = {
|
||||
.phy_cfg = phy_cfg_exynos2200,
|
||||
.phy_ops = &exynos2200_usbdrd_phy_ops,
|
||||
.pmu_offset_usbdrd0_phy = EXYNOS2200_PHY_CTRL_USB20,
|
||||
.clk_names = exynos5_clk_names,
|
||||
.n_clks = ARRAY_SIZE(exynos5_clk_names),
|
||||
/* clocks and regulators are specific to the underlying PHY blocks */
|
||||
.core_clk_names = NULL,
|
||||
.n_core_clks = 0,
|
||||
.regulator_names = NULL,
|
||||
.n_regulators = 0,
|
||||
};
|
||||
|
||||
static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = {
|
||||
.phy_cfg = phy_cfg_exynos5,
|
||||
.phy_ops = &exynos5_usbdrd_phy_ops,
|
||||
|
@ -1575,6 +2000,19 @@ static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = {
|
|||
.n_regulators = ARRAY_SIZE(exynos5_regulator_names),
|
||||
};
|
||||
|
||||
static const struct exynos5_usbdrd_phy_drvdata exynos7870_usbdrd_phy = {
|
||||
.phy_cfg = phy_cfg_exynos7870,
|
||||
.phy_tunes = exynos7870_tunes,
|
||||
.phy_ops = &exynos7870_usbdrd_phy_ops,
|
||||
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
|
||||
.clk_names = exynos5_clk_names,
|
||||
.n_clks = ARRAY_SIZE(exynos5_clk_names),
|
||||
.core_clk_names = exynos5_core_clk_names,
|
||||
.n_core_clks = ARRAY_SIZE(exynos5_core_clk_names),
|
||||
.regulator_names = exynos5_regulator_names,
|
||||
.n_regulators = ARRAY_SIZE(exynos5_regulator_names),
|
||||
};
|
||||
|
||||
static const struct exynos5_usbdrd_phy_drvdata exynos850_usbdrd_phy = {
|
||||
.phy_cfg = phy_cfg_exynos850,
|
||||
.phy_ops = &exynos850_usbdrd_phy_ops,
|
||||
|
@ -1769,6 +2207,9 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
|
|||
{
|
||||
.compatible = "google,gs101-usb31drd-phy",
|
||||
.data = &gs101_usbd31rd_phy
|
||||
}, {
|
||||
.compatible = "samsung,exynos2200-usb32drd-phy",
|
||||
.data = &exynos2200_usb32drd_phy,
|
||||
}, {
|
||||
.compatible = "samsung,exynos5250-usbdrd-phy",
|
||||
.data = &exynos5250_usbdrd_phy
|
||||
|
@ -1781,6 +2222,9 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
|
|||
}, {
|
||||
.compatible = "samsung,exynos7-usbdrd-phy",
|
||||
.data = &exynos7_usbdrd_phy
|
||||
}, {
|
||||
.compatible = "samsung,exynos7870-usbdrd-phy",
|
||||
.data = &exynos7870_usbdrd_phy
|
||||
}, {
|
||||
.compatible = "samsung,exynos850-usbdrd-phy",
|
||||
.data = &exynos850_usbdrd_phy
|
||||
|
@ -1841,6 +2285,17 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(phy_drd->reg_phy);
|
||||
}
|
||||
|
||||
/*
|
||||
* USB32DRD 4nm controller implements Synopsys eUSB2.0 PHY
|
||||
* and Synopsys SS/USBDP COMBOPHY, managed by external code.
|
||||
*/
|
||||
if (of_property_present(dev->of_node, "phy-names")) {
|
||||
phy_drd->hs_phy = devm_of_phy_get(dev, dev->of_node, "hs");
|
||||
if (IS_ERR(phy_drd->hs_phy))
|
||||
return dev_err_probe(dev, PTR_ERR(phy_drd->hs_phy),
|
||||
"failed to get hs_phy\n");
|
||||
}
|
||||
|
||||
ret = exynos5_usbdrd_phy_clk_handle(phy_drd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
@ -13,7 +13,7 @@ config PHY_TEGRA_XUSB
|
|||
|
||||
config PHY_TEGRA194_P2U
|
||||
tristate "NVIDIA Tegra194 PIPE2UPHY PHY driver"
|
||||
depends on ARCH_TEGRA_194_SOC || ARCH_TEGRA_234_SOC || COMPILE_TEST
|
||||
depends on ARCH_TEGRA || COMPILE_TEST
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support the P2U (PIPE to UPHY) that is part of Tegra 19x
|
||||
|
|
|
@ -222,7 +222,6 @@ struct xpsgtr_phy {
|
|||
* @siou: siou base address
|
||||
* @gtr_mutex: mutex for locking
|
||||
* @phys: PHY lanes
|
||||
* @refclk_sscs: spread spectrum settings for the reference clocks
|
||||
* @clk: reference clocks
|
||||
* @tx_term_fix: fix for GT issue
|
||||
* @saved_icm_cfg0: stored value of ICM CFG0 register
|
||||
|
@ -235,7 +234,6 @@ struct xpsgtr_dev {
|
|||
void __iomem *siou;
|
||||
struct mutex gtr_mutex; /* mutex for locking */
|
||||
struct xpsgtr_phy phys[NUM_LANES];
|
||||
const struct xpsgtr_ssc *refclk_sscs[NUM_LANES];
|
||||
struct clk *clk[NUM_LANES];
|
||||
bool tx_term_fix;
|
||||
unsigned int saved_icm_cfg0;
|
||||
|
@ -398,13 +396,40 @@ got_phy:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Get the spread spectrum (SSC) settings for the reference clock rate */
|
||||
static const struct xpsgtr_ssc *xpsgtr_find_sscs(struct xpsgtr_phy *gtr_phy)
|
||||
{
|
||||
unsigned long rate;
|
||||
struct clk *clk;
|
||||
unsigned int i;
|
||||
|
||||
clk = gtr_phy->dev->clk[gtr_phy->refclk];
|
||||
rate = clk_get_rate(clk);
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(ssc_lookup); i++) {
|
||||
/* Allow an error of 100 ppm */
|
||||
unsigned long error = ssc_lookup[i].refclk_rate / 10000;
|
||||
|
||||
if (abs(rate - ssc_lookup[i].refclk_rate) < error)
|
||||
return &ssc_lookup[i];
|
||||
}
|
||||
|
||||
dev_err(gtr_phy->dev->dev, "Invalid rate %lu for reference clock %u\n",
|
||||
rate, gtr_phy->refclk);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Configure PLL and spread-sprectrum clock. */
|
||||
static void xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy)
|
||||
static int xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy)
|
||||
{
|
||||
const struct xpsgtr_ssc *ssc;
|
||||
u32 step_size;
|
||||
|
||||
ssc = gtr_phy->dev->refclk_sscs[gtr_phy->refclk];
|
||||
ssc = xpsgtr_find_sscs(gtr_phy);
|
||||
if (!ssc)
|
||||
return -EINVAL;
|
||||
|
||||
step_size = ssc->step_size;
|
||||
|
||||
xpsgtr_clr_set(gtr_phy->dev, PLL_REF_SEL(gtr_phy->lane),
|
||||
|
@ -446,6 +471,8 @@ static void xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy)
|
|||
xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_3_MSB,
|
||||
STEP_SIZE_3_MASK, (step_size & STEP_SIZE_3_MASK) |
|
||||
FORCE_STEP_SIZE | FORCE_STEPS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Configure the lane protocol. */
|
||||
|
@ -658,7 +685,10 @@ static int xpsgtr_phy_init(struct phy *phy)
|
|||
* Configure the PLL, the lane protocol, and perform protocol-specific
|
||||
* initialization.
|
||||
*/
|
||||
xpsgtr_configure_pll(gtr_phy);
|
||||
ret = xpsgtr_configure_pll(gtr_phy);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
xpsgtr_lane_set_protocol(gtr_phy);
|
||||
|
||||
switch (gtr_phy->protocol) {
|
||||
|
@ -823,8 +853,7 @@ static struct phy *xpsgtr_xlate(struct device *dev,
|
|||
}
|
||||
|
||||
refclk = args->args[3];
|
||||
if (refclk >= ARRAY_SIZE(gtr_dev->refclk_sscs) ||
|
||||
!gtr_dev->refclk_sscs[refclk]) {
|
||||
if (refclk >= ARRAY_SIZE(gtr_dev->clk)) {
|
||||
dev_err(dev, "Invalid reference clock number %u\n", refclk);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
@ -928,9 +957,7 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev)
|
|||
{
|
||||
unsigned int refclk;
|
||||
|
||||
for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) {
|
||||
unsigned long rate;
|
||||
unsigned int i;
|
||||
for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->clk); ++refclk) {
|
||||
struct clk *clk;
|
||||
char name[8];
|
||||
|
||||
|
@ -946,29 +973,6 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev)
|
|||
continue;
|
||||
|
||||
gtr_dev->clk[refclk] = clk;
|
||||
|
||||
/*
|
||||
* Get the spread spectrum (SSC) settings for the reference
|
||||
* clock rate.
|
||||
*/
|
||||
rate = clk_get_rate(clk);
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(ssc_lookup); i++) {
|
||||
/* Allow an error of 100 ppm */
|
||||
unsigned long error = ssc_lookup[i].refclk_rate / 10000;
|
||||
|
||||
if (abs(rate - ssc_lookup[i].refclk_rate) < error) {
|
||||
gtr_dev->refclk_sscs[refclk] = &ssc_lookup[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(ssc_lookup)) {
|
||||
dev_err(gtr_dev->dev,
|
||||
"Invalid rate %lu for reference clock %u\n",
|
||||
rate, refclk);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
21
include/linux/phy/phy-hdmi.h
Normal file
21
include/linux/phy/phy-hdmi.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright 2022,2024 NXP
|
||||
*/
|
||||
|
||||
#ifndef __PHY_HDMI_H_
|
||||
#define __PHY_HDMI_H_
|
||||
|
||||
/**
|
||||
* struct phy_configure_opts_hdmi - HDMI configuration set
|
||||
* @tmds_char_rate: HDMI TMDS Character Rate in Hertz.
|
||||
* @bpc: Bits per color channel.
|
||||
*
|
||||
* This structure is used to represent the configuration state of a HDMI phy.
|
||||
*/
|
||||
struct phy_configure_opts_hdmi {
|
||||
unsigned long long tmds_char_rate;
|
||||
unsigned int bpc;
|
||||
};
|
||||
|
||||
#endif /* __PHY_HDMI_H_ */
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <linux/phy/phy-dp.h>
|
||||
#include <linux/phy/phy-hdmi.h>
|
||||
#include <linux/phy/phy-lvds.h>
|
||||
#include <linux/phy/phy-mipi-dphy.h>
|
||||
|
||||
|
@ -42,7 +43,8 @@ enum phy_mode {
|
|||
PHY_MODE_MIPI_DPHY,
|
||||
PHY_MODE_SATA,
|
||||
PHY_MODE_LVDS,
|
||||
PHY_MODE_DP
|
||||
PHY_MODE_DP,
|
||||
PHY_MODE_HDMI,
|
||||
};
|
||||
|
||||
enum phy_media {
|
||||
|
@ -60,11 +62,14 @@ enum phy_media {
|
|||
* the DisplayPort protocol.
|
||||
* @lvds: Configuration set applicable for phys supporting
|
||||
* the LVDS phy mode.
|
||||
* @hdmi: Configuration set applicable for phys supporting
|
||||
* the HDMI phy mode.
|
||||
*/
|
||||
union phy_configure_opts {
|
||||
struct phy_configure_opts_mipi_dphy mipi_dphy;
|
||||
struct phy_configure_opts_dp dp;
|
||||
struct phy_configure_opts_lvds lvds;
|
||||
struct phy_configure_opts_hdmi hdmi;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -55,6 +55,8 @@
|
|||
#define EXYNOS4_MIPI_PHY_SRESETN (1 << 1)
|
||||
#define EXYNOS4_MIPI_PHY_MRESETN (1 << 2)
|
||||
#define EXYNOS4_MIPI_PHY_RESET_MASK (3 << 1)
|
||||
/* USB PHY enable bit, valid for Exynos7870 */
|
||||
#define EXYNOS7870_USB2PHY_ENABLE (1 << 1)
|
||||
|
||||
#define S5P_INFORM0 0x0800
|
||||
#define S5P_INFORM1 0x0804
|
||||
|
@ -185,6 +187,9 @@
|
|||
/* Only for S5Pv210 */
|
||||
#define S5PV210_EINT_WAKEUP_MASK 0xC004
|
||||
|
||||
/* Only for Exynos2200 */
|
||||
#define EXYNOS2200_PHY_CTRL_USB20 0x72C
|
||||
|
||||
/* Only for Exynos4210 */
|
||||
#define S5P_CMU_CLKSTOP_LCD1_LOWPWR 0x1154
|
||||
#define S5P_CMU_RESET_LCD1_LOWPWR 0x1174
|
||||
|
|
Loading…
Reference in New Issue
Block a user