forked from Minki/linux
phy-for-5.19
- New support: - LVDS configuration support and implementation in fsl driver - Qualcomm UFS phy support for SM6350 and USB PHY for SDX65 - Allwinner D-PHY Rx mode support - Yamilfy Mixel mipi-dsi-phy - Updates: - Documentation for phy ops order - Can transceiver mux support - Qualcomm QMP phy updates - Uniphier phy updates -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmJ8+aQACgkQfBQHDyUj g0dw4g//a/M781Z0aQKs4emUwC1fetk2zqEz0Veh8O7QVYxmPf2QlJVI8tmKA1Y9 QRKTwcaLUKRE1ljIY7BeVEf3dr1lMDny7CP1nFXEoO6z/jwxe2yfhWgzG5mY08g3 LsNF7YxL+2XUBQbBrTCVauNrWKgw0dVTlajaPYLwQar0RudP9ptwpxAaompGXoKX Q1Zbnu82/ivEgPOQotmZAPH+2LFX7DzHwB8O1saY8ewZUoSWMjo3nDS/z+o7f/VM 8imyvdPgcORGIS5pXXuA6HaPrRm+3Mr5/bsY4LL+UpBKsz8Qd3FaJlkHtKvPHzDE WH7VaVbjwo412AhO5FRJtOxngYRAktQD8iiNq/XiB/4QpdRs1nSPGK2waJeatouM pnKEuDOzAVcDqIE4mEnpjI+HMMwM1ZZJknW32ekuO6h1W7HE1X8ZqQ08wDi90smK f8Qr8GrriVbmEpUwB3iLafsqS6ERYTmoc0Ar5hCwnbmgP+MCDGFYCA1lsVYM+TQE n1G+pNkGjpdbRuzVipddApNCQxfv1DYGb1lVBSFJICs3TcXhNwVt6aEHXtgAKCUW WnwBTAN+Mvwx9AX2hs92jPNc/k9dFys1ym+vwlWtW9bf4KnxY6idM8Psb+BZf2Pz G8hmdyEvN7quoxLxCo5JCoXaZn5Ye+qouKUwVPqt/gpH7cU3dpI= =LKvH -----END PGP SIGNATURE----- Merge tag 'phy-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy into char-work-next Vinod writes: phy-for-5.19 - New support: - LVDS configuration support and implementation in fsl driver - Qualcomm UFS phy support for SM6350 and USB PHY for SDX65 - Allwinner D-PHY Rx mode support - Yamilfy Mixel mipi-dsi-phy - Updates: - Documentation for phy ops order - Can transceiver mux support - Qualcomm QMP phy updates - Uniphier phy updates * tag 'phy-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (40 commits) phy: qcom-qmp: rename error labels phy: qcom-qmp: fix pipe-clock imbalance on power-on failure phy: qcom-qmp: switch to explicit reset helpers phy: qcom-qmp: fix reset-controller leak on probe errors phy: qcom-qmp: fix struct clk leak on probe errors dt-bindings: phy: renesas,usb2-phy: Document RZ/G2UL phy bindings dt-bindings: phy: marvell,armada-3700-utmi-host-phy: Fix incorrect compatible in example phy: qcom-qmp: fix phy-descriptor kernel-doc typo phy: rockchip-inno-usb2: Clean up some inconsistent indenting phy: freescale: imx8m-pcie: Handle IMX8_PCIE_REFCLK_PAD_UNUSED phy: core: Warn when phy_power_on is called before phy_init phy: core: Update documentation syntax phy: core: Add documentation of phy operation order phy: rockchip-inno-usb2: Handle ID IRQ phy: rockchip-inno-usb2: Handle bvalid falling phy: rockchip-inno-usb2: Support multi-bit mask properties phy: rockchip-inno-usb2: Do not lock in bvalid IRQ handler phy: rockchip-inno-usb2: Do not check bvalid twice phy: rockchip-inno-usb2: Fix muxed interrupt support phy: allwinner: phy-sun6i-mipi-dphy: Support D-PHY Rx mode for MIPI CSI-2 ...
This commit is contained in:
commit
46509e7578
@ -37,6 +37,18 @@ properties:
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
allwinner,direction:
|
||||
$ref: '/schemas/types.yaml#/definitions/string'
|
||||
description: |
|
||||
Direction of the D-PHY:
|
||||
- "rx" for receiving (e.g. when used with MIPI CSI-2);
|
||||
- "tx" for transmitting (e.g. when used with MIPI DSI).
|
||||
|
||||
enum:
|
||||
- tx
|
||||
- rx
|
||||
default: tx
|
||||
|
||||
required:
|
||||
- "#phy-cells"
|
||||
- compatible
|
||||
|
@ -45,7 +45,7 @@ additionalProperties: false
|
||||
examples:
|
||||
- |
|
||||
usb2_utmi_host_phy: phy@5f000 {
|
||||
compatible = "marvell,armada-3700-utmi-host-phy";
|
||||
compatible = "marvell,a3700-utmi-host-phy";
|
||||
reg = <0x5f000 0x800>;
|
||||
marvell,usb-misc-reg = <&usb2_syscon>;
|
||||
#phy-cells = <0>;
|
||||
|
@ -1,29 +0,0 @@
|
||||
Mixel DSI PHY for i.MX8
|
||||
|
||||
The Mixel MIPI-DSI PHY IP block is e.g. found on i.MX8 platforms (along the
|
||||
MIPI-DSI IP from Northwest Logic). It represents the physical layer for the
|
||||
electrical signals for DSI.
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be:
|
||||
- "fsl,imx8mq-mipi-dphy"
|
||||
- clocks: Must contain an entry for each entry in clock-names.
|
||||
- clock-names: Must contain the following entries:
|
||||
- "phy_ref": phandle and specifier referring to the DPHY ref clock
|
||||
- reg: the register range of the PHY controller
|
||||
- #phy-cells: number of cells in PHY, as defined in
|
||||
Documentation/devicetree/bindings/phy/phy-bindings.txt
|
||||
this must be <0>
|
||||
|
||||
Optional properties:
|
||||
- power-domains: phandle to power domain
|
||||
|
||||
Example:
|
||||
dphy: dphy@30a0030 {
|
||||
compatible = "fsl,imx8mq-mipi-dphy";
|
||||
clocks = <&clk IMX8MQ_CLK_DSI_PHY_REF>;
|
||||
clock-names = "phy_ref";
|
||||
reg = <0x30a00300 0x100>;
|
||||
power-domains = <&pd_mipi0>;
|
||||
#phy-cells = <0>;
|
||||
};
|
107
Documentation/devicetree/bindings/phy/mixel,mipi-dsi-phy.yaml
Normal file
107
Documentation/devicetree/bindings/phy/mixel,mipi-dsi-phy.yaml
Normal file
@ -0,0 +1,107 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/mixel,mipi-dsi-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mixel DSI PHY for i.MX8
|
||||
|
||||
maintainers:
|
||||
- Guido Günther <agx@sigxcpu.org>
|
||||
|
||||
description: |
|
||||
The Mixel MIPI-DSI PHY IP block is e.g. found on i.MX8 platforms (along the
|
||||
MIPI-DSI IP from Northwest Logic). It represents the physical layer for the
|
||||
electrical signals for DSI.
|
||||
|
||||
The Mixel PHY IP block found on i.MX8qxp is a combo PHY that can work
|
||||
in either MIPI-DSI PHY mode or LVDS PHY mode.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx8mq-mipi-dphy
|
||||
- fsl,imx8qxp-mipi-dphy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: phy_ref
|
||||
|
||||
assigned-clocks:
|
||||
maxItems: 1
|
||||
|
||||
assigned-clock-parents:
|
||||
maxItems: 1
|
||||
|
||||
assigned-clock-rates:
|
||||
maxItems: 1
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
fsl,syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: |
|
||||
A phandle which points to Control and Status Registers(CSR) module.
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- "#phy-cells"
|
||||
- power-domains
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: fsl,imx8mq-mipi-dphy
|
||||
then:
|
||||
properties:
|
||||
fsl,syscon: false
|
||||
|
||||
required:
|
||||
- assigned-clocks
|
||||
- assigned-clock-parents
|
||||
- assigned-clock-rates
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: fsl,imx8qxp-mipi-dphy
|
||||
then:
|
||||
properties:
|
||||
assigned-clocks: false
|
||||
assigned-clock-parents: false
|
||||
assigned-clock-rates: false
|
||||
|
||||
required:
|
||||
- fsl,syscon
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/imx8mq-clock.h>
|
||||
dphy: dphy@30a0030 {
|
||||
compatible = "fsl,imx8mq-mipi-dphy";
|
||||
reg = <0x30a00300 0x100>;
|
||||
clocks = <&clk IMX8MQ_CLK_DSI_PHY_REF>;
|
||||
clock-names = "phy_ref";
|
||||
assigned-clocks = <&clk IMX8MQ_CLK_DSI_PHY_REF>;
|
||||
assigned-clock-parents = <&clk IMX8MQ_VIDEO_PLL1_OUT>;
|
||||
assigned-clock-rates = <24000000>;
|
||||
#phy-cells = <0>;
|
||||
power-domains = <&pgc_mipi>;
|
||||
};
|
@ -39,6 +39,7 @@ properties:
|
||||
- qcom,sdm845-qmp-usb3-phy
|
||||
- qcom,sdm845-qmp-usb3-uni-phy
|
||||
- qcom,sm6115-qmp-ufs-phy
|
||||
- qcom,sm6350-qmp-ufs-phy
|
||||
- qcom,sm8150-qmp-ufs-phy
|
||||
- qcom,sm8150-qmp-usb3-phy
|
||||
- qcom,sm8150-qmp-usb3-uni-phy
|
||||
@ -57,6 +58,7 @@ properties:
|
||||
- qcom,sm8450-qmp-usb3-phy
|
||||
- qcom,sdx55-qmp-pcie-phy
|
||||
- qcom,sdx55-qmp-usb3-uni-phy
|
||||
- qcom,sdx65-qmp-usb3-uni-phy
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
@ -163,6 +165,7 @@ allOf:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sdx55-qmp-usb3-uni-phy
|
||||
- qcom,sdx65-qmp-usb3-uni-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
@ -279,6 +282,7 @@ allOf:
|
||||
enum:
|
||||
- qcom,msm8998-qmp-ufs-phy
|
||||
- qcom,sdm845-qmp-ufs-phy
|
||||
- qcom,sm6350-qmp-ufs-phy
|
||||
- qcom,sm8150-qmp-ufs-phy
|
||||
- qcom,sm8250-qmp-ufs-phy
|
||||
- qcom,sc8180x-qmp-ufs-phy
|
||||
|
@ -32,6 +32,7 @@ properties:
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,usb2-phy-r9a07g043 # RZ/G2UL
|
||||
- renesas,usb2-phy-r9a07g044 # RZ/G2{L,LC}
|
||||
- renesas,usb2-phy-r9a07g054 # RZ/V2L
|
||||
- const: renesas,rzg2l-usb2-phy
|
||||
|
@ -30,32 +30,79 @@ properties:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
oneOf:
|
||||
- items: # for PXs2
|
||||
- const: link
|
||||
- items: # for Pro4
|
||||
- const: link
|
||||
- const: gio
|
||||
- items: # for others
|
||||
- const: link
|
||||
- const: phy
|
||||
clock-names: true
|
||||
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
maxItems: 6
|
||||
|
||||
reset-names:
|
||||
oneOf:
|
||||
- items: # for Pro4
|
||||
- const: link
|
||||
- const: gio
|
||||
- const: pm
|
||||
- const: tx
|
||||
- const: rx
|
||||
- items: # for others
|
||||
- const: link
|
||||
- const: phy
|
||||
reset-names: true
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: socionext,uniphier-pro4-ahci-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: gio
|
||||
resets:
|
||||
minItems: 6
|
||||
maxItems: 6
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: gio
|
||||
- const: phy
|
||||
- const: pm
|
||||
- const: tx
|
||||
- const: rx
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: socionext,uniphier-pxs2-ahci-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 1
|
||||
clock-names:
|
||||
const: link
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: socionext,uniphier-pxs3-ahci-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
@ -31,28 +31,51 @@ properties:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
oneOf:
|
||||
- items: # for Pro5
|
||||
- const: gio
|
||||
- const: link
|
||||
- const: link # for others
|
||||
clock-names: true
|
||||
|
||||
resets:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
oneOf:
|
||||
- items: # for Pro5
|
||||
- const: gio
|
||||
- const: link
|
||||
- const: link # for others
|
||||
reset-names: true
|
||||
|
||||
socionext,syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: A phandle to system control to set configurations for phy
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: socionext,uniphier-pro5-pcie-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: gio
|
||||
- const: link
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: gio
|
||||
- const: link
|
||||
else:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 1
|
||||
clock-names:
|
||||
const: link
|
||||
resets:
|
||||
maxItems: 1
|
||||
reset-names:
|
||||
const: link
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -43,6 +43,9 @@ patternProperties:
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
vbus-supply:
|
||||
description: A phandle to the regulator for USB VBUS, only for USB host
|
||||
|
||||
required:
|
||||
- reg
|
||||
- "#phy-cells"
|
||||
|
@ -31,27 +31,15 @@ properties:
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
oneOf:
|
||||
- const: link # for PXs2
|
||||
- items: # for PXs3 with phy-ext
|
||||
- const: link
|
||||
- const: phy
|
||||
- const: phy-ext
|
||||
- items: # for others
|
||||
- const: link
|
||||
- const: phy
|
||||
clock-names: true
|
||||
|
||||
resets:
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
reset-names: true
|
||||
|
||||
vbus-supply:
|
||||
description: A phandle to the regulator for USB VBUS
|
||||
@ -74,6 +62,77 @@ properties:
|
||||
required for each port, if any one is omitted, the trimming data
|
||||
of the port will not be set at all.
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: socionext,uniphier-pro5-usb3-hsphy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: gio
|
||||
- const: link
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: gio
|
||||
- const: link
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- socionext,uniphier-pxs2-usb3-hsphy
|
||||
- socionext,uniphier-ld20-usb3-hsphy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- socionext,uniphier-pxs3-usb3-hsphy
|
||||
- socionext,uniphier-nx1-usb3-hsphy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
- const: phy-ext
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -35,33 +35,88 @@ properties:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
oneOf:
|
||||
- items: # for Pro4, Pro5
|
||||
- const: gio
|
||||
- const: link
|
||||
- items: # for PXs3 with phy-ext
|
||||
- const: link
|
||||
- const: phy
|
||||
- const: phy-ext
|
||||
- items: # for others
|
||||
- const: link
|
||||
- const: phy
|
||||
clock-names: true
|
||||
|
||||
resets:
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
oneOf:
|
||||
- items: # for Pro4,Pro5
|
||||
- const: gio
|
||||
- const: link
|
||||
- items: # for others
|
||||
- const: link
|
||||
- const: phy
|
||||
reset-names: true
|
||||
|
||||
vbus-supply:
|
||||
description: A phandle to the regulator for USB VBUS
|
||||
description: A phandle to the regulator for USB VBUS, only for USB host
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- socionext,uniphier-pro4-usb3-ssphy
|
||||
- socionext,uniphier-pro5-usb3-ssphy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: gio
|
||||
- const: link
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: gio
|
||||
- const: link
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- socionext,uniphier-pxs2-usb3-ssphy
|
||||
- socionext,uniphier-ld20-usb3-ssphy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- socionext,uniphier-pxs3-usb3-ssphy
|
||||
- socionext,uniphier-nx1-usb3-ssphy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
- const: phy-ext
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reset-names:
|
||||
items:
|
||||
- const: link
|
||||
- const: phy
|
||||
|
||||
required:
|
||||
- compatible
|
||||
@ -71,7 +126,6 @@ required:
|
||||
- clock-names
|
||||
- resets
|
||||
- reset-names
|
||||
- vbus-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
|
@ -64,6 +64,7 @@ config USB_LGM_PHY
|
||||
config PHY_CAN_TRANSCEIVER
|
||||
tristate "CAN transceiver PHY"
|
||||
select GENERIC_PHY
|
||||
select MULTIPLEXER
|
||||
help
|
||||
This option enables support for CAN transceivers as a PHY. This
|
||||
driver provides function for putting the transceivers in various
|
||||
|
@ -24,6 +24,14 @@
|
||||
#define SUN6I_DPHY_TX_CTL_REG 0x04
|
||||
#define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28)
|
||||
|
||||
#define SUN6I_DPHY_RX_CTL_REG 0x08
|
||||
#define SUN6I_DPHY_RX_CTL_EN_DBC BIT(31)
|
||||
#define SUN6I_DPHY_RX_CTL_RX_CLK_FORCE BIT(24)
|
||||
#define SUN6I_DPHY_RX_CTL_RX_D3_FORCE BIT(23)
|
||||
#define SUN6I_DPHY_RX_CTL_RX_D2_FORCE BIT(22)
|
||||
#define SUN6I_DPHY_RX_CTL_RX_D1_FORCE BIT(21)
|
||||
#define SUN6I_DPHY_RX_CTL_RX_D0_FORCE BIT(20)
|
||||
|
||||
#define SUN6I_DPHY_TX_TIME0_REG 0x10
|
||||
#define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24)
|
||||
#define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16)
|
||||
@ -44,12 +52,29 @@
|
||||
#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8)
|
||||
#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n) ((n) & 0xff)
|
||||
|
||||
#define SUN6I_DPHY_RX_TIME0_REG 0x30
|
||||
#define SUN6I_DPHY_RX_TIME0_HS_RX_SYNC(n) (((n) & 0xff) << 24)
|
||||
#define SUN6I_DPHY_RX_TIME0_HS_RX_CLK_MISS(n) (((n) & 0xff) << 16)
|
||||
#define SUN6I_DPHY_RX_TIME0_LP_RX(n) (((n) & 0xff) << 8)
|
||||
|
||||
#define SUN6I_DPHY_RX_TIME1_REG 0x34
|
||||
#define SUN6I_DPHY_RX_TIME1_RX_DLY(n) (((n) & 0xfff) << 20)
|
||||
#define SUN6I_DPHY_RX_TIME1_LP_RX_ULPS_WP(n) ((n) & 0xfffff)
|
||||
|
||||
#define SUN6I_DPHY_RX_TIME2_REG 0x38
|
||||
#define SUN6I_DPHY_RX_TIME2_HS_RX_ANA1(n) (((n) & 0xff) << 8)
|
||||
#define SUN6I_DPHY_RX_TIME2_HS_RX_ANA0(n) ((n) & 0xff)
|
||||
|
||||
#define SUN6I_DPHY_RX_TIME3_REG 0x40
|
||||
#define SUN6I_DPHY_RX_TIME3_LPRST_DLY(n) (((n) & 0xffff) << 16)
|
||||
|
||||
#define SUN6I_DPHY_ANA0_REG 0x4c
|
||||
#define SUN6I_DPHY_ANA0_REG_PWS BIT(31)
|
||||
#define SUN6I_DPHY_ANA0_REG_DMPC BIT(28)
|
||||
#define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24)
|
||||
#define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12)
|
||||
#define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8)
|
||||
#define SUN6I_DPHY_ANA0_REG_SFB(n) (((n) & 3) << 2)
|
||||
|
||||
#define SUN6I_DPHY_ANA1_REG 0x50
|
||||
#define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31)
|
||||
@ -84,6 +109,11 @@
|
||||
|
||||
#define SUN6I_DPHY_DBG5_REG 0xf4
|
||||
|
||||
enum sun6i_dphy_direction {
|
||||
SUN6I_DPHY_DIRECTION_TX,
|
||||
SUN6I_DPHY_DIRECTION_RX,
|
||||
};
|
||||
|
||||
struct sun6i_dphy {
|
||||
struct clk *bus_clk;
|
||||
struct clk *mod_clk;
|
||||
@ -92,6 +122,8 @@ struct sun6i_dphy {
|
||||
|
||||
struct phy *phy;
|
||||
struct phy_configure_opts_mipi_dphy config;
|
||||
|
||||
enum sun6i_dphy_direction direction;
|
||||
};
|
||||
|
||||
static int sun6i_dphy_init(struct phy *phy)
|
||||
@ -119,9 +151,8 @@ static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sun6i_dphy_power_on(struct phy *phy)
|
||||
static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy)
|
||||
{
|
||||
struct sun6i_dphy *dphy = phy_get_drvdata(phy);
|
||||
u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0);
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG,
|
||||
@ -211,12 +242,129 @@ static int sun6i_dphy_power_on(struct phy *phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sun6i_dphy_rx_power_on(struct sun6i_dphy *dphy)
|
||||
{
|
||||
/* Physical clock rate is actually half of symbol rate with DDR. */
|
||||
unsigned long mipi_symbol_rate = dphy->config.hs_clk_rate;
|
||||
unsigned long dphy_clk_rate;
|
||||
unsigned int rx_dly;
|
||||
unsigned int lprst_dly;
|
||||
u32 value;
|
||||
|
||||
dphy_clk_rate = clk_get_rate(dphy->mod_clk);
|
||||
if (!dphy_clk_rate)
|
||||
return -EINVAL;
|
||||
|
||||
/* Hardcoded timing parameters from the Allwinner BSP. */
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME0_REG,
|
||||
SUN6I_DPHY_RX_TIME0_HS_RX_SYNC(255) |
|
||||
SUN6I_DPHY_RX_TIME0_HS_RX_CLK_MISS(255) |
|
||||
SUN6I_DPHY_RX_TIME0_LP_RX(255));
|
||||
|
||||
/*
|
||||
* Formula from the Allwinner BSP, with hardcoded coefficients
|
||||
* (probably internal divider/multiplier).
|
||||
*/
|
||||
rx_dly = 8 * (unsigned int)(dphy_clk_rate / (mipi_symbol_rate / 8));
|
||||
|
||||
/*
|
||||
* The Allwinner BSP has an alternative formula for LP_RX_ULPS_WP:
|
||||
* lp_ulps_wp_cnt = lp_ulps_wp_ms * lp_clk / 1000
|
||||
* but does not use it and hardcodes 255 instead.
|
||||
*/
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME1_REG,
|
||||
SUN6I_DPHY_RX_TIME1_RX_DLY(rx_dly) |
|
||||
SUN6I_DPHY_RX_TIME1_LP_RX_ULPS_WP(255));
|
||||
|
||||
/* HS_RX_ANA0 value is hardcoded in the Allwinner BSP. */
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME2_REG,
|
||||
SUN6I_DPHY_RX_TIME2_HS_RX_ANA0(4));
|
||||
|
||||
/*
|
||||
* Formula from the Allwinner BSP, with hardcoded coefficients
|
||||
* (probably internal divider/multiplier).
|
||||
*/
|
||||
lprst_dly = 4 * (unsigned int)(dphy_clk_rate / (mipi_symbol_rate / 2));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME3_REG,
|
||||
SUN6I_DPHY_RX_TIME3_LPRST_DLY(lprst_dly));
|
||||
|
||||
/* Analog parameters are hardcoded in the Allwinner BSP. */
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
|
||||
SUN6I_DPHY_ANA0_REG_PWS |
|
||||
SUN6I_DPHY_ANA0_REG_SLV(7) |
|
||||
SUN6I_DPHY_ANA0_REG_SFB(2));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG,
|
||||
SUN6I_DPHY_ANA1_REG_SVTT(4));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG,
|
||||
SUN6I_DPHY_ANA4_REG_DMPLVC |
|
||||
SUN6I_DPHY_ANA4_REG_DMPLVD(1));
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG,
|
||||
SUN6I_DPHY_ANA2_REG_ENIB);
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG,
|
||||
SUN6I_DPHY_ANA3_EN_LDOR |
|
||||
SUN6I_DPHY_ANA3_EN_LDOC |
|
||||
SUN6I_DPHY_ANA3_EN_LDOD);
|
||||
|
||||
/*
|
||||
* Delay comes from the Allwinner BSP, likely for internal regulator
|
||||
* ramp-up.
|
||||
*/
|
||||
udelay(3);
|
||||
|
||||
value = SUN6I_DPHY_RX_CTL_EN_DBC | SUN6I_DPHY_RX_CTL_RX_CLK_FORCE;
|
||||
|
||||
/*
|
||||
* Rx data lane force-enable bits are used as regular RX enable by the
|
||||
* Allwinner BSP.
|
||||
*/
|
||||
if (dphy->config.lanes >= 1)
|
||||
value |= SUN6I_DPHY_RX_CTL_RX_D0_FORCE;
|
||||
if (dphy->config.lanes >= 2)
|
||||
value |= SUN6I_DPHY_RX_CTL_RX_D1_FORCE;
|
||||
if (dphy->config.lanes >= 3)
|
||||
value |= SUN6I_DPHY_RX_CTL_RX_D2_FORCE;
|
||||
if (dphy->config.lanes == 4)
|
||||
value |= SUN6I_DPHY_RX_CTL_RX_D3_FORCE;
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_RX_CTL_REG, value);
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG,
|
||||
SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) |
|
||||
SUN6I_DPHY_GCTL_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sun6i_dphy_power_on(struct phy *phy)
|
||||
{
|
||||
struct sun6i_dphy *dphy = phy_get_drvdata(phy);
|
||||
|
||||
switch (dphy->direction) {
|
||||
case SUN6I_DPHY_DIRECTION_TX:
|
||||
return sun6i_dphy_tx_power_on(dphy);
|
||||
case SUN6I_DPHY_DIRECTION_RX:
|
||||
return sun6i_dphy_rx_power_on(dphy);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int sun6i_dphy_power_off(struct phy *phy)
|
||||
{
|
||||
struct sun6i_dphy *dphy = phy_get_drvdata(phy);
|
||||
|
||||
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
|
||||
SUN6I_DPHY_ANA1_REG_VTTMODE, 0);
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, 0);
|
||||
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, 0);
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, 0);
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, 0);
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, 0);
|
||||
regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -253,7 +401,9 @@ static int sun6i_dphy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct phy_provider *phy_provider;
|
||||
struct sun6i_dphy *dphy;
|
||||
const char *direction;
|
||||
void __iomem *regs;
|
||||
int ret;
|
||||
|
||||
dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
|
||||
if (!dphy)
|
||||
@ -290,6 +440,14 @@ static int sun6i_dphy_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(dphy->phy);
|
||||
}
|
||||
|
||||
dphy->direction = SUN6I_DPHY_DIRECTION_TX;
|
||||
|
||||
ret = of_property_read_string(pdev->dev.of_node, "allwinner,direction",
|
||||
&direction);
|
||||
|
||||
if (!ret && !strncmp(direction, "rx", 2))
|
||||
dphy->direction = SUN6I_DPHY_DIRECTION_RX;
|
||||
|
||||
phy_set_drvdata(dphy->phy, dphy);
|
||||
phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
|
||||
|
||||
|
@ -83,6 +83,7 @@
|
||||
#define SIERRA_DFE_BIASTRIM_PREG 0x04C
|
||||
#define SIERRA_DRVCTRL_ATTEN_PREG 0x06A
|
||||
#define SIERRA_DRVCTRL_BOOST_PREG 0x06F
|
||||
#define SIERRA_TX_RCVDET_OVRD_PREG 0x072
|
||||
#define SIERRA_CLKPATHCTRL_TMR_PREG 0x081
|
||||
#define SIERRA_RX_CREQ_FLTR_A_MODE3_PREG 0x085
|
||||
#define SIERRA_RX_CREQ_FLTR_A_MODE2_PREG 0x086
|
||||
@ -1684,6 +1685,66 @@ static struct cdns_sierra_vals ml_pcie_100_no_ssc_ln_vals = {
|
||||
.num_regs = ARRAY_SIZE(ml_pcie_100_no_ssc_ln_regs),
|
||||
};
|
||||
|
||||
/*
|
||||
* TI J721E:
|
||||
* refclk100MHz_32b_PCIe_ln_no_ssc, multilink, using_plllc,
|
||||
* cmn_pllcy_anaclk0_1Ghz, xcvr_pllclk_fullrt_500mhz
|
||||
*/
|
||||
static const struct cdns_reg_pairs ti_ml_pcie_100_no_ssc_ln_regs[] = {
|
||||
{0xFC08, SIERRA_DET_STANDEC_A_PREG},
|
||||
{0x001D, SIERRA_PSM_A3IN_TMR_PREG},
|
||||
{0x0004, SIERRA_PSC_LN_A3_PREG},
|
||||
{0x0004, SIERRA_PSC_LN_A4_PREG},
|
||||
{0x0004, SIERRA_PSC_LN_IDLE_PREG},
|
||||
{0x1555, SIERRA_DFE_BIASTRIM_PREG},
|
||||
{0x9703, SIERRA_DRVCTRL_BOOST_PREG},
|
||||
{0x8055, SIERRA_RX_CREQ_FLTR_A_MODE3_PREG},
|
||||
{0x80BB, SIERRA_RX_CREQ_FLTR_A_MODE2_PREG},
|
||||
{0x8351, SIERRA_RX_CREQ_FLTR_A_MODE1_PREG},
|
||||
{0x8349, SIERRA_RX_CREQ_FLTR_A_MODE0_PREG},
|
||||
{0x0002, SIERRA_CREQ_DCBIASATTEN_OVR_PREG},
|
||||
{0x9800, SIERRA_RX_CTLE_CAL_PREG},
|
||||
{0x5624, SIERRA_DEQ_CONCUR_CTRL2_PREG},
|
||||
{0x000F, SIERRA_DEQ_EPIPWR_CTRL2_PREG},
|
||||
{0x00FF, SIERRA_DEQ_FAST_MAINT_CYCLES_PREG},
|
||||
{0x4C4C, SIERRA_DEQ_ERRCMP_CTRL_PREG},
|
||||
{0x02FA, SIERRA_DEQ_OFFSET_CTRL_PREG},
|
||||
{0x02FA, SIERRA_DEQ_GAIN_CTRL_PREG},
|
||||
{0x0041, SIERRA_DEQ_GLUT0},
|
||||
{0x0082, SIERRA_DEQ_GLUT1},
|
||||
{0x00C3, SIERRA_DEQ_GLUT2},
|
||||
{0x0145, SIERRA_DEQ_GLUT3},
|
||||
{0x0186, SIERRA_DEQ_GLUT4},
|
||||
{0x09E7, SIERRA_DEQ_ALUT0},
|
||||
{0x09A6, SIERRA_DEQ_ALUT1},
|
||||
{0x0965, SIERRA_DEQ_ALUT2},
|
||||
{0x08E3, SIERRA_DEQ_ALUT3},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP0},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP1},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP2},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP3},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP4},
|
||||
{0x000F, SIERRA_DEQ_PRECUR_PREG},
|
||||
{0x0280, SIERRA_DEQ_POSTCUR_PREG},
|
||||
{0x8F00, SIERRA_DEQ_POSTCUR_DECR_PREG},
|
||||
{0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG},
|
||||
{0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG},
|
||||
{0x0100, SIERRA_DEQ_TAU_CTRL3_PREG},
|
||||
{0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG},
|
||||
{0x002B, SIERRA_CPI_TRIM_PREG},
|
||||
{0x0003, SIERRA_EPI_CTRL_PREG},
|
||||
{0x803F, SIERRA_SDFILT_H2L_A_PREG},
|
||||
{0x0004, SIERRA_RXBUFFER_CTLECTRL_PREG},
|
||||
{0x2010, SIERRA_RXBUFFER_RCDFECTRL_PREG},
|
||||
{0x4432, SIERRA_RXBUFFER_DFECTRL_PREG},
|
||||
{0x0002, SIERRA_TX_RCVDET_OVRD_PREG}
|
||||
};
|
||||
|
||||
static struct cdns_sierra_vals ti_ml_pcie_100_no_ssc_ln_vals = {
|
||||
.reg_pairs = ti_ml_pcie_100_no_ssc_ln_regs,
|
||||
.num_regs = ARRAY_SIZE(ti_ml_pcie_100_no_ssc_ln_regs),
|
||||
};
|
||||
|
||||
/* refclk100MHz_32b_PCIe_cmn_pll_int_ssc, pcie_links_using_plllc, pipe_bw_3 */
|
||||
static const struct cdns_reg_pairs pcie_100_int_ssc_plllc_cmn_regs[] = {
|
||||
{0x000E, SIERRA_CMN_PLLLC_MODE_PREG},
|
||||
@ -1765,6 +1826,69 @@ static struct cdns_sierra_vals ml_pcie_100_int_ssc_ln_vals = {
|
||||
.num_regs = ARRAY_SIZE(ml_pcie_100_int_ssc_ln_regs),
|
||||
};
|
||||
|
||||
/*
|
||||
* TI J721E:
|
||||
* refclk100MHz_32b_PCIe_ln_int_ssc, multilink, using_plllc,
|
||||
* cmn_pllcy_anaclk0_1Ghz, xcvr_pllclk_fullrt_500mhz
|
||||
*/
|
||||
static const struct cdns_reg_pairs ti_ml_pcie_100_int_ssc_ln_regs[] = {
|
||||
{0xFC08, SIERRA_DET_STANDEC_A_PREG},
|
||||
{0x001D, SIERRA_PSM_A3IN_TMR_PREG},
|
||||
{0x0004, SIERRA_PSC_LN_A3_PREG},
|
||||
{0x0004, SIERRA_PSC_LN_A4_PREG},
|
||||
{0x0004, SIERRA_PSC_LN_IDLE_PREG},
|
||||
{0x1555, SIERRA_DFE_BIASTRIM_PREG},
|
||||
{0x9703, SIERRA_DRVCTRL_BOOST_PREG},
|
||||
{0x813E, SIERRA_CLKPATHCTRL_TMR_PREG},
|
||||
{0x8047, SIERRA_RX_CREQ_FLTR_A_MODE3_PREG},
|
||||
{0x808F, SIERRA_RX_CREQ_FLTR_A_MODE2_PREG},
|
||||
{0x808F, SIERRA_RX_CREQ_FLTR_A_MODE1_PREG},
|
||||
{0x808F, SIERRA_RX_CREQ_FLTR_A_MODE0_PREG},
|
||||
{0x0002, SIERRA_CREQ_DCBIASATTEN_OVR_PREG},
|
||||
{0x9800, SIERRA_RX_CTLE_CAL_PREG},
|
||||
{0x033C, SIERRA_RX_CTLE_MAINTENANCE_PREG},
|
||||
{0x44CC, SIERRA_CREQ_EQ_OPEN_EYE_THRESH_PREG},
|
||||
{0x5624, SIERRA_DEQ_CONCUR_CTRL2_PREG},
|
||||
{0x000F, SIERRA_DEQ_EPIPWR_CTRL2_PREG},
|
||||
{0x00FF, SIERRA_DEQ_FAST_MAINT_CYCLES_PREG},
|
||||
{0x4C4C, SIERRA_DEQ_ERRCMP_CTRL_PREG},
|
||||
{0x02FA, SIERRA_DEQ_OFFSET_CTRL_PREG},
|
||||
{0x02FA, SIERRA_DEQ_GAIN_CTRL_PREG},
|
||||
{0x0041, SIERRA_DEQ_GLUT0},
|
||||
{0x0082, SIERRA_DEQ_GLUT1},
|
||||
{0x00C3, SIERRA_DEQ_GLUT2},
|
||||
{0x0145, SIERRA_DEQ_GLUT3},
|
||||
{0x0186, SIERRA_DEQ_GLUT4},
|
||||
{0x09E7, SIERRA_DEQ_ALUT0},
|
||||
{0x09A6, SIERRA_DEQ_ALUT1},
|
||||
{0x0965, SIERRA_DEQ_ALUT2},
|
||||
{0x08E3, SIERRA_DEQ_ALUT3},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP0},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP1},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP2},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP3},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP4},
|
||||
{0x000F, SIERRA_DEQ_PRECUR_PREG},
|
||||
{0x0280, SIERRA_DEQ_POSTCUR_PREG},
|
||||
{0x8F00, SIERRA_DEQ_POSTCUR_DECR_PREG},
|
||||
{0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG},
|
||||
{0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG},
|
||||
{0x0100, SIERRA_DEQ_TAU_CTRL3_PREG},
|
||||
{0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG},
|
||||
{0x002B, SIERRA_CPI_TRIM_PREG},
|
||||
{0x0003, SIERRA_EPI_CTRL_PREG},
|
||||
{0x803F, SIERRA_SDFILT_H2L_A_PREG},
|
||||
{0x0004, SIERRA_RXBUFFER_CTLECTRL_PREG},
|
||||
{0x2010, SIERRA_RXBUFFER_RCDFECTRL_PREG},
|
||||
{0x4432, SIERRA_RXBUFFER_DFECTRL_PREG},
|
||||
{0x0002, SIERRA_TX_RCVDET_OVRD_PREG}
|
||||
};
|
||||
|
||||
static struct cdns_sierra_vals ti_ml_pcie_100_int_ssc_ln_vals = {
|
||||
.reg_pairs = ti_ml_pcie_100_int_ssc_ln_regs,
|
||||
.num_regs = ARRAY_SIZE(ti_ml_pcie_100_int_ssc_ln_regs),
|
||||
};
|
||||
|
||||
/* refclk100MHz_32b_PCIe_cmn_pll_ext_ssc, pcie_links_using_plllc, pipe_bw_3 */
|
||||
static const struct cdns_reg_pairs pcie_100_ext_ssc_plllc_cmn_regs[] = {
|
||||
{0x2106, SIERRA_CMN_PLLLC_LF_COEFF_MODE1_PREG},
|
||||
@ -1840,6 +1964,69 @@ static struct cdns_sierra_vals ml_pcie_100_ext_ssc_ln_vals = {
|
||||
.num_regs = ARRAY_SIZE(ml_pcie_100_ext_ssc_ln_regs),
|
||||
};
|
||||
|
||||
/*
|
||||
* TI J721E:
|
||||
* refclk100MHz_32b_PCIe_ln_ext_ssc, multilink, using_plllc,
|
||||
* cmn_pllcy_anaclk0_1Ghz, xcvr_pllclk_fullrt_500mhz
|
||||
*/
|
||||
static const struct cdns_reg_pairs ti_ml_pcie_100_ext_ssc_ln_regs[] = {
|
||||
{0xFC08, SIERRA_DET_STANDEC_A_PREG},
|
||||
{0x001D, SIERRA_PSM_A3IN_TMR_PREG},
|
||||
{0x0004, SIERRA_PSC_LN_A3_PREG},
|
||||
{0x0004, SIERRA_PSC_LN_A4_PREG},
|
||||
{0x0004, SIERRA_PSC_LN_IDLE_PREG},
|
||||
{0x1555, SIERRA_DFE_BIASTRIM_PREG},
|
||||
{0x9703, SIERRA_DRVCTRL_BOOST_PREG},
|
||||
{0x813E, SIERRA_CLKPATHCTRL_TMR_PREG},
|
||||
{0x8047, SIERRA_RX_CREQ_FLTR_A_MODE3_PREG},
|
||||
{0x808F, SIERRA_RX_CREQ_FLTR_A_MODE2_PREG},
|
||||
{0x808F, SIERRA_RX_CREQ_FLTR_A_MODE1_PREG},
|
||||
{0x808F, SIERRA_RX_CREQ_FLTR_A_MODE0_PREG},
|
||||
{0x0002, SIERRA_CREQ_DCBIASATTEN_OVR_PREG},
|
||||
{0x9800, SIERRA_RX_CTLE_CAL_PREG},
|
||||
{0x033C, SIERRA_RX_CTLE_MAINTENANCE_PREG},
|
||||
{0x44CC, SIERRA_CREQ_EQ_OPEN_EYE_THRESH_PREG},
|
||||
{0x5624, SIERRA_DEQ_CONCUR_CTRL2_PREG},
|
||||
{0x000F, SIERRA_DEQ_EPIPWR_CTRL2_PREG},
|
||||
{0x00FF, SIERRA_DEQ_FAST_MAINT_CYCLES_PREG},
|
||||
{0x4C4C, SIERRA_DEQ_ERRCMP_CTRL_PREG},
|
||||
{0x02FA, SIERRA_DEQ_OFFSET_CTRL_PREG},
|
||||
{0x02FA, SIERRA_DEQ_GAIN_CTRL_PREG},
|
||||
{0x0041, SIERRA_DEQ_GLUT0},
|
||||
{0x0082, SIERRA_DEQ_GLUT1},
|
||||
{0x00C3, SIERRA_DEQ_GLUT2},
|
||||
{0x0145, SIERRA_DEQ_GLUT3},
|
||||
{0x0186, SIERRA_DEQ_GLUT4},
|
||||
{0x09E7, SIERRA_DEQ_ALUT0},
|
||||
{0x09A6, SIERRA_DEQ_ALUT1},
|
||||
{0x0965, SIERRA_DEQ_ALUT2},
|
||||
{0x08E3, SIERRA_DEQ_ALUT3},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP0},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP1},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP2},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP3},
|
||||
{0x00FA, SIERRA_DEQ_DFETAP4},
|
||||
{0x000F, SIERRA_DEQ_PRECUR_PREG},
|
||||
{0x0280, SIERRA_DEQ_POSTCUR_PREG},
|
||||
{0x8F00, SIERRA_DEQ_POSTCUR_DECR_PREG},
|
||||
{0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG},
|
||||
{0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG},
|
||||
{0x0100, SIERRA_DEQ_TAU_CTRL3_PREG},
|
||||
{0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG},
|
||||
{0x002B, SIERRA_CPI_TRIM_PREG},
|
||||
{0x0003, SIERRA_EPI_CTRL_PREG},
|
||||
{0x803F, SIERRA_SDFILT_H2L_A_PREG},
|
||||
{0x0004, SIERRA_RXBUFFER_CTLECTRL_PREG},
|
||||
{0x2010, SIERRA_RXBUFFER_RCDFECTRL_PREG},
|
||||
{0x4432, SIERRA_RXBUFFER_DFECTRL_PREG},
|
||||
{0x0002, SIERRA_TX_RCVDET_OVRD_PREG}
|
||||
};
|
||||
|
||||
static struct cdns_sierra_vals ti_ml_pcie_100_ext_ssc_ln_vals = {
|
||||
.reg_pairs = ti_ml_pcie_100_ext_ssc_ln_regs,
|
||||
.num_regs = ARRAY_SIZE(ti_ml_pcie_100_ext_ssc_ln_regs),
|
||||
};
|
||||
|
||||
/* refclk100MHz_32b_PCIe_cmn_pll_no_ssc */
|
||||
static const struct cdns_reg_pairs cdns_pcie_cmn_regs_no_ssc[] = {
|
||||
{0x2105, SIERRA_CMN_PLLLC_LF_COEFF_MODE1_PREG},
|
||||
@ -2299,9 +2486,9 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = {
|
||||
[INTERNAL_SSC] = &pcie_100_int_ssc_ln_vals,
|
||||
},
|
||||
[TYPE_QSGMII] = {
|
||||
[NO_SSC] = &ml_pcie_100_no_ssc_ln_vals,
|
||||
[EXTERNAL_SSC] = &ml_pcie_100_ext_ssc_ln_vals,
|
||||
[INTERNAL_SSC] = &ml_pcie_100_int_ssc_ln_vals,
|
||||
[NO_SSC] = &ti_ml_pcie_100_no_ssc_ln_vals,
|
||||
[EXTERNAL_SSC] = &ti_ml_pcie_100_ext_ssc_ln_vals,
|
||||
[INTERNAL_SSC] = &ti_ml_pcie_100_int_ssc_ln_vals,
|
||||
},
|
||||
},
|
||||
[TYPE_USB] = {
|
||||
|
@ -4,17 +4,33 @@
|
||||
* Copyright 2019 Purism SPC
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/firmware/imx/ipc.h>
|
||||
#include <linux/firmware/imx/svc/misc.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <dt-bindings/firmware/imx/rsrc.h>
|
||||
|
||||
/* Control and Status Registers(CSR) */
|
||||
#define PHY_CTRL 0x00
|
||||
#define CCM_MASK GENMASK(7, 5)
|
||||
#define CCM(n) FIELD_PREP(CCM_MASK, (n))
|
||||
#define CCM_1_2V 0x5
|
||||
#define CA_MASK GENMASK(4, 2)
|
||||
#define CA_3_51MA 0x4
|
||||
#define CA(n) FIELD_PREP(CA_MASK, (n))
|
||||
#define RFB BIT(1)
|
||||
#define LVDS_EN BIT(0)
|
||||
|
||||
/* DPHY registers */
|
||||
#define DPHY_PD_DPHY 0x00
|
||||
@ -55,8 +71,15 @@
|
||||
#define PWR_ON 0
|
||||
#define PWR_OFF 1
|
||||
|
||||
#define MIN_VCO_FREQ 640000000
|
||||
#define MAX_VCO_FREQ 1500000000
|
||||
|
||||
#define MIN_LVDS_REFCLK_FREQ 24000000
|
||||
#define MAX_LVDS_REFCLK_FREQ 150000000
|
||||
|
||||
enum mixel_dphy_devtype {
|
||||
MIXEL_IMX8MQ,
|
||||
MIXEL_IMX8QXP,
|
||||
};
|
||||
|
||||
struct mixel_dphy_devdata {
|
||||
@ -65,6 +88,7 @@ struct mixel_dphy_devdata {
|
||||
u8 reg_rxlprp;
|
||||
u8 reg_rxcdrp;
|
||||
u8 reg_rxhs_settle;
|
||||
bool is_combo; /* MIPI DPHY and LVDS PHY combo */
|
||||
};
|
||||
|
||||
static const struct mixel_dphy_devdata mixel_dphy_devdata[] = {
|
||||
@ -74,6 +98,10 @@ static const struct mixel_dphy_devdata mixel_dphy_devdata[] = {
|
||||
.reg_rxlprp = 0x40,
|
||||
.reg_rxcdrp = 0x44,
|
||||
.reg_rxhs_settle = 0x48,
|
||||
.is_combo = false,
|
||||
},
|
||||
[MIXEL_IMX8QXP] = {
|
||||
.is_combo = true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -95,8 +123,12 @@ struct mixel_dphy_cfg {
|
||||
struct mixel_dphy_priv {
|
||||
struct mixel_dphy_cfg cfg;
|
||||
struct regmap *regmap;
|
||||
struct regmap *lvds_regmap;
|
||||
struct clk *phy_ref_clk;
|
||||
const struct mixel_dphy_devdata *devdata;
|
||||
struct imx_sc_ipc *ipc_handle;
|
||||
bool is_slave;
|
||||
int id;
|
||||
};
|
||||
|
||||
static const struct regmap_config mixel_dphy_regmap_config = {
|
||||
@ -317,7 +349,8 @@ static int mixel_dphy_set_pll_params(struct phy *phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mixel_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
|
||||
static int
|
||||
mixel_dphy_configure_mipi_dphy(struct phy *phy, union phy_configure_opts *opts)
|
||||
{
|
||||
struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
|
||||
struct mixel_dphy_cfg cfg = { 0 };
|
||||
@ -345,15 +378,126 @@ static int mixel_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mixel_dphy_configure_lvds_phy(struct phy *phy, union phy_configure_opts *opts)
|
||||
{
|
||||
struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
|
||||
struct phy_configure_opts_lvds *lvds_opts = &opts->lvds;
|
||||
unsigned long data_rate;
|
||||
unsigned long fvco;
|
||||
u32 rsc;
|
||||
u32 co;
|
||||
int ret;
|
||||
|
||||
priv->is_slave = lvds_opts->is_slave;
|
||||
|
||||
/* LVDS interface pins */
|
||||
regmap_write(priv->lvds_regmap, PHY_CTRL,
|
||||
CCM(CCM_1_2V) | CA(CA_3_51MA) | RFB);
|
||||
|
||||
/* enable MODE8 only for slave LVDS PHY */
|
||||
rsc = priv->id ? IMX_SC_R_MIPI_1 : IMX_SC_R_MIPI_0;
|
||||
ret = imx_sc_misc_set_control(priv->ipc_handle, rsc, IMX_SC_C_DUAL_MODE,
|
||||
lvds_opts->is_slave);
|
||||
if (ret) {
|
||||
dev_err(&phy->dev, "Failed to configure MODE8: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Choose an appropriate divider ratio to meet the requirement of
|
||||
* PLL VCO frequency range.
|
||||
*
|
||||
* ----- 640MHz ~ 1500MHz ------------ ---------------
|
||||
* | VCO | ----------------> | CO divider | -> | LVDS data rate|
|
||||
* ----- FVCO ------------ ---------------
|
||||
* 1/2/4/8 div 7 * differential_clk_rate
|
||||
*/
|
||||
data_rate = 7 * lvds_opts->differential_clk_rate;
|
||||
for (co = 1; co <= 8; co *= 2) {
|
||||
fvco = data_rate * co;
|
||||
|
||||
if (fvco >= MIN_VCO_FREQ)
|
||||
break;
|
||||
}
|
||||
|
||||
if (fvco < MIN_VCO_FREQ || fvco > MAX_VCO_FREQ) {
|
||||
dev_err(&phy->dev, "VCO frequency %lu is out of range\n", fvco);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/*
|
||||
* CO is configurable, while CN and CM are not,
|
||||
* as fixed ratios 1 and 7 are applied respectively.
|
||||
*/
|
||||
phy_write(phy, __ffs(co), DPHY_CO);
|
||||
|
||||
/* set reference clock rate */
|
||||
clk_set_rate(priv->phy_ref_clk, lvds_opts->differential_clk_rate);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mixel_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
|
||||
{
|
||||
if (!opts) {
|
||||
dev_err(&phy->dev, "No configuration options\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (phy->attrs.mode == PHY_MODE_MIPI_DPHY)
|
||||
return mixel_dphy_configure_mipi_dphy(phy, opts);
|
||||
else if (phy->attrs.mode == PHY_MODE_LVDS)
|
||||
return mixel_dphy_configure_lvds_phy(phy, opts);
|
||||
|
||||
dev_err(&phy->dev,
|
||||
"Failed to configure PHY with invalid PHY mode: %d\n", phy->attrs.mode);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
mixel_dphy_validate_lvds_phy(struct phy *phy, union phy_configure_opts *opts)
|
||||
{
|
||||
struct phy_configure_opts_lvds *lvds_cfg = &opts->lvds;
|
||||
|
||||
if (lvds_cfg->bits_per_lane_and_dclk_cycle != 7) {
|
||||
dev_err(&phy->dev, "Invalid bits per LVDS data lane: %u\n",
|
||||
lvds_cfg->bits_per_lane_and_dclk_cycle);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (lvds_cfg->lanes != 4) {
|
||||
dev_err(&phy->dev, "Invalid LVDS data lanes: %u\n", lvds_cfg->lanes);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (lvds_cfg->differential_clk_rate < MIN_LVDS_REFCLK_FREQ ||
|
||||
lvds_cfg->differential_clk_rate > MAX_LVDS_REFCLK_FREQ) {
|
||||
dev_err(&phy->dev,
|
||||
"Invalid LVDS differential clock rate: %lu\n",
|
||||
lvds_cfg->differential_clk_rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mixel_dphy_validate(struct phy *phy, enum phy_mode mode, int submode,
|
||||
union phy_configure_opts *opts)
|
||||
{
|
||||
struct mixel_dphy_cfg cfg = { 0 };
|
||||
if (mode == PHY_MODE_MIPI_DPHY) {
|
||||
struct mixel_dphy_cfg mipi_dphy_cfg = { 0 };
|
||||
|
||||
if (mode != PHY_MODE_MIPI_DPHY)
|
||||
return -EINVAL;
|
||||
return mixel_dphy_config_from_opts(phy, &opts->mipi_dphy,
|
||||
&mipi_dphy_cfg);
|
||||
} else if (mode == PHY_MODE_LVDS) {
|
||||
return mixel_dphy_validate_lvds_phy(phy, opts);
|
||||
}
|
||||
|
||||
return mixel_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg);
|
||||
dev_err(&phy->dev,
|
||||
"Failed to validate PHY with invalid PHY mode: %d\n", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int mixel_dphy_init(struct phy *phy)
|
||||
@ -373,26 +517,74 @@ static int mixel_dphy_exit(struct phy *phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mixel_dphy_power_on(struct phy *phy)
|
||||
static int mixel_dphy_power_on_mipi_dphy(struct phy *phy)
|
||||
{
|
||||
struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
|
||||
u32 locked;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(priv->phy_ref_clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
phy_write(phy, PWR_ON, DPHY_PD_PLL);
|
||||
ret = regmap_read_poll_timeout(priv->regmap, DPHY_LOCK, locked,
|
||||
locked, PLL_LOCK_SLEEP,
|
||||
PLL_LOCK_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
dev_err(&phy->dev, "Could not get DPHY lock (%d)!\n", ret);
|
||||
goto clock_disable;
|
||||
return ret;
|
||||
}
|
||||
phy_write(phy, PWR_ON, DPHY_PD_DPHY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mixel_dphy_power_on_lvds_phy(struct phy *phy)
|
||||
{
|
||||
struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
|
||||
u32 locked;
|
||||
int ret;
|
||||
|
||||
regmap_update_bits(priv->lvds_regmap, PHY_CTRL, LVDS_EN, LVDS_EN);
|
||||
|
||||
phy_write(phy, PWR_ON, DPHY_PD_DPHY);
|
||||
phy_write(phy, PWR_ON, DPHY_PD_PLL);
|
||||
|
||||
/* do not wait for slave LVDS PHY being locked */
|
||||
if (priv->is_slave)
|
||||
return 0;
|
||||
|
||||
ret = regmap_read_poll_timeout(priv->regmap, DPHY_LOCK, locked,
|
||||
locked, PLL_LOCK_SLEEP,
|
||||
PLL_LOCK_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
dev_err(&phy->dev, "Could not get LVDS PHY lock (%d)!\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mixel_dphy_power_on(struct phy *phy)
|
||||
{
|
||||
struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(priv->phy_ref_clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (phy->attrs.mode == PHY_MODE_MIPI_DPHY) {
|
||||
ret = mixel_dphy_power_on_mipi_dphy(phy);
|
||||
} else if (phy->attrs.mode == PHY_MODE_LVDS) {
|
||||
ret = mixel_dphy_power_on_lvds_phy(phy);
|
||||
} else {
|
||||
dev_err(&phy->dev,
|
||||
"Failed to power on PHY with invalid PHY mode: %d\n",
|
||||
phy->attrs.mode);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto clock_disable;
|
||||
|
||||
return 0;
|
||||
clock_disable:
|
||||
clk_disable_unprepare(priv->phy_ref_clk);
|
||||
@ -406,16 +598,51 @@ static int mixel_dphy_power_off(struct phy *phy)
|
||||
phy_write(phy, PWR_OFF, DPHY_PD_PLL);
|
||||
phy_write(phy, PWR_OFF, DPHY_PD_DPHY);
|
||||
|
||||
if (phy->attrs.mode == PHY_MODE_LVDS)
|
||||
regmap_update_bits(priv->lvds_regmap, PHY_CTRL, LVDS_EN, 0);
|
||||
|
||||
clk_disable_unprepare(priv->phy_ref_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mixel_dphy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
|
||||
{
|
||||
struct mixel_dphy_priv *priv = phy_get_drvdata(phy);
|
||||
int ret;
|
||||
|
||||
if (priv->devdata->is_combo && mode != PHY_MODE_LVDS) {
|
||||
dev_err(&phy->dev, "Failed to set PHY mode for combo PHY\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!priv->devdata->is_combo && mode != PHY_MODE_MIPI_DPHY) {
|
||||
dev_err(&phy->dev, "Failed to set PHY mode to MIPI DPHY\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (priv->devdata->is_combo) {
|
||||
u32 rsc = priv->id ? IMX_SC_R_MIPI_1 : IMX_SC_R_MIPI_0;
|
||||
|
||||
ret = imx_sc_misc_set_control(priv->ipc_handle,
|
||||
rsc, IMX_SC_C_MODE,
|
||||
mode == PHY_MODE_LVDS);
|
||||
if (ret) {
|
||||
dev_err(&phy->dev,
|
||||
"Failed to set PHY mode via SCU ipc: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops mixel_dphy_phy_ops = {
|
||||
.init = mixel_dphy_init,
|
||||
.exit = mixel_dphy_exit,
|
||||
.power_on = mixel_dphy_power_on,
|
||||
.power_off = mixel_dphy_power_off,
|
||||
.set_mode = mixel_dphy_set_mode,
|
||||
.configure = mixel_dphy_configure,
|
||||
.validate = mixel_dphy_validate,
|
||||
.owner = THIS_MODULE,
|
||||
@ -424,6 +651,8 @@ static const struct phy_ops mixel_dphy_phy_ops = {
|
||||
static const struct of_device_id mixel_dphy_of_match[] = {
|
||||
{ .compatible = "fsl,imx8mq-mipi-dphy",
|
||||
.data = &mixel_dphy_devdata[MIXEL_IMX8MQ] },
|
||||
{ .compatible = "fsl,imx8qxp-mipi-dphy",
|
||||
.data = &mixel_dphy_devdata[MIXEL_IMX8QXP] },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mixel_dphy_of_match);
|
||||
@ -436,6 +665,7 @@ static int mixel_dphy_probe(struct platform_device *pdev)
|
||||
struct mixel_dphy_priv *priv;
|
||||
struct phy *phy;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
@ -467,6 +697,30 @@ static int mixel_dphy_probe(struct platform_device *pdev)
|
||||
dev_dbg(dev, "phy_ref clock rate: %lu\n",
|
||||
clk_get_rate(priv->phy_ref_clk));
|
||||
|
||||
if (priv->devdata->is_combo) {
|
||||
priv->lvds_regmap =
|
||||
syscon_regmap_lookup_by_phandle(np, "fsl,syscon");
|
||||
if (IS_ERR(priv->lvds_regmap)) {
|
||||
ret = PTR_ERR(priv->lvds_regmap);
|
||||
dev_err_probe(dev, ret, "Failed to get LVDS regmap\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->id = of_alias_get_id(np, "mipi_dphy");
|
||||
if (priv->id < 0) {
|
||||
dev_err(dev, "Failed to get phy node alias id: %d\n",
|
||||
priv->id);
|
||||
return priv->id;
|
||||
}
|
||||
|
||||
ret = imx_scu_get_handle(&priv->ipc_handle);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret,
|
||||
"Failed to get SCU ipc handle\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, priv);
|
||||
|
||||
phy = devm_phy_create(dev, np, &mixel_dphy_phy_ops);
|
||||
|
@ -94,15 +94,21 @@ static int imx8_pcie_phy_init(struct phy *phy)
|
||||
IMX8MM_GPR_PCIE_CMN_RST);
|
||||
usleep_range(200, 500);
|
||||
|
||||
if (pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT) {
|
||||
if (pad_mode == IMX8_PCIE_REFCLK_PAD_INPUT ||
|
||||
pad_mode == IMX8_PCIE_REFCLK_PAD_UNUSED) {
|
||||
/* Configure the pad as input */
|
||||
val = readl(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
|
||||
writel(val & ~ANA_PLL_CLK_OUT_TO_EXT_IO_EN,
|
||||
imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
|
||||
} else if (pad_mode == IMX8_PCIE_REFCLK_PAD_OUTPUT) {
|
||||
} else {
|
||||
/* Configure the PHY to output the refclock via pad */
|
||||
writel(ANA_PLL_CLK_OUT_TO_EXT_IO_EN,
|
||||
imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
|
||||
}
|
||||
|
||||
if (pad_mode == IMX8_PCIE_REFCLK_PAD_OUTPUT ||
|
||||
pad_mode == IMX8_PCIE_REFCLK_PAD_UNUSED) {
|
||||
/* Source clock from SoC internal PLL */
|
||||
writel(ANA_PLL_CLK_OUT_TO_EXT_IO_SEL,
|
||||
imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG062);
|
||||
writel(AUX_PLL_REFCLK_SEL_SYS_PLL,
|
||||
|
@ -120,20 +120,16 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(hdmi_phy->regs);
|
||||
|
||||
ref_clk = devm_clk_get(dev, "pll_ref");
|
||||
if (IS_ERR(ref_clk)) {
|
||||
ret = PTR_ERR(ref_clk);
|
||||
dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(ref_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(ref_clk),
|
||||
"Failed to get PLL reference clock\n");
|
||||
|
||||
ref_clk_name = __clk_get_name(ref_clk);
|
||||
|
||||
ret = of_property_read_string(dev->of_node, "clock-output-names",
|
||||
&clk_init.name);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to read clock-output-names: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to read clock-output-names\n");
|
||||
|
||||
hdmi_phy->dev = dev;
|
||||
hdmi_phy->conf =
|
||||
@ -141,25 +137,19 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev)
|
||||
mtk_hdmi_phy_clk_get_data(hdmi_phy, &clk_init);
|
||||
hdmi_phy->pll_hw.init = &clk_init;
|
||||
hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw);
|
||||
if (IS_ERR(hdmi_phy->pll)) {
|
||||
ret = PTR_ERR(hdmi_phy->pll);
|
||||
dev_err(dev, "Failed to register PLL: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(hdmi_phy->pll))
|
||||
return dev_err_probe(dev, PTR_ERR(hdmi_phy->pll),
|
||||
"Failed to register PLL\n");
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "mediatek,ibias",
|
||||
&hdmi_phy->ibias);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to get ibias\n");
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up",
|
||||
&hdmi_phy->ibias_up);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to get ibias_up\n");
|
||||
|
||||
dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n");
|
||||
hdmi_phy->drv_imp_clk = 0x30;
|
||||
@ -168,17 +158,15 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev)
|
||||
hdmi_phy->drv_imp_d0 = 0x30;
|
||||
|
||||
phy = devm_phy_create(dev, NULL, mtk_hdmi_phy_dev_get_ops(hdmi_phy));
|
||||
if (IS_ERR(phy)) {
|
||||
dev_err(dev, "Failed to create HDMI PHY\n");
|
||||
return PTR_ERR(phy);
|
||||
}
|
||||
if (IS_ERR(phy))
|
||||
return dev_err_probe(dev, PTR_ERR(phy), "Cannot create HDMI PHY\n");
|
||||
|
||||
phy_set_drvdata(phy, hdmi_phy);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(phy_provider)) {
|
||||
dev_err(dev, "Failed to register HDMI PHY\n");
|
||||
return PTR_ERR(phy_provider);
|
||||
}
|
||||
if (IS_ERR(phy_provider))
|
||||
return dev_err_probe(dev, PTR_ERR(phy_provider),
|
||||
"Failed to register HDMI PHY\n");
|
||||
|
||||
if (hdmi_phy->conf->pll_default_off)
|
||||
hdmi_phy->conf->hdmi_phy_disable_tmds(hdmi_phy);
|
||||
|
@ -154,11 +154,9 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(mipi_tx->regs);
|
||||
|
||||
ref_clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(ref_clk)) {
|
||||
ret = PTR_ERR(ref_clk);
|
||||
dev_err(dev, "Failed to get reference clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(ref_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(ref_clk),
|
||||
"Failed to get reference clock\n");
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "drive-strength-microamp",
|
||||
&mipi_tx->mipitx_drive);
|
||||
@ -178,27 +176,20 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
|
||||
|
||||
ret = of_property_read_string(dev->of_node, "clock-output-names",
|
||||
&clk_init.name);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to read clock-output-names: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "Failed to read clock-output-names\n");
|
||||
|
||||
clk_init.ops = mipi_tx->driver_data->mipi_tx_clk_ops;
|
||||
|
||||
mipi_tx->pll_hw.init = &clk_init;
|
||||
mipi_tx->pll = devm_clk_register(dev, &mipi_tx->pll_hw);
|
||||
if (IS_ERR(mipi_tx->pll)) {
|
||||
ret = PTR_ERR(mipi_tx->pll);
|
||||
dev_err(dev, "Failed to register PLL: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(mipi_tx->pll))
|
||||
return dev_err_probe(dev, PTR_ERR(mipi_tx->pll), "Failed to register PLL\n");
|
||||
|
||||
phy = devm_phy_create(dev, NULL, &mtk_mipi_tx_ops);
|
||||
if (IS_ERR(phy)) {
|
||||
ret = PTR_ERR(phy);
|
||||
dev_err(dev, "Failed to create MIPI D-PHY: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(phy))
|
||||
return dev_err_probe(dev, PTR_ERR(phy), "Failed to create MIPI D-PHY\n");
|
||||
|
||||
phy_set_drvdata(phy, mipi_tx);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include<linux/module.h>
|
||||
#include<linux/gpio.h>
|
||||
#include<linux/gpio/consumer.h>
|
||||
#include <linux/mux/consumer.h>
|
||||
|
||||
struct can_transceiver_data {
|
||||
u32 flags;
|
||||
@ -21,13 +22,22 @@ struct can_transceiver_phy {
|
||||
struct phy *generic_phy;
|
||||
struct gpio_desc *standby_gpio;
|
||||
struct gpio_desc *enable_gpio;
|
||||
struct mux_state *mux_state;
|
||||
};
|
||||
|
||||
/* Power on function */
|
||||
static int can_transceiver_phy_power_on(struct phy *phy)
|
||||
{
|
||||
struct can_transceiver_phy *can_transceiver_phy = phy_get_drvdata(phy);
|
||||
int ret;
|
||||
|
||||
if (can_transceiver_phy->mux_state) {
|
||||
ret = mux_state_select(can_transceiver_phy->mux_state);
|
||||
if (ret) {
|
||||
dev_err(&phy->dev, "Failed to select CAN mux: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (can_transceiver_phy->standby_gpio)
|
||||
gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 0);
|
||||
if (can_transceiver_phy->enable_gpio)
|
||||
@ -45,6 +55,8 @@ static int can_transceiver_phy_power_off(struct phy *phy)
|
||||
gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 1);
|
||||
if (can_transceiver_phy->enable_gpio)
|
||||
gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 0);
|
||||
if (can_transceiver_phy->mux_state)
|
||||
mux_state_deselect(can_transceiver_phy->mux_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -95,6 +107,16 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
|
||||
match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node);
|
||||
drvdata = match->data;
|
||||
|
||||
if (of_property_read_bool(dev->of_node, "mux-states")) {
|
||||
struct mux_state *mux_state;
|
||||
|
||||
mux_state = devm_mux_state_get(dev, NULL);
|
||||
if (IS_ERR(mux_state))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(mux_state),
|
||||
"failed to get mux\n");
|
||||
can_transceiver_phy->mux_state = mux_state;
|
||||
}
|
||||
|
||||
phy = devm_phy_create(dev, dev->of_node,
|
||||
&can_transceiver_phy_ops);
|
||||
if (IS_ERR(phy)) {
|
||||
|
@ -229,6 +229,17 @@ void phy_pm_runtime_forbid(struct phy *phy)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_pm_runtime_forbid);
|
||||
|
||||
/**
|
||||
* phy_init - phy internal initialization before phy operation
|
||||
* @phy: the phy returned by phy_get()
|
||||
*
|
||||
* Used to allow phy's driver to perform phy internal initialization,
|
||||
* such as PLL block powering, clock initialization or anything that's
|
||||
* is required by the phy to perform the start of operation.
|
||||
* Must be called before phy_power_on().
|
||||
*
|
||||
* Return: %0 if successful, a negative error code otherwise
|
||||
*/
|
||||
int phy_init(struct phy *phy)
|
||||
{
|
||||
int ret;
|
||||
@ -242,6 +253,9 @@ int phy_init(struct phy *phy)
|
||||
ret = 0; /* Override possible ret == -ENOTSUPP */
|
||||
|
||||
mutex_lock(&phy->mutex);
|
||||
if (phy->power_count > phy->init_count)
|
||||
dev_warn(&phy->dev, "phy_power_on was called before phy_init\n");
|
||||
|
||||
if (phy->init_count == 0 && phy->ops->init) {
|
||||
ret = phy->ops->init(phy);
|
||||
if (ret < 0) {
|
||||
@ -258,6 +272,14 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_init);
|
||||
|
||||
/**
|
||||
* phy_exit - Phy internal un-initialization
|
||||
* @phy: the phy returned by phy_get()
|
||||
*
|
||||
* Must be called after phy_power_off().
|
||||
*
|
||||
* Return: %0 if successful, a negative error code otherwise
|
||||
*/
|
||||
int phy_exit(struct phy *phy)
|
||||
{
|
||||
int ret;
|
||||
@ -287,6 +309,14 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_exit);
|
||||
|
||||
/**
|
||||
* phy_power_on - Enable the phy and enter proper operation
|
||||
* @phy: the phy returned by phy_get()
|
||||
*
|
||||
* Must be called after phy_init().
|
||||
*
|
||||
* Return: %0 if successful, a negative error code otherwise
|
||||
*/
|
||||
int phy_power_on(struct phy *phy)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -329,6 +359,14 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_power_on);
|
||||
|
||||
/**
|
||||
* phy_power_off - Disable the phy.
|
||||
* @phy: the phy returned by phy_get()
|
||||
*
|
||||
* Must be called before phy_exit().
|
||||
*
|
||||
* Return: %0 if successful, a negative error code otherwise
|
||||
*/
|
||||
int phy_power_off(struct phy *phy)
|
||||
{
|
||||
int ret;
|
||||
@ -432,7 +470,7 @@ EXPORT_SYMBOL_GPL(phy_reset);
|
||||
* runtime, which are otherwise lost after host controller reset and cannot
|
||||
* be applied in phy_init() or phy_power_on().
|
||||
*
|
||||
* Returns: 0 if successful, an negative error code otherwise
|
||||
* Return: %0 if successful, a negative error code otherwise
|
||||
*/
|
||||
int phy_calibrate(struct phy *phy)
|
||||
{
|
||||
@ -458,7 +496,7 @@ EXPORT_SYMBOL_GPL(phy_calibrate);
|
||||
* on the phy. The configuration will be applied on the current phy
|
||||
* mode, that can be changed using phy_set_mode().
|
||||
*
|
||||
* Returns: 0 if successful, an negative error code otherwise
|
||||
* Return: %0 if successful, a negative error code otherwise
|
||||
*/
|
||||
int phy_configure(struct phy *phy, union phy_configure_opts *opts)
|
||||
{
|
||||
@ -492,7 +530,7 @@ EXPORT_SYMBOL_GPL(phy_configure);
|
||||
* PHY, so calling it as many times as deemed fit will have no side
|
||||
* effect.
|
||||
*
|
||||
* Returns: 0 if successful, an negative error code otherwise
|
||||
* Return: %0 if successful, a negative error code otherwise
|
||||
*/
|
||||
int phy_validate(struct phy *phy, enum phy_mode mode, int submode,
|
||||
union phy_configure_opts *opts)
|
||||
|
@ -2535,6 +2535,50 @@ static const struct qmp_phy_init_tbl sdx55_qmp_pcie_pcs_misc_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_LANE1_INSIG_MX_CTRL2, 0x00),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl sdx65_usb3_uniphy_tx_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0xa5),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_2, 0x82),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_3, 0x3f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_4, 0x3f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_TX_PI_QEC_CTRL, 0x21),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x0b),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl sdx65_usb3_uniphy_rx_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xdb),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0xbd),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xff),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH, 0x7f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_LOW, 0xff),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xa9),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x7b),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH2, 0xe4),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH, 0x24),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_LOW, 0x64),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_PI_CONTROLS, 0x99),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH1, 0x08),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH2, 0x08),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_GAIN1, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_GAIN2, 0x04),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FO_GAIN, 0x0a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL1, 0x54),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x0f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x47),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_CNTRL, 0x04),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, 0x0e),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SO_GAIN, 0x05),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_GM_CAL, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_ENABLES, 0x00),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl sm8350_ufsphy_serdes_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0xd9),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_SEL, 0x11),
|
||||
@ -3177,7 +3221,7 @@ struct qmp_phy_combo_cfg {
|
||||
* @tx2: iomapped memory space for second lane's tx (in dual lane PHYs)
|
||||
* @rx2: iomapped memory space for second lane's rx (in dual lane PHYs)
|
||||
* @pcs_misc: iomapped memory space for lane's pcs_misc
|
||||
* @pipe_clk: pipe lock
|
||||
* @pipe_clk: pipe clock
|
||||
* @index: lane index
|
||||
* @qmp: QMP phy to which this lane belongs
|
||||
* @lane_rst: lane's reset controller
|
||||
@ -4217,6 +4261,35 @@ static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = {
|
||||
.pwrdn_delay_max = 1005, /* us */
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg sdx65_usb3_uniphy_cfg = {
|
||||
.type = PHY_TYPE_USB3,
|
||||
.nlanes = 1,
|
||||
|
||||
.serdes_tbl = sm8150_usb3_uniphy_serdes_tbl,
|
||||
.serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_uniphy_serdes_tbl),
|
||||
.tx_tbl = sdx65_usb3_uniphy_tx_tbl,
|
||||
.tx_tbl_num = ARRAY_SIZE(sdx65_usb3_uniphy_tx_tbl),
|
||||
.rx_tbl = sdx65_usb3_uniphy_rx_tbl,
|
||||
.rx_tbl_num = ARRAY_SIZE(sdx65_usb3_uniphy_rx_tbl),
|
||||
.pcs_tbl = sm8350_usb3_uniphy_pcs_tbl,
|
||||
.pcs_tbl_num = ARRAY_SIZE(sm8350_usb3_uniphy_pcs_tbl),
|
||||
.clk_list = qmp_v4_sdx55_usbphy_clk_l,
|
||||
.num_clks = ARRAY_SIZE(qmp_v4_sdx55_usbphy_clk_l),
|
||||
.reset_list = msm8996_usb3phy_reset_l,
|
||||
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
|
||||
.vreg_list = qmp_phy_vreg_l,
|
||||
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||
.regs = sm8350_usb3_uniphy_regs_layout,
|
||||
|
||||
.start_ctrl = SERDES_START | PCS_START,
|
||||
.pwrdn_ctrl = SW_PWRDN,
|
||||
.phy_status = PHYSTATUS,
|
||||
|
||||
.has_pwrdn_delay = true,
|
||||
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
|
||||
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
|
||||
.type = PHY_TYPE_UFS,
|
||||
.nlanes = 2,
|
||||
@ -5012,7 +5085,7 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
|
||||
ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
|
||||
if (ret) {
|
||||
dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
|
||||
goto err_reg_enable;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
for (i = 0; i < cfg->num_resets; i++) {
|
||||
@ -5020,7 +5093,7 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
|
||||
if (ret) {
|
||||
dev_err(qmp->dev, "%s reset assert failed\n",
|
||||
cfg->reset_list[i]);
|
||||
goto err_rst_assert;
|
||||
goto err_disable_regulators;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5029,13 +5102,13 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
|
||||
if (ret) {
|
||||
dev_err(qmp->dev, "%s reset deassert failed\n",
|
||||
qphy->cfg->reset_list[i]);
|
||||
goto err_rst;
|
||||
goto err_assert_reset;
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
|
||||
if (ret)
|
||||
goto err_rst;
|
||||
goto err_assert_reset;
|
||||
|
||||
if (cfg->has_phy_dp_com_ctrl) {
|
||||
qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL,
|
||||
@ -5077,12 +5150,12 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
|
||||
|
||||
return 0;
|
||||
|
||||
err_rst:
|
||||
err_assert_reset:
|
||||
while (++i < cfg->num_resets)
|
||||
reset_control_assert(qmp->resets[i]);
|
||||
err_rst_assert:
|
||||
err_disable_regulators:
|
||||
regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
|
||||
err_reg_enable:
|
||||
err_unlock:
|
||||
mutex_unlock(&qmp->phy_mutex);
|
||||
|
||||
return ret;
|
||||
@ -5188,14 +5261,14 @@ static int qcom_qmp_phy_power_on(struct phy *phy)
|
||||
if (ret) {
|
||||
dev_err(qmp->dev, "lane%d reset deassert failed\n",
|
||||
qphy->index);
|
||||
goto err_lane_rst;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(qphy->pipe_clk);
|
||||
if (ret) {
|
||||
dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret);
|
||||
goto err_clk_enable;
|
||||
goto err_reset_lane;
|
||||
}
|
||||
|
||||
/* Tx, Rx, and PCS configurations */
|
||||
@ -5246,7 +5319,7 @@ static int qcom_qmp_phy_power_on(struct phy *phy)
|
||||
|
||||
ret = reset_control_deassert(qmp->ufs_reset);
|
||||
if (ret)
|
||||
goto err_lane_rst;
|
||||
goto err_disable_pipe_clk;
|
||||
|
||||
qcom_qmp_phy_configure(pcs_misc, cfg->regs, cfg->pcs_misc_tbl,
|
||||
cfg->pcs_misc_tbl_num);
|
||||
@ -5285,17 +5358,17 @@ static int qcom_qmp_phy_power_on(struct phy *phy)
|
||||
PHY_INIT_COMPLETE_TIMEOUT);
|
||||
if (ret) {
|
||||
dev_err(qmp->dev, "phy initialization timed-out\n");
|
||||
goto err_pcs_ready;
|
||||
goto err_disable_pipe_clk;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_pcs_ready:
|
||||
err_disable_pipe_clk:
|
||||
clk_disable_unprepare(qphy->pipe_clk);
|
||||
err_clk_enable:
|
||||
err_reset_lane:
|
||||
if (cfg->has_lane_rst)
|
||||
reset_control_assert(qphy->lane_rst);
|
||||
err_lane_rst:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -5514,7 +5587,7 @@ static int qcom_qmp_phy_reset_init(struct device *dev, const struct qmp_phy_cfg
|
||||
struct reset_control *rst;
|
||||
const char *name = cfg->reset_list[i];
|
||||
|
||||
rst = devm_reset_control_get(dev, name);
|
||||
rst = devm_reset_control_get_exclusive(dev, name);
|
||||
if (IS_ERR(rst)) {
|
||||
dev_err(dev, "failed to get %s reset\n", name);
|
||||
return PTR_ERR(rst);
|
||||
@ -5818,6 +5891,11 @@ static const struct phy_ops qcom_qmp_pcie_ufs_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void qcom_qmp_reset_control_put(void *data)
|
||||
{
|
||||
reset_control_put(data);
|
||||
}
|
||||
|
||||
static
|
||||
int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id,
|
||||
void __iomem *serdes, const struct qmp_phy_cfg *cfg)
|
||||
@ -5890,7 +5968,7 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id,
|
||||
* all phys that don't need this.
|
||||
*/
|
||||
snprintf(prop_name, sizeof(prop_name), "pipe%d", id);
|
||||
qphy->pipe_clk = of_clk_get_by_name(np, prop_name);
|
||||
qphy->pipe_clk = devm_get_clk_from_child(dev, np, prop_name);
|
||||
if (IS_ERR(qphy->pipe_clk)) {
|
||||
if (cfg->type == PHY_TYPE_PCIE ||
|
||||
cfg->type == PHY_TYPE_USB3) {
|
||||
@ -5907,11 +5985,15 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id,
|
||||
/* Get lane reset, if any */
|
||||
if (cfg->has_lane_rst) {
|
||||
snprintf(prop_name, sizeof(prop_name), "lane%d", id);
|
||||
qphy->lane_rst = of_reset_control_get(np, prop_name);
|
||||
qphy->lane_rst = of_reset_control_get_exclusive(np, prop_name);
|
||||
if (IS_ERR(qphy->lane_rst)) {
|
||||
dev_err(dev, "failed to get lane%d reset\n", id);
|
||||
return PTR_ERR(qphy->lane_rst);
|
||||
}
|
||||
ret = devm_add_action_or_reset(dev, qcom_qmp_reset_control_put,
|
||||
qphy->lane_rst);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (cfg->type == PHY_TYPE_UFS || cfg->type == PHY_TYPE_PCIE)
|
||||
@ -6007,6 +6089,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
|
||||
}, {
|
||||
.compatible = "qcom,sm6115-qmp-ufs-phy",
|
||||
.data = &sm6115_ufsphy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,sm6350-qmp-ufs-phy",
|
||||
.data = &sdm845_ufsphy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,sm8150-qmp-ufs-phy",
|
||||
.data = &sm8150_ufsphy_cfg,
|
||||
@ -6046,6 +6131,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
|
||||
}, {
|
||||
.compatible = "qcom,sdx55-qmp-usb3-uni-phy",
|
||||
.data = &sdx55_usb3_uniphy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,sdx65-qmp-usb3-uni-phy",
|
||||
.data = &sdx65_usb3_uniphy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,sm8350-qmp-usb3-phy",
|
||||
.data = &sm8350_usb3phy_cfg,
|
||||
|
@ -327,7 +327,6 @@ static int rk_dphy_probe(struct platform_device *pdev)
|
||||
struct device_node *np = dev->of_node;
|
||||
const struct rk_dphy_drv_data *drv_data;
|
||||
struct phy_provider *phy_provider;
|
||||
const struct of_device_id *of_id;
|
||||
struct rk_dphy *priv;
|
||||
struct phy *phy;
|
||||
unsigned int i;
|
||||
@ -347,11 +346,7 @@ static int rk_dphy_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
of_id = of_match_device(rk_dphy_dt_ids, dev);
|
||||
if (!of_id)
|
||||
return -EINVAL;
|
||||
|
||||
drv_data = of_id->data;
|
||||
drv_data = of_device_get_match_data(dev);
|
||||
priv->drv_data = drv_data;
|
||||
priv->clks = devm_kcalloc(&pdev->dev, drv_data->num_clks,
|
||||
sizeof(*priv->clks), GFP_KERNEL);
|
||||
|
@ -116,11 +116,15 @@ struct rockchip_chg_det_reg {
|
||||
* @bvalid_det_en: vbus valid rise detection enable register.
|
||||
* @bvalid_det_st: vbus valid rise detection status register.
|
||||
* @bvalid_det_clr: vbus valid rise detection clear register.
|
||||
* @id_det_en: id detection enable register.
|
||||
* @id_det_st: id detection state register.
|
||||
* @id_det_clr: id detection clear register.
|
||||
* @ls_det_en: linestate detection enable register.
|
||||
* @ls_det_st: linestate detection state register.
|
||||
* @ls_det_clr: linestate detection clear register.
|
||||
* @utmi_avalid: utmi vbus avalid status register.
|
||||
* @utmi_bvalid: utmi vbus bvalid status register.
|
||||
* @utmi_id: utmi id state register.
|
||||
* @utmi_ls: utmi linestate state register.
|
||||
* @utmi_hstdet: utmi host disconnect register.
|
||||
*/
|
||||
@ -129,11 +133,15 @@ struct rockchip_usb2phy_port_cfg {
|
||||
struct usb2phy_reg bvalid_det_en;
|
||||
struct usb2phy_reg bvalid_det_st;
|
||||
struct usb2phy_reg bvalid_det_clr;
|
||||
struct usb2phy_reg id_det_en;
|
||||
struct usb2phy_reg id_det_st;
|
||||
struct usb2phy_reg id_det_clr;
|
||||
struct usb2phy_reg ls_det_en;
|
||||
struct usb2phy_reg ls_det_st;
|
||||
struct usb2phy_reg ls_det_clr;
|
||||
struct usb2phy_reg utmi_avalid;
|
||||
struct usb2phy_reg utmi_bvalid;
|
||||
struct usb2phy_reg utmi_id;
|
||||
struct usb2phy_reg utmi_ls;
|
||||
struct usb2phy_reg utmi_hstdet;
|
||||
};
|
||||
@ -161,6 +169,7 @@ struct rockchip_usb2phy_cfg {
|
||||
* @suspended: phy suspended flag.
|
||||
* @vbus_attached: otg device vbus status.
|
||||
* @bvalid_irq: IRQ number assigned for vbus valid rise detection.
|
||||
* @id_irq: IRQ number assigned for ID pin detection.
|
||||
* @ls_irq: IRQ number assigned for linestate detection.
|
||||
* @otg_mux_irq: IRQ number which multiplex otg-id/otg-bvalid/linestate
|
||||
* irqs to one irq in otg-port.
|
||||
@ -179,6 +188,7 @@ struct rockchip_usb2phy_port {
|
||||
bool suspended;
|
||||
bool vbus_attached;
|
||||
int bvalid_irq;
|
||||
int id_irq;
|
||||
int ls_irq;
|
||||
int otg_mux_irq;
|
||||
struct mutex mutex;
|
||||
@ -253,7 +263,7 @@ static inline bool property_enabled(struct regmap *base,
|
||||
return false;
|
||||
|
||||
tmp = (orig & mask) >> reg->bitstart;
|
||||
return tmp == reg->enable;
|
||||
return tmp != reg->disable;
|
||||
}
|
||||
|
||||
static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw)
|
||||
@ -419,6 +429,19 @@ static int rockchip_usb2phy_init(struct phy *phy)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* clear id status and enable id detect irq */
|
||||
ret = property_enable(rphy->grf,
|
||||
&rport->port_cfg->id_det_clr,
|
||||
true);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = property_enable(rphy->grf,
|
||||
&rport->port_cfg->id_det_en,
|
||||
true);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
schedule_delayed_work(&rport->otg_sm_work,
|
||||
OTG_SCHEDULE_DELAY * 3);
|
||||
} else {
|
||||
@ -905,27 +928,40 @@ static irqreturn_t rockchip_usb2phy_bvalid_irq(int irq, void *data)
|
||||
if (!property_enabled(rphy->grf, &rport->port_cfg->bvalid_det_st))
|
||||
return IRQ_NONE;
|
||||
|
||||
mutex_lock(&rport->mutex);
|
||||
|
||||
/* clear bvalid detect irq pending status */
|
||||
property_enable(rphy->grf, &rport->port_cfg->bvalid_det_clr, true);
|
||||
|
||||
mutex_unlock(&rport->mutex);
|
||||
|
||||
rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t rockchip_usb2phy_otg_mux_irq(int irq, void *data)
|
||||
static irqreturn_t rockchip_usb2phy_id_irq(int irq, void *data)
|
||||
{
|
||||
struct rockchip_usb2phy_port *rport = data;
|
||||
struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
|
||||
bool id;
|
||||
|
||||
if (property_enabled(rphy->grf, &rport->port_cfg->bvalid_det_st))
|
||||
return rockchip_usb2phy_bvalid_irq(irq, data);
|
||||
else
|
||||
if (!property_enabled(rphy->grf, &rport->port_cfg->id_det_st))
|
||||
return IRQ_NONE;
|
||||
|
||||
/* clear id detect irq pending status */
|
||||
property_enable(rphy->grf, &rport->port_cfg->id_det_clr, true);
|
||||
|
||||
id = property_enabled(rphy->grf, &rport->port_cfg->utmi_id);
|
||||
extcon_set_state_sync(rphy->edev, EXTCON_USB_HOST, !id);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t rockchip_usb2phy_otg_mux_irq(int irq, void *data)
|
||||
{
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
|
||||
ret |= rockchip_usb2phy_bvalid_irq(irq, data);
|
||||
ret |= rockchip_usb2phy_id_irq(irq, data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t rockchip_usb2phy_irq(int irq, void *data)
|
||||
@ -940,8 +976,14 @@ static irqreturn_t rockchip_usb2phy_irq(int irq, void *data)
|
||||
if (!rport->phy)
|
||||
continue;
|
||||
|
||||
/* Handle linestate irq for both otg port and host port */
|
||||
ret = rockchip_usb2phy_linestate_irq(irq, rport);
|
||||
switch (rport->port_id) {
|
||||
case USB2PHY_PORT_OTG:
|
||||
ret |= rockchip_usb2phy_otg_mux_irq(irq, rport);
|
||||
break;
|
||||
case USB2PHY_PORT_HOST:
|
||||
ret |= rockchip_usb2phy_linestate_irq(irq, rport);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -1015,6 +1057,25 @@ static int rockchip_usb2phy_port_irq_init(struct rockchip_usb2phy *rphy,
|
||||
"failed to request otg-bvalid irq handle\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
rport->id_irq = of_irq_get_byname(child_np, "otg-id");
|
||||
if (rport->id_irq < 0) {
|
||||
dev_err(rphy->dev, "no otg-id irq provided\n");
|
||||
ret = rport->id_irq;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(rphy->dev, rport->id_irq,
|
||||
NULL,
|
||||
rockchip_usb2phy_id_irq,
|
||||
IRQF_ONESHOT,
|
||||
"rockchip_usb2phy_id",
|
||||
rport);
|
||||
if (ret) {
|
||||
dev_err(rphy->dev,
|
||||
"failed to request otg-id irq handle\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -1139,8 +1200,8 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
|
||||
|
||||
else {
|
||||
rphy->grf = syscon_node_to_regmap(dev->parent->of_node);
|
||||
if (IS_ERR(rphy->grf))
|
||||
return PTR_ERR(rphy->grf);
|
||||
if (IS_ERR(rphy->grf))
|
||||
return PTR_ERR(rphy->grf);
|
||||
}
|
||||
|
||||
if (of_device_is_compatible(np, "rockchip,rv1108-usb2phy")) {
|
||||
@ -1289,10 +1350,14 @@ static const struct rockchip_usb2phy_cfg rk3228_phy_cfgs[] = {
|
||||
.bvalid_det_en = { 0x0680, 3, 3, 0, 1 },
|
||||
.bvalid_det_st = { 0x0690, 3, 3, 0, 1 },
|
||||
.bvalid_det_clr = { 0x06a0, 3, 3, 0, 1 },
|
||||
.id_det_en = { 0x0680, 6, 5, 0, 3 },
|
||||
.id_det_st = { 0x0690, 6, 5, 0, 3 },
|
||||
.id_det_clr = { 0x06a0, 6, 5, 0, 3 },
|
||||
.ls_det_en = { 0x0680, 2, 2, 0, 1 },
|
||||
.ls_det_st = { 0x0690, 2, 2, 0, 1 },
|
||||
.ls_det_clr = { 0x06a0, 2, 2, 0, 1 },
|
||||
.utmi_bvalid = { 0x0480, 4, 4, 0, 1 },
|
||||
.utmi_id = { 0x0480, 1, 1, 0, 1 },
|
||||
.utmi_ls = { 0x0480, 3, 2, 0, 1 },
|
||||
},
|
||||
[USB2PHY_PORT_HOST] = {
|
||||
@ -1345,14 +1410,18 @@ static const struct rockchip_usb2phy_cfg rk3308_phy_cfgs[] = {
|
||||
.port_cfgs = {
|
||||
[USB2PHY_PORT_OTG] = {
|
||||
.phy_sus = { 0x0100, 8, 0, 0, 0x1d1 },
|
||||
.bvalid_det_en = { 0x3020, 2, 2, 0, 1 },
|
||||
.bvalid_det_st = { 0x3024, 2, 2, 0, 1 },
|
||||
.bvalid_det_clr = { 0x3028, 2, 2, 0, 1 },
|
||||
.bvalid_det_en = { 0x3020, 3, 2, 0, 3 },
|
||||
.bvalid_det_st = { 0x3024, 3, 2, 0, 3 },
|
||||
.bvalid_det_clr = { 0x3028, 3, 2, 0, 3 },
|
||||
.id_det_en = { 0x3020, 5, 4, 0, 3 },
|
||||
.id_det_st = { 0x3024, 5, 4, 0, 3 },
|
||||
.id_det_clr = { 0x3028, 5, 4, 0, 3 },
|
||||
.ls_det_en = { 0x3020, 0, 0, 0, 1 },
|
||||
.ls_det_st = { 0x3024, 0, 0, 0, 1 },
|
||||
.ls_det_clr = { 0x3028, 0, 0, 0, 1 },
|
||||
.utmi_avalid = { 0x0120, 10, 10, 0, 1 },
|
||||
.utmi_bvalid = { 0x0120, 9, 9, 0, 1 },
|
||||
.utmi_id = { 0x0120, 6, 6, 0, 1 },
|
||||
.utmi_ls = { 0x0120, 5, 4, 0, 1 },
|
||||
},
|
||||
[USB2PHY_PORT_HOST] = {
|
||||
@ -1388,14 +1457,18 @@ static const struct rockchip_usb2phy_cfg rk3328_phy_cfgs[] = {
|
||||
.port_cfgs = {
|
||||
[USB2PHY_PORT_OTG] = {
|
||||
.phy_sus = { 0x0100, 15, 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 },
|
||||
.bvalid_det_en = { 0x0110, 3, 2, 0, 3 },
|
||||
.bvalid_det_st = { 0x0114, 3, 2, 0, 3 },
|
||||
.bvalid_det_clr = { 0x0118, 3, 2, 0, 3 },
|
||||
.id_det_en = { 0x0110, 5, 4, 0, 3 },
|
||||
.id_det_st = { 0x0114, 5, 4, 0, 3 },
|
||||
.id_det_clr = { 0x0118, 5, 4, 0, 3 },
|
||||
.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_id = { 0x0120, 6, 6, 0, 1 },
|
||||
.utmi_ls = { 0x0120, 5, 4, 0, 1 },
|
||||
},
|
||||
[USB2PHY_PORT_HOST] = {
|
||||
@ -1453,8 +1526,12 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
|
||||
.bvalid_det_en = { 0xe3c0, 3, 3, 0, 1 },
|
||||
.bvalid_det_st = { 0xe3e0, 3, 3, 0, 1 },
|
||||
.bvalid_det_clr = { 0xe3d0, 3, 3, 0, 1 },
|
||||
.id_det_en = { 0xe3c0, 5, 4, 0, 3 },
|
||||
.id_det_st = { 0xe3e0, 5, 4, 0, 3 },
|
||||
.id_det_clr = { 0xe3d0, 5, 4, 0, 3 },
|
||||
.utmi_avalid = { 0xe2ac, 7, 7, 0, 1 },
|
||||
.utmi_bvalid = { 0xe2ac, 12, 12, 0, 1 },
|
||||
.utmi_id = { 0xe2ac, 8, 8, 0, 1 },
|
||||
},
|
||||
[USB2PHY_PORT_HOST] = {
|
||||
.phy_sus = { 0xe458, 1, 0, 0x2, 0x1 },
|
||||
@ -1488,8 +1565,12 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
|
||||
.bvalid_det_en = { 0xe3c0, 8, 8, 0, 1 },
|
||||
.bvalid_det_st = { 0xe3e0, 8, 8, 0, 1 },
|
||||
.bvalid_det_clr = { 0xe3d0, 8, 8, 0, 1 },
|
||||
.id_det_en = { 0xe3c0, 10, 9, 0, 3 },
|
||||
.id_det_st = { 0xe3e0, 10, 9, 0, 3 },
|
||||
.id_det_clr = { 0xe3d0, 10, 9, 0, 3 },
|
||||
.utmi_avalid = { 0xe2ac, 10, 10, 0, 1 },
|
||||
.utmi_bvalid = { 0xe2ac, 16, 16, 0, 1 },
|
||||
.utmi_id = { 0xe2ac, 11, 11, 0, 1 },
|
||||
},
|
||||
[USB2PHY_PORT_HOST] = {
|
||||
.phy_sus = { 0xe468, 1, 0, 0x2, 0x1 },
|
||||
@ -1512,11 +1593,15 @@ static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = {
|
||||
.port_cfgs = {
|
||||
[USB2PHY_PORT_OTG] = {
|
||||
.phy_sus = { 0x0000, 8, 0, 0, 0x1d1 },
|
||||
.bvalid_det_en = { 0x0080, 2, 2, 0, 1 },
|
||||
.bvalid_det_st = { 0x0084, 2, 2, 0, 1 },
|
||||
.bvalid_det_clr = { 0x0088, 2, 2, 0, 1 },
|
||||
.bvalid_det_en = { 0x0080, 3, 2, 0, 3 },
|
||||
.bvalid_det_st = { 0x0084, 3, 2, 0, 3 },
|
||||
.bvalid_det_clr = { 0x0088, 3, 2, 0, 3 },
|
||||
.id_det_en = { 0x0080, 5, 4, 0, 3 },
|
||||
.id_det_st = { 0x0084, 5, 4, 0, 3 },
|
||||
.id_det_clr = { 0x0088, 5, 4, 0, 3 },
|
||||
.utmi_avalid = { 0x00c0, 10, 10, 0, 1 },
|
||||
.utmi_bvalid = { 0x00c0, 9, 9, 0, 1 },
|
||||
.utmi_id = { 0x00c0, 6, 6, 0, 1 },
|
||||
},
|
||||
[USB2PHY_PORT_HOST] = {
|
||||
/* Select suspend control from controller */
|
||||
|
@ -1105,15 +1105,14 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
|
||||
struct phy_provider *phy_provider;
|
||||
struct resource *res;
|
||||
const struct rockchip_usb3phy_port_cfg *phy_cfgs;
|
||||
const struct of_device_id *match;
|
||||
int index, ret;
|
||||
|
||||
tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL);
|
||||
if (!tcphy)
|
||||
return -ENOMEM;
|
||||
|
||||
match = of_match_device(dev->driver->of_match_table, dev);
|
||||
if (!match || !match->data) {
|
||||
phy_cfgs = of_device_get_match_data(dev);
|
||||
if (!phy_cfgs) {
|
||||
dev_err(dev, "phy configs are not assigned!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1123,7 +1122,6 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(tcphy->base))
|
||||
return PTR_ERR(tcphy->base);
|
||||
|
||||
phy_cfgs = match->data;
|
||||
/* find out a proper config which can be matched with dt. */
|
||||
index = 0;
|
||||
while (phy_cfgs[index].reg) {
|
||||
|
32
include/linux/phy/phy-lvds.h
Normal file
32
include/linux/phy/phy-lvds.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright 2020,2022 NXP
|
||||
*/
|
||||
|
||||
#ifndef __PHY_LVDS_H_
|
||||
#define __PHY_LVDS_H_
|
||||
|
||||
/**
|
||||
* struct phy_configure_opts_lvds - LVDS configuration set
|
||||
* @bits_per_lane_and_dclk_cycle: Number of bits per lane per differential
|
||||
* clock cycle.
|
||||
* @differential_clk_rate: Clock rate, in Hertz, of the LVDS
|
||||
* differential clock.
|
||||
* @lanes: Number of active, consecutive,
|
||||
* data lanes, starting from lane 0,
|
||||
* used for the transmissions.
|
||||
* @is_slave: Boolean, true if the phy is a slave
|
||||
* which works together with a master
|
||||
* phy to support dual link transmission,
|
||||
* otherwise a regular phy or a master phy.
|
||||
*
|
||||
* This structure is used to represent the configuration state of a LVDS phy.
|
||||
*/
|
||||
struct phy_configure_opts_lvds {
|
||||
unsigned int bits_per_lane_and_dclk_cycle;
|
||||
unsigned long differential_clk_rate;
|
||||
unsigned int lanes;
|
||||
bool is_slave;
|
||||
};
|
||||
|
||||
#endif /* __PHY_LVDS_H_ */
|
@ -17,6 +17,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <linux/phy/phy-dp.h>
|
||||
#include <linux/phy/phy-lvds.h>
|
||||
#include <linux/phy/phy-mipi-dphy.h>
|
||||
|
||||
struct phy;
|
||||
@ -57,10 +58,13 @@ enum phy_media {
|
||||
* the MIPI_DPHY phy mode.
|
||||
* @dp: Configuration set applicable for phys supporting
|
||||
* the DisplayPort protocol.
|
||||
* @lvds: Configuration set applicable for phys supporting
|
||||
* the LVDS 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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user