Commit 46509e75 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'phy-for-5.19' of...

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
  ...
parents 46ee6bca d413a349
...@@ -37,6 +37,18 @@ properties: ...@@ -37,6 +37,18 @@ properties:
resets: resets:
maxItems: 1 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: required:
- "#phy-cells" - "#phy-cells"
- compatible - compatible
......
...@@ -45,7 +45,7 @@ additionalProperties: false ...@@ -45,7 +45,7 @@ additionalProperties: false
examples: examples:
- | - |
usb2_utmi_host_phy: phy@5f000 { usb2_utmi_host_phy: phy@5f000 {
compatible = "marvell,armada-3700-utmi-host-phy"; compatible = "marvell,a3700-utmi-host-phy";
reg = <0x5f000 0x800>; reg = <0x5f000 0x800>;
marvell,usb-misc-reg = <&usb2_syscon>; marvell,usb-misc-reg = <&usb2_syscon>;
#phy-cells = <0>; #phy-cells = <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>;
};
# 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: ...@@ -39,6 +39,7 @@ properties:
- qcom,sdm845-qmp-usb3-phy - qcom,sdm845-qmp-usb3-phy
- qcom,sdm845-qmp-usb3-uni-phy - qcom,sdm845-qmp-usb3-uni-phy
- qcom,sm6115-qmp-ufs-phy - qcom,sm6115-qmp-ufs-phy
- qcom,sm6350-qmp-ufs-phy
- qcom,sm8150-qmp-ufs-phy - qcom,sm8150-qmp-ufs-phy
- qcom,sm8150-qmp-usb3-phy - qcom,sm8150-qmp-usb3-phy
- qcom,sm8150-qmp-usb3-uni-phy - qcom,sm8150-qmp-usb3-uni-phy
...@@ -57,6 +58,7 @@ properties: ...@@ -57,6 +58,7 @@ properties:
- qcom,sm8450-qmp-usb3-phy - qcom,sm8450-qmp-usb3-phy
- qcom,sdx55-qmp-pcie-phy - qcom,sdx55-qmp-pcie-phy
- qcom,sdx55-qmp-usb3-uni-phy - qcom,sdx55-qmp-usb3-uni-phy
- qcom,sdx65-qmp-usb3-uni-phy
reg: reg:
minItems: 1 minItems: 1
...@@ -163,6 +165,7 @@ allOf: ...@@ -163,6 +165,7 @@ allOf:
contains: contains:
enum: enum:
- qcom,sdx55-qmp-usb3-uni-phy - qcom,sdx55-qmp-usb3-uni-phy
- qcom,sdx65-qmp-usb3-uni-phy
then: then:
properties: properties:
clocks: clocks:
...@@ -279,6 +282,7 @@ allOf: ...@@ -279,6 +282,7 @@ allOf:
enum: enum:
- qcom,msm8998-qmp-ufs-phy - qcom,msm8998-qmp-ufs-phy
- qcom,sdm845-qmp-ufs-phy - qcom,sdm845-qmp-ufs-phy
- qcom,sm6350-qmp-ufs-phy
- qcom,sm8150-qmp-ufs-phy - qcom,sm8150-qmp-ufs-phy
- qcom,sm8250-qmp-ufs-phy - qcom,sm8250-qmp-ufs-phy
- qcom,sc8180x-qmp-ufs-phy - qcom,sc8180x-qmp-ufs-phy
......
...@@ -32,6 +32,7 @@ properties: ...@@ -32,6 +32,7 @@ properties:
- items: - items:
- enum: - enum:
- renesas,usb2-phy-r9a07g043 # RZ/G2UL
- renesas,usb2-phy-r9a07g044 # RZ/G2{L,LC} - renesas,usb2-phy-r9a07g044 # RZ/G2{L,LC}
- renesas,usb2-phy-r9a07g054 # RZ/V2L - renesas,usb2-phy-r9a07g054 # RZ/V2L
- const: renesas,rzg2l-usb2-phy - const: renesas,rzg2l-usb2-phy
......
...@@ -30,30 +30,77 @@ properties: ...@@ -30,30 +30,77 @@ properties:
minItems: 1 minItems: 1
maxItems: 2 maxItems: 2
clock-names: clock-names: true
oneOf:
- items: # for PXs2
- const: link
- items: # for Pro4
- const: link
- const: gio
- items: # for others
- const: link
- const: phy
resets: resets:
minItems: 2 minItems: 2
maxItems: 5 maxItems: 6
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: reset-names:
oneOf: items:
- items: # for Pro4
- const: link - const: link
- const: gio - const: gio
- const: phy
- const: pm - const: pm
- const: tx - const: tx
- const: rx - const: rx
- items: # for others - 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: link
- const: phy - const: phy
......
...@@ -31,28 +31,51 @@ properties: ...@@ -31,28 +31,51 @@ properties:
minItems: 1 minItems: 1
maxItems: 2 maxItems: 2
clock-names: clock-names: true
oneOf:
- items: # for Pro5
- const: gio
- const: link
- const: link # for others
resets: resets:
minItems: 1 minItems: 1
maxItems: 2 maxItems: 2
reset-names: reset-names: true
oneOf:
- items: # for Pro5
- const: gio
- const: link
- const: link # for others
socionext,syscon: socionext,syscon:
$ref: /schemas/types.yaml#/definitions/phandle $ref: /schemas/types.yaml#/definitions/phandle
description: A phandle to system control to set configurations for phy 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: required:
- compatible - compatible
- reg - reg
......
...@@ -43,6 +43,9 @@ patternProperties: ...@@ -43,6 +43,9 @@ patternProperties:
"#phy-cells": "#phy-cells":
const: 0 const: 0
vbus-supply:
description: A phandle to the regulator for USB VBUS, only for USB host
required: required:
- reg - reg
- "#phy-cells" - "#phy-cells"
......
...@@ -31,27 +31,15 @@ properties: ...@@ -31,27 +31,15 @@ properties:
const: 0 const: 0
clocks: clocks:
minItems: 1 minItems: 2
maxItems: 3 maxItems: 3
clock-names: clock-names: true
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
resets: resets:
maxItems: 2 maxItems: 2
reset-names: reset-names: true
items:
- const: link
- const: phy
vbus-supply: vbus-supply:
description: A phandle to the regulator for USB VBUS description: A phandle to the regulator for USB VBUS
...@@ -74,6 +62,77 @@ properties: ...@@ -74,6 +62,77 @@ properties:
required for each port, if any one is omitted, the trimming data required for each port, if any one is omitted, the trimming data
of the port will not be set at all. 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: required:
- compatible - compatible
- reg - reg
......
...@@ -35,34 +35,89 @@ properties: ...@@ -35,34 +35,89 @@ properties:
minItems: 2 minItems: 2
maxItems: 3 maxItems: 3
clock-names: true
resets:
maxItems: 2
reset-names: true
vbus-supply:
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: clock-names:
oneOf: items:
- items: # for Pro4, Pro5
- const: gio - const: gio
- const: link - const: link
- items: # for PXs3 with phy-ext resets:
minItems: 2
maxItems: 2
reset-names:
items:
- const: gio
- const: link - const: link
- const: phy - if:
- const: phy-ext properties:
- items: # for others 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: link
- const: phy - const: phy
resets: resets:
minItems: 2
maxItems: 2 maxItems: 2
reset-names: reset-names:
oneOf: items:
- items: # for Pro4,Pro5 - const: link
- const: gio - 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: link
- items: # for others - const: phy
- const: phy-ext
resets:
minItems: 2
maxItems: 2
reset-names:
items:
- const: link - const: link
- const: phy - const: phy
vbus-supply:
description: A phandle to the regulator for USB VBUS
required: required:
- compatible - compatible
- reg - reg
...@@ -71,7 +126,6 @@ required: ...@@ -71,7 +126,6 @@ required:
- clock-names - clock-names
- resets - resets
- reset-names - reset-names
- vbus-supply
additionalProperties: false additionalProperties: false
......
...@@ -64,6 +64,7 @@ config USB_LGM_PHY ...@@ -64,6 +64,7 @@ config USB_LGM_PHY
config PHY_CAN_TRANSCEIVER config PHY_CAN_TRANSCEIVER
tristate "CAN transceiver PHY" tristate "CAN transceiver PHY"
select GENERIC_PHY select GENERIC_PHY
select MULTIPLEXER
help help
This option enables support for CAN transceivers as a PHY. This This option enables support for CAN transceivers as a PHY. This
driver provides function for putting the transceivers in various driver provides function for putting the transceivers in various
......
...@@ -24,6 +24,14 @@ ...@@ -24,6 +24,14 @@
#define SUN6I_DPHY_TX_CTL_REG 0x04 #define SUN6I_DPHY_TX_CTL_REG 0x04
#define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28) #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_REG 0x10
#define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24) #define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24)
#define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16) #define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16)
...@@ -44,12 +52,29 @@ ...@@ -44,12 +52,29 @@
#define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8) #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_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 0x4c
#define SUN6I_DPHY_ANA0_REG_PWS BIT(31) #define SUN6I_DPHY_ANA0_REG_PWS BIT(31)
#define SUN6I_DPHY_ANA0_REG_DMPC BIT(28) #define SUN6I_DPHY_ANA0_REG_DMPC BIT(28)
#define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24) #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_SLV(n) (((n) & 7) << 12)
#define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8) #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 0x50
#define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31) #define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31)
...@@ -84,6 +109,11 @@ ...@@ -84,6 +109,11 @@
#define SUN6I_DPHY_DBG5_REG 0xf4 #define SUN6I_DPHY_DBG5_REG 0xf4
enum sun6i_dphy_direction {
SUN6I_DPHY_DIRECTION_TX,
SUN6I_DPHY_DIRECTION_RX,
};
struct sun6i_dphy { struct sun6i_dphy {
struct clk *bus_clk; struct clk *bus_clk;
struct clk *mod_clk; struct clk *mod_clk;
...@@ -92,6 +122,8 @@ struct sun6i_dphy { ...@@ -92,6 +122,8 @@ struct sun6i_dphy {
struct phy *phy; struct phy *phy;
struct phy_configure_opts_mipi_dphy config; struct phy_configure_opts_mipi_dphy config;
enum sun6i_dphy_direction direction;
}; };
static int sun6i_dphy_init(struct phy *phy) 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) ...@@ -119,9 +151,8 @@ static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
return 0; 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); u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0);
regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG, regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG,
...@@ -211,12 +242,129 @@ static int sun6i_dphy_power_on(struct phy *phy) ...@@ -211,12 +242,129 @@ static int sun6i_dphy_power_on(struct phy *phy)
return 0; 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) static int sun6i_dphy_power_off(struct phy *phy)
{ {
struct sun6i_dphy *dphy = phy_get_drvdata(phy); struct sun6i_dphy *dphy = phy_get_drvdata(phy);
regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG, regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, 0);
SUN6I_DPHY_ANA1_REG_VTTMODE, 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; return 0;
} }
...@@ -253,7 +401,9 @@ static int sun6i_dphy_probe(struct platform_device *pdev) ...@@ -253,7 +401,9 @@ static int sun6i_dphy_probe(struct platform_device *pdev)
{ {
struct phy_provider *phy_provider; struct phy_provider *phy_provider;
struct sun6i_dphy *dphy; struct sun6i_dphy *dphy;
const char *direction;
void __iomem *regs; void __iomem *regs;
int ret;
dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
if (!dphy) if (!dphy)
...@@ -290,6 +440,14 @@ static int sun6i_dphy_probe(struct platform_device *pdev) ...@@ -290,6 +440,14 @@ static int sun6i_dphy_probe(struct platform_device *pdev)
return PTR_ERR(dphy->phy); 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_set_drvdata(dphy->phy, dphy);
phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
......
...@@ -83,6 +83,7 @@ ...@@ -83,6 +83,7 @@
#define SIERRA_DFE_BIASTRIM_PREG 0x04C #define SIERRA_DFE_BIASTRIM_PREG 0x04C
#define SIERRA_DRVCTRL_ATTEN_PREG 0x06A #define SIERRA_DRVCTRL_ATTEN_PREG 0x06A
#define SIERRA_DRVCTRL_BOOST_PREG 0x06F #define SIERRA_DRVCTRL_BOOST_PREG 0x06F
#define SIERRA_TX_RCVDET_OVRD_PREG 0x072
#define SIERRA_CLKPATHCTRL_TMR_PREG 0x081 #define SIERRA_CLKPATHCTRL_TMR_PREG 0x081
#define SIERRA_RX_CREQ_FLTR_A_MODE3_PREG 0x085 #define SIERRA_RX_CREQ_FLTR_A_MODE3_PREG 0x085
#define SIERRA_RX_CREQ_FLTR_A_MODE2_PREG 0x086 #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 = { ...@@ -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), .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 */ /* 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[] = { static const struct cdns_reg_pairs pcie_100_int_ssc_plllc_cmn_regs[] = {
{0x000E, SIERRA_CMN_PLLLC_MODE_PREG}, {0x000E, SIERRA_CMN_PLLLC_MODE_PREG},
...@@ -1765,6 +1826,69 @@ static struct cdns_sierra_vals ml_pcie_100_int_ssc_ln_vals = { ...@@ -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), .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 */ /* 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[] = { static const struct cdns_reg_pairs pcie_100_ext_ssc_plllc_cmn_regs[] = {
{0x2106, SIERRA_CMN_PLLLC_LF_COEFF_MODE1_PREG}, {0x2106, SIERRA_CMN_PLLLC_LF_COEFF_MODE1_PREG},
...@@ -1840,6 +1964,69 @@ static struct cdns_sierra_vals ml_pcie_100_ext_ssc_ln_vals = { ...@@ -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), .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 */ /* refclk100MHz_32b_PCIe_cmn_pll_no_ssc */
static const struct cdns_reg_pairs cdns_pcie_cmn_regs_no_ssc[] = { static const struct cdns_reg_pairs cdns_pcie_cmn_regs_no_ssc[] = {
{0x2105, SIERRA_CMN_PLLLC_LF_COEFF_MODE1_PREG}, {0x2105, SIERRA_CMN_PLLLC_LF_COEFF_MODE1_PREG},
...@@ -2299,9 +2486,9 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = { ...@@ -2299,9 +2486,9 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = {
[INTERNAL_SSC] = &pcie_100_int_ssc_ln_vals, [INTERNAL_SSC] = &pcie_100_int_ssc_ln_vals,
}, },
[TYPE_QSGMII] = { [TYPE_QSGMII] = {
[NO_SSC] = &ml_pcie_100_no_ssc_ln_vals, [NO_SSC] = &ti_ml_pcie_100_no_ssc_ln_vals,
[EXTERNAL_SSC] = &ml_pcie_100_ext_ssc_ln_vals, [EXTERNAL_SSC] = &ti_ml_pcie_100_ext_ssc_ln_vals,
[INTERNAL_SSC] = &ml_pcie_100_int_ssc_ln_vals, [INTERNAL_SSC] = &ti_ml_pcie_100_int_ssc_ln_vals,
}, },
}, },
[TYPE_USB] = { [TYPE_USB] = {
......
...@@ -94,15 +94,21 @@ static int imx8_pcie_phy_init(struct phy *phy) ...@@ -94,15 +94,21 @@ static int imx8_pcie_phy_init(struct phy *phy)
IMX8MM_GPR_PCIE_CMN_RST); IMX8MM_GPR_PCIE_CMN_RST);
usleep_range(200, 500); 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 */ /* Configure the pad as input */
val = readl(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061); val = readl(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061);
writel(val & ~ANA_PLL_CLK_OUT_TO_EXT_IO_EN, writel(val & ~ANA_PLL_CLK_OUT_TO_EXT_IO_EN,
imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061); 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 */ /* Configure the PHY to output the refclock via pad */
writel(ANA_PLL_CLK_OUT_TO_EXT_IO_EN, writel(ANA_PLL_CLK_OUT_TO_EXT_IO_EN,
imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG061); 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, writel(ANA_PLL_CLK_OUT_TO_EXT_IO_SEL,
imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG062); imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG062);
writel(AUX_PLL_REFCLK_SEL_SYS_PLL, writel(AUX_PLL_REFCLK_SEL_SYS_PLL,
......
...@@ -120,20 +120,16 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev) ...@@ -120,20 +120,16 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev)
return PTR_ERR(hdmi_phy->regs); return PTR_ERR(hdmi_phy->regs);
ref_clk = devm_clk_get(dev, "pll_ref"); ref_clk = devm_clk_get(dev, "pll_ref");
if (IS_ERR(ref_clk)) { if (IS_ERR(ref_clk))
ret = PTR_ERR(ref_clk); return dev_err_probe(dev, PTR_ERR(ref_clk),
dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n", "Failed to get PLL reference clock\n");
ret);
return ret;
}
ref_clk_name = __clk_get_name(ref_clk); ref_clk_name = __clk_get_name(ref_clk);
ret = of_property_read_string(dev->of_node, "clock-output-names", ret = of_property_read_string(dev->of_node, "clock-output-names",
&clk_init.name); &clk_init.name);
if (ret < 0) { if (ret < 0)
dev_err(dev, "Failed to read clock-output-names: %d\n", ret); return dev_err_probe(dev, ret, "Failed to read clock-output-names\n");
return ret;
}
hdmi_phy->dev = dev; hdmi_phy->dev = dev;
hdmi_phy->conf = hdmi_phy->conf =
...@@ -141,25 +137,19 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev) ...@@ -141,25 +137,19 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev)
mtk_hdmi_phy_clk_get_data(hdmi_phy, &clk_init); mtk_hdmi_phy_clk_get_data(hdmi_phy, &clk_init);
hdmi_phy->pll_hw.init = &clk_init; hdmi_phy->pll_hw.init = &clk_init;
hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw); hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw);
if (IS_ERR(hdmi_phy->pll)) { if (IS_ERR(hdmi_phy->pll))
ret = PTR_ERR(hdmi_phy->pll); return dev_err_probe(dev, PTR_ERR(hdmi_phy->pll),
dev_err(dev, "Failed to register PLL: %d\n", ret); "Failed to register PLL\n");
return ret;
}
ret = of_property_read_u32(dev->of_node, "mediatek,ibias", ret = of_property_read_u32(dev->of_node, "mediatek,ibias",
&hdmi_phy->ibias); &hdmi_phy->ibias);
if (ret < 0) { if (ret < 0)
dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret); return dev_err_probe(dev, ret, "Failed to get ibias\n");
return ret;
}
ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up", ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up",
&hdmi_phy->ibias_up); &hdmi_phy->ibias_up);
if (ret < 0) { if (ret < 0)
dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret); return dev_err_probe(dev, ret, "Failed to get ibias_up\n");
return ret;
}
dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n"); dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n");
hdmi_phy->drv_imp_clk = 0x30; hdmi_phy->drv_imp_clk = 0x30;
...@@ -168,17 +158,15 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev) ...@@ -168,17 +158,15 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev)
hdmi_phy->drv_imp_d0 = 0x30; hdmi_phy->drv_imp_d0 = 0x30;
phy = devm_phy_create(dev, NULL, mtk_hdmi_phy_dev_get_ops(hdmi_phy)); phy = devm_phy_create(dev, NULL, mtk_hdmi_phy_dev_get_ops(hdmi_phy));
if (IS_ERR(phy)) { if (IS_ERR(phy))
dev_err(dev, "Failed to create HDMI PHY\n"); return dev_err_probe(dev, PTR_ERR(phy), "Cannot create HDMI PHY\n");
return PTR_ERR(phy);
}
phy_set_drvdata(phy, hdmi_phy); phy_set_drvdata(phy, hdmi_phy);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(phy_provider)) { if (IS_ERR(phy_provider))
dev_err(dev, "Failed to register HDMI PHY\n"); return dev_err_probe(dev, PTR_ERR(phy_provider),
return PTR_ERR(phy_provider); "Failed to register HDMI PHY\n");
}
if (hdmi_phy->conf->pll_default_off) if (hdmi_phy->conf->pll_default_off)
hdmi_phy->conf->hdmi_phy_disable_tmds(hdmi_phy); hdmi_phy->conf->hdmi_phy_disable_tmds(hdmi_phy);
......
...@@ -154,11 +154,9 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev) ...@@ -154,11 +154,9 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
return PTR_ERR(mipi_tx->regs); return PTR_ERR(mipi_tx->regs);
ref_clk = devm_clk_get(dev, NULL); ref_clk = devm_clk_get(dev, NULL);
if (IS_ERR(ref_clk)) { if (IS_ERR(ref_clk))
ret = PTR_ERR(ref_clk); return dev_err_probe(dev, PTR_ERR(ref_clk),
dev_err(dev, "Failed to get reference clock: %d\n", ret); "Failed to get reference clock\n");
return ret;
}
ret = of_property_read_u32(dev->of_node, "drive-strength-microamp", ret = of_property_read_u32(dev->of_node, "drive-strength-microamp",
&mipi_tx->mipitx_drive); &mipi_tx->mipitx_drive);
...@@ -178,27 +176,20 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev) ...@@ -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", ret = of_property_read_string(dev->of_node, "clock-output-names",
&clk_init.name); &clk_init.name);
if (ret < 0) { if (ret < 0)
dev_err(dev, "Failed to read clock-output-names: %d\n", ret); return dev_err_probe(dev, ret, "Failed to read clock-output-names\n");
return ret;
}
clk_init.ops = mipi_tx->driver_data->mipi_tx_clk_ops; clk_init.ops = mipi_tx->driver_data->mipi_tx_clk_ops;
mipi_tx->pll_hw.init = &clk_init; mipi_tx->pll_hw.init = &clk_init;
mipi_tx->pll = devm_clk_register(dev, &mipi_tx->pll_hw); mipi_tx->pll = devm_clk_register(dev, &mipi_tx->pll_hw);
if (IS_ERR(mipi_tx->pll)) { if (IS_ERR(mipi_tx->pll))
ret = PTR_ERR(mipi_tx->pll); return dev_err_probe(dev, PTR_ERR(mipi_tx->pll), "Failed to register PLL\n");
dev_err(dev, "Failed to register PLL: %d\n", ret);
return ret;
}
phy = devm_phy_create(dev, NULL, &mtk_mipi_tx_ops); phy = devm_phy_create(dev, NULL, &mtk_mipi_tx_ops);
if (IS_ERR(phy)) { if (IS_ERR(phy))
ret = PTR_ERR(phy); return dev_err_probe(dev, PTR_ERR(phy), "Failed to create MIPI D-PHY\n");
dev_err(dev, "Failed to create MIPI D-PHY: %d\n", ret);
return ret;
}
phy_set_drvdata(phy, mipi_tx); phy_set_drvdata(phy, mipi_tx);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include<linux/module.h> #include<linux/module.h>
#include<linux/gpio.h> #include<linux/gpio.h>
#include<linux/gpio/consumer.h> #include<linux/gpio/consumer.h>
#include <linux/mux/consumer.h>
struct can_transceiver_data { struct can_transceiver_data {
u32 flags; u32 flags;
...@@ -21,13 +22,22 @@ struct can_transceiver_phy { ...@@ -21,13 +22,22 @@ struct can_transceiver_phy {
struct phy *generic_phy; struct phy *generic_phy;
struct gpio_desc *standby_gpio; struct gpio_desc *standby_gpio;
struct gpio_desc *enable_gpio; struct gpio_desc *enable_gpio;
struct mux_state *mux_state;
}; };
/* Power on function */ /* Power on function */
static int can_transceiver_phy_power_on(struct phy *phy) static int can_transceiver_phy_power_on(struct phy *phy)
{ {
struct can_transceiver_phy *can_transceiver_phy = phy_get_drvdata(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) if (can_transceiver_phy->standby_gpio)
gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 0); gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 0);
if (can_transceiver_phy->enable_gpio) if (can_transceiver_phy->enable_gpio)
...@@ -45,6 +55,8 @@ static int can_transceiver_phy_power_off(struct phy *phy) ...@@ -45,6 +55,8 @@ static int can_transceiver_phy_power_off(struct phy *phy)
gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 1); gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 1);
if (can_transceiver_phy->enable_gpio) if (can_transceiver_phy->enable_gpio)
gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 0); 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; return 0;
} }
...@@ -95,6 +107,16 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) ...@@ -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); match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node);
drvdata = match->data; 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, phy = devm_phy_create(dev, dev->of_node,
&can_transceiver_phy_ops); &can_transceiver_phy_ops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
......
...@@ -229,6 +229,17 @@ void phy_pm_runtime_forbid(struct phy *phy) ...@@ -229,6 +229,17 @@ void phy_pm_runtime_forbid(struct phy *phy)
} }
EXPORT_SYMBOL_GPL(phy_pm_runtime_forbid); 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 phy_init(struct phy *phy)
{ {
int ret; int ret;
...@@ -242,6 +253,9 @@ int phy_init(struct phy *phy) ...@@ -242,6 +253,9 @@ int phy_init(struct phy *phy)
ret = 0; /* Override possible ret == -ENOTSUPP */ ret = 0; /* Override possible ret == -ENOTSUPP */
mutex_lock(&phy->mutex); 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) { if (phy->init_count == 0 && phy->ops->init) {
ret = phy->ops->init(phy); ret = phy->ops->init(phy);
if (ret < 0) { if (ret < 0) {
...@@ -258,6 +272,14 @@ int phy_init(struct phy *phy) ...@@ -258,6 +272,14 @@ int phy_init(struct phy *phy)
} }
EXPORT_SYMBOL_GPL(phy_init); 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 phy_exit(struct phy *phy)
{ {
int ret; int ret;
...@@ -287,6 +309,14 @@ int phy_exit(struct phy *phy) ...@@ -287,6 +309,14 @@ int phy_exit(struct phy *phy)
} }
EXPORT_SYMBOL_GPL(phy_exit); 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 phy_power_on(struct phy *phy)
{ {
int ret = 0; int ret = 0;
...@@ -329,6 +359,14 @@ int phy_power_on(struct phy *phy) ...@@ -329,6 +359,14 @@ int phy_power_on(struct phy *phy)
} }
EXPORT_SYMBOL_GPL(phy_power_on); 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 phy_power_off(struct phy *phy)
{ {
int ret; int ret;
...@@ -432,7 +470,7 @@ EXPORT_SYMBOL_GPL(phy_reset); ...@@ -432,7 +470,7 @@ EXPORT_SYMBOL_GPL(phy_reset);
* runtime, which are otherwise lost after host controller reset and cannot * runtime, which are otherwise lost after host controller reset and cannot
* be applied in phy_init() or phy_power_on(). * 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) int phy_calibrate(struct phy *phy)
{ {
...@@ -458,7 +496,7 @@ EXPORT_SYMBOL_GPL(phy_calibrate); ...@@ -458,7 +496,7 @@ EXPORT_SYMBOL_GPL(phy_calibrate);
* on the phy. The configuration will be applied on the current phy * on the phy. The configuration will be applied on the current phy
* mode, that can be changed using phy_set_mode(). * 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) int phy_configure(struct phy *phy, union phy_configure_opts *opts)
{ {
...@@ -492,7 +530,7 @@ EXPORT_SYMBOL_GPL(phy_configure); ...@@ -492,7 +530,7 @@ EXPORT_SYMBOL_GPL(phy_configure);
* PHY, so calling it as many times as deemed fit will have no side * PHY, so calling it as many times as deemed fit will have no side
* effect. * 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, int phy_validate(struct phy *phy, enum phy_mode mode, int submode,
union phy_configure_opts *opts) union phy_configure_opts *opts)
......
...@@ -2535,6 +2535,50 @@ static const struct qmp_phy_init_tbl sdx55_qmp_pcie_pcs_misc_tbl[] = { ...@@ -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), 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[] = { 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_SYSCLK_EN_SEL, 0xd9),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_SEL, 0x11), QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_SEL, 0x11),
...@@ -3177,7 +3221,7 @@ struct qmp_phy_combo_cfg { ...@@ -3177,7 +3221,7 @@ struct qmp_phy_combo_cfg {
* @tx2: iomapped memory space for second lane's tx (in dual lane PHYs) * @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) * @rx2: iomapped memory space for second lane's rx (in dual lane PHYs)
* @pcs_misc: iomapped memory space for lane's pcs_misc * @pcs_misc: iomapped memory space for lane's pcs_misc
* @pipe_clk: pipe lock * @pipe_clk: pipe clock
* @index: lane index * @index: lane index
* @qmp: QMP phy to which this lane belongs * @qmp: QMP phy to which this lane belongs
* @lane_rst: lane's reset controller * @lane_rst: lane's reset controller
...@@ -4217,6 +4261,35 @@ static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = { ...@@ -4217,6 +4261,35 @@ static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = {
.pwrdn_delay_max = 1005, /* us */ .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 = { static const struct qmp_phy_cfg sm8350_ufsphy_cfg = {
.type = PHY_TYPE_UFS, .type = PHY_TYPE_UFS,
.nlanes = 2, .nlanes = 2,
...@@ -5012,7 +5085,7 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy) ...@@ -5012,7 +5085,7 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
if (ret) { if (ret) {
dev_err(qmp->dev, "failed to enable regulators, err=%d\n", 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++) { for (i = 0; i < cfg->num_resets; i++) {
...@@ -5020,7 +5093,7 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy) ...@@ -5020,7 +5093,7 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
if (ret) { if (ret) {
dev_err(qmp->dev, "%s reset assert failed\n", dev_err(qmp->dev, "%s reset assert failed\n",
cfg->reset_list[i]); 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) ...@@ -5029,13 +5102,13 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
if (ret) { if (ret) {
dev_err(qmp->dev, "%s reset deassert failed\n", dev_err(qmp->dev, "%s reset deassert failed\n",
qphy->cfg->reset_list[i]); qphy->cfg->reset_list[i]);
goto err_rst; goto err_assert_reset;
} }
} }
ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks); ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks);
if (ret) if (ret)
goto err_rst; goto err_assert_reset;
if (cfg->has_phy_dp_com_ctrl) { if (cfg->has_phy_dp_com_ctrl) {
qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, qphy_setbits(dp_com, QPHY_V3_DP_COM_POWER_DOWN_CTRL,
...@@ -5077,12 +5150,12 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy) ...@@ -5077,12 +5150,12 @@ static int qcom_qmp_phy_com_init(struct qmp_phy *qphy)
return 0; return 0;
err_rst: err_assert_reset:
while (++i < cfg->num_resets) while (++i < cfg->num_resets)
reset_control_assert(qmp->resets[i]); reset_control_assert(qmp->resets[i]);
err_rst_assert: err_disable_regulators:
regulator_bulk_disable(cfg->num_vregs, qmp->vregs); regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
err_reg_enable: err_unlock:
mutex_unlock(&qmp->phy_mutex); mutex_unlock(&qmp->phy_mutex);
return ret; return ret;
...@@ -5188,14 +5261,14 @@ static int qcom_qmp_phy_power_on(struct phy *phy) ...@@ -5188,14 +5261,14 @@ static int qcom_qmp_phy_power_on(struct phy *phy)
if (ret) { if (ret) {
dev_err(qmp->dev, "lane%d reset deassert failed\n", dev_err(qmp->dev, "lane%d reset deassert failed\n",
qphy->index); qphy->index);
goto err_lane_rst; return ret;
} }
} }
ret = clk_prepare_enable(qphy->pipe_clk); ret = clk_prepare_enable(qphy->pipe_clk);
if (ret) { if (ret) {
dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", 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 */ /* Tx, Rx, and PCS configurations */
...@@ -5246,7 +5319,7 @@ static int qcom_qmp_phy_power_on(struct phy *phy) ...@@ -5246,7 +5319,7 @@ static int qcom_qmp_phy_power_on(struct phy *phy)
ret = reset_control_deassert(qmp->ufs_reset); ret = reset_control_deassert(qmp->ufs_reset);
if (ret) if (ret)
goto err_lane_rst; goto err_disable_pipe_clk;
qcom_qmp_phy_configure(pcs_misc, cfg->regs, cfg->pcs_misc_tbl, qcom_qmp_phy_configure(pcs_misc, cfg->regs, cfg->pcs_misc_tbl,
cfg->pcs_misc_tbl_num); cfg->pcs_misc_tbl_num);
...@@ -5285,17 +5358,17 @@ static int qcom_qmp_phy_power_on(struct phy *phy) ...@@ -5285,17 +5358,17 @@ static int qcom_qmp_phy_power_on(struct phy *phy)
PHY_INIT_COMPLETE_TIMEOUT); PHY_INIT_COMPLETE_TIMEOUT);
if (ret) { if (ret) {
dev_err(qmp->dev, "phy initialization timed-out\n"); dev_err(qmp->dev, "phy initialization timed-out\n");
goto err_pcs_ready; goto err_disable_pipe_clk;
} }
} }
return 0; return 0;
err_pcs_ready: err_disable_pipe_clk:
clk_disable_unprepare(qphy->pipe_clk); clk_disable_unprepare(qphy->pipe_clk);
err_clk_enable: err_reset_lane:
if (cfg->has_lane_rst) if (cfg->has_lane_rst)
reset_control_assert(qphy->lane_rst); reset_control_assert(qphy->lane_rst);
err_lane_rst:
return ret; return ret;
} }
...@@ -5514,7 +5587,7 @@ static int qcom_qmp_phy_reset_init(struct device *dev, const struct qmp_phy_cfg ...@@ -5514,7 +5587,7 @@ static int qcom_qmp_phy_reset_init(struct device *dev, const struct qmp_phy_cfg
struct reset_control *rst; struct reset_control *rst;
const char *name = cfg->reset_list[i]; 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)) { if (IS_ERR(rst)) {
dev_err(dev, "failed to get %s reset\n", name); dev_err(dev, "failed to get %s reset\n", name);
return PTR_ERR(rst); return PTR_ERR(rst);
...@@ -5818,6 +5891,11 @@ static const struct phy_ops qcom_qmp_pcie_ufs_ops = { ...@@ -5818,6 +5891,11 @@ static const struct phy_ops qcom_qmp_pcie_ufs_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static void qcom_qmp_reset_control_put(void *data)
{
reset_control_put(data);
}
static static
int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id, int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id,
void __iomem *serdes, const struct qmp_phy_cfg *cfg) 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, ...@@ -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. * all phys that don't need this.
*/ */
snprintf(prop_name, sizeof(prop_name), "pipe%d", id); 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 (IS_ERR(qphy->pipe_clk)) {
if (cfg->type == PHY_TYPE_PCIE || if (cfg->type == PHY_TYPE_PCIE ||
cfg->type == PHY_TYPE_USB3) { cfg->type == PHY_TYPE_USB3) {
...@@ -5907,11 +5985,15 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id, ...@@ -5907,11 +5985,15 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id,
/* Get lane reset, if any */ /* Get lane reset, if any */
if (cfg->has_lane_rst) { if (cfg->has_lane_rst) {
snprintf(prop_name, sizeof(prop_name), "lane%d", id); 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)) { if (IS_ERR(qphy->lane_rst)) {
dev_err(dev, "failed to get lane%d reset\n", id); dev_err(dev, "failed to get lane%d reset\n", id);
return PTR_ERR(qphy->lane_rst); 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) 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[] = { ...@@ -6007,6 +6089,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
}, { }, {
.compatible = "qcom,sm6115-qmp-ufs-phy", .compatible = "qcom,sm6115-qmp-ufs-phy",
.data = &sm6115_ufsphy_cfg, .data = &sm6115_ufsphy_cfg,
}, {
.compatible = "qcom,sm6350-qmp-ufs-phy",
.data = &sdm845_ufsphy_cfg,
}, { }, {
.compatible = "qcom,sm8150-qmp-ufs-phy", .compatible = "qcom,sm8150-qmp-ufs-phy",
.data = &sm8150_ufsphy_cfg, .data = &sm8150_ufsphy_cfg,
...@@ -6046,6 +6131,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { ...@@ -6046,6 +6131,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
}, { }, {
.compatible = "qcom,sdx55-qmp-usb3-uni-phy", .compatible = "qcom,sdx55-qmp-usb3-uni-phy",
.data = &sdx55_usb3_uniphy_cfg, .data = &sdx55_usb3_uniphy_cfg,
}, {
.compatible = "qcom,sdx65-qmp-usb3-uni-phy",
.data = &sdx65_usb3_uniphy_cfg,
}, { }, {
.compatible = "qcom,sm8350-qmp-usb3-phy", .compatible = "qcom,sm8350-qmp-usb3-phy",
.data = &sm8350_usb3phy_cfg, .data = &sm8350_usb3phy_cfg,
......
...@@ -327,7 +327,6 @@ static int rk_dphy_probe(struct platform_device *pdev) ...@@ -327,7 +327,6 @@ static int rk_dphy_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
const struct rk_dphy_drv_data *drv_data; const struct rk_dphy_drv_data *drv_data;
struct phy_provider *phy_provider; struct phy_provider *phy_provider;
const struct of_device_id *of_id;
struct rk_dphy *priv; struct rk_dphy *priv;
struct phy *phy; struct phy *phy;
unsigned int i; unsigned int i;
...@@ -347,11 +346,7 @@ static int rk_dphy_probe(struct platform_device *pdev) ...@@ -347,11 +346,7 @@ static int rk_dphy_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
} }
of_id = of_match_device(rk_dphy_dt_ids, dev); drv_data = of_device_get_match_data(dev);
if (!of_id)
return -EINVAL;
drv_data = of_id->data;
priv->drv_data = drv_data; priv->drv_data = drv_data;
priv->clks = devm_kcalloc(&pdev->dev, drv_data->num_clks, priv->clks = devm_kcalloc(&pdev->dev, drv_data->num_clks,
sizeof(*priv->clks), GFP_KERNEL); sizeof(*priv->clks), GFP_KERNEL);
......
...@@ -116,11 +116,15 @@ struct rockchip_chg_det_reg { ...@@ -116,11 +116,15 @@ struct rockchip_chg_det_reg {
* @bvalid_det_en: vbus valid rise detection enable register. * @bvalid_det_en: vbus valid rise detection enable register.
* @bvalid_det_st: vbus valid rise detection status register. * @bvalid_det_st: vbus valid rise detection status register.
* @bvalid_det_clr: vbus valid rise detection clear 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_en: linestate detection enable register.
* @ls_det_st: linestate detection state register. * @ls_det_st: linestate detection state register.
* @ls_det_clr: linestate detection clear register. * @ls_det_clr: linestate detection clear register.
* @utmi_avalid: utmi vbus avalid status register. * @utmi_avalid: utmi vbus avalid status register.
* @utmi_bvalid: utmi vbus bvalid status register. * @utmi_bvalid: utmi vbus bvalid status register.
* @utmi_id: utmi id state register.
* @utmi_ls: utmi linestate state register. * @utmi_ls: utmi linestate state register.
* @utmi_hstdet: utmi host disconnect register. * @utmi_hstdet: utmi host disconnect register.
*/ */
...@@ -129,11 +133,15 @@ struct rockchip_usb2phy_port_cfg { ...@@ -129,11 +133,15 @@ struct rockchip_usb2phy_port_cfg {
struct usb2phy_reg bvalid_det_en; struct usb2phy_reg bvalid_det_en;
struct usb2phy_reg bvalid_det_st; struct usb2phy_reg bvalid_det_st;
struct usb2phy_reg bvalid_det_clr; 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_en;
struct usb2phy_reg ls_det_st; struct usb2phy_reg ls_det_st;
struct usb2phy_reg ls_det_clr; struct usb2phy_reg ls_det_clr;
struct usb2phy_reg utmi_avalid; struct usb2phy_reg utmi_avalid;
struct usb2phy_reg utmi_bvalid; struct usb2phy_reg utmi_bvalid;
struct usb2phy_reg utmi_id;
struct usb2phy_reg utmi_ls; struct usb2phy_reg utmi_ls;
struct usb2phy_reg utmi_hstdet; struct usb2phy_reg utmi_hstdet;
}; };
...@@ -161,6 +169,7 @@ struct rockchip_usb2phy_cfg { ...@@ -161,6 +169,7 @@ struct rockchip_usb2phy_cfg {
* @suspended: phy suspended flag. * @suspended: phy suspended flag.
* @vbus_attached: otg device vbus status. * @vbus_attached: otg device vbus status.
* @bvalid_irq: IRQ number assigned for vbus valid rise detection. * @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. * @ls_irq: IRQ number assigned for linestate detection.
* @otg_mux_irq: IRQ number which multiplex otg-id/otg-bvalid/linestate * @otg_mux_irq: IRQ number which multiplex otg-id/otg-bvalid/linestate
* irqs to one irq in otg-port. * irqs to one irq in otg-port.
...@@ -179,6 +188,7 @@ struct rockchip_usb2phy_port { ...@@ -179,6 +188,7 @@ struct rockchip_usb2phy_port {
bool suspended; bool suspended;
bool vbus_attached; bool vbus_attached;
int bvalid_irq; int bvalid_irq;
int id_irq;
int ls_irq; int ls_irq;
int otg_mux_irq; int otg_mux_irq;
struct mutex mutex; struct mutex mutex;
...@@ -253,7 +263,7 @@ static inline bool property_enabled(struct regmap *base, ...@@ -253,7 +263,7 @@ static inline bool property_enabled(struct regmap *base,
return false; return false;
tmp = (orig & mask) >> reg->bitstart; tmp = (orig & mask) >> reg->bitstart;
return tmp == reg->enable; return tmp != reg->disable;
} }
static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw) static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw)
...@@ -419,6 +429,19 @@ static int rockchip_usb2phy_init(struct phy *phy) ...@@ -419,6 +429,19 @@ static int rockchip_usb2phy_init(struct phy *phy)
if (ret) if (ret)
goto out; 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, schedule_delayed_work(&rport->otg_sm_work,
OTG_SCHEDULE_DELAY * 3); OTG_SCHEDULE_DELAY * 3);
} else { } else {
...@@ -905,27 +928,40 @@ static irqreturn_t rockchip_usb2phy_bvalid_irq(int irq, void *data) ...@@ -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)) if (!property_enabled(rphy->grf, &rport->port_cfg->bvalid_det_st))
return IRQ_NONE; return IRQ_NONE;
mutex_lock(&rport->mutex);
/* clear bvalid detect irq pending status */ /* clear bvalid detect irq pending status */
property_enable(rphy->grf, &rport->port_cfg->bvalid_det_clr, true); 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); rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work);
return IRQ_HANDLED; 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_port *rport = data;
struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
bool id;
if (property_enabled(rphy->grf, &rport->port_cfg->bvalid_det_st)) if (!property_enabled(rphy->grf, &rport->port_cfg->id_det_st))
return rockchip_usb2phy_bvalid_irq(irq, data);
else
return IRQ_NONE; 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) static irqreturn_t rockchip_usb2phy_irq(int irq, void *data)
...@@ -940,8 +976,14 @@ 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) if (!rport->phy)
continue; continue;
/* Handle linestate irq for both otg port and host port */ switch (rport->port_id) {
ret = rockchip_usb2phy_linestate_irq(irq, rport); 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; return ret;
...@@ -1015,6 +1057,25 @@ static int rockchip_usb2phy_port_irq_init(struct rockchip_usb2phy *rphy, ...@@ -1015,6 +1057,25 @@ static int rockchip_usb2phy_port_irq_init(struct rockchip_usb2phy *rphy,
"failed to request otg-bvalid irq handle\n"); "failed to request otg-bvalid irq handle\n");
return ret; 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; break;
default: default:
...@@ -1289,10 +1350,14 @@ static const struct rockchip_usb2phy_cfg rk3228_phy_cfgs[] = { ...@@ -1289,10 +1350,14 @@ static const struct rockchip_usb2phy_cfg rk3228_phy_cfgs[] = {
.bvalid_det_en = { 0x0680, 3, 3, 0, 1 }, .bvalid_det_en = { 0x0680, 3, 3, 0, 1 },
.bvalid_det_st = { 0x0690, 3, 3, 0, 1 }, .bvalid_det_st = { 0x0690, 3, 3, 0, 1 },
.bvalid_det_clr = { 0x06a0, 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_en = { 0x0680, 2, 2, 0, 1 },
.ls_det_st = { 0x0690, 2, 2, 0, 1 }, .ls_det_st = { 0x0690, 2, 2, 0, 1 },
.ls_det_clr = { 0x06a0, 2, 2, 0, 1 }, .ls_det_clr = { 0x06a0, 2, 2, 0, 1 },
.utmi_bvalid = { 0x0480, 4, 4, 0, 1 }, .utmi_bvalid = { 0x0480, 4, 4, 0, 1 },
.utmi_id = { 0x0480, 1, 1, 0, 1 },
.utmi_ls = { 0x0480, 3, 2, 0, 1 }, .utmi_ls = { 0x0480, 3, 2, 0, 1 },
}, },
[USB2PHY_PORT_HOST] = { [USB2PHY_PORT_HOST] = {
...@@ -1345,14 +1410,18 @@ static const struct rockchip_usb2phy_cfg rk3308_phy_cfgs[] = { ...@@ -1345,14 +1410,18 @@ static const struct rockchip_usb2phy_cfg rk3308_phy_cfgs[] = {
.port_cfgs = { .port_cfgs = {
[USB2PHY_PORT_OTG] = { [USB2PHY_PORT_OTG] = {
.phy_sus = { 0x0100, 8, 0, 0, 0x1d1 }, .phy_sus = { 0x0100, 8, 0, 0, 0x1d1 },
.bvalid_det_en = { 0x3020, 2, 2, 0, 1 }, .bvalid_det_en = { 0x3020, 3, 2, 0, 3 },
.bvalid_det_st = { 0x3024, 2, 2, 0, 1 }, .bvalid_det_st = { 0x3024, 3, 2, 0, 3 },
.bvalid_det_clr = { 0x3028, 2, 2, 0, 1 }, .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_en = { 0x3020, 0, 0, 0, 1 },
.ls_det_st = { 0x3024, 0, 0, 0, 1 }, .ls_det_st = { 0x3024, 0, 0, 0, 1 },
.ls_det_clr = { 0x3028, 0, 0, 0, 1 }, .ls_det_clr = { 0x3028, 0, 0, 0, 1 },
.utmi_avalid = { 0x0120, 10, 10, 0, 1 }, .utmi_avalid = { 0x0120, 10, 10, 0, 1 },
.utmi_bvalid = { 0x0120, 9, 9, 0, 1 }, .utmi_bvalid = { 0x0120, 9, 9, 0, 1 },
.utmi_id = { 0x0120, 6, 6, 0, 1 },
.utmi_ls = { 0x0120, 5, 4, 0, 1 }, .utmi_ls = { 0x0120, 5, 4, 0, 1 },
}, },
[USB2PHY_PORT_HOST] = { [USB2PHY_PORT_HOST] = {
...@@ -1388,14 +1457,18 @@ static const struct rockchip_usb2phy_cfg rk3328_phy_cfgs[] = { ...@@ -1388,14 +1457,18 @@ static const struct rockchip_usb2phy_cfg rk3328_phy_cfgs[] = {
.port_cfgs = { .port_cfgs = {
[USB2PHY_PORT_OTG] = { [USB2PHY_PORT_OTG] = {
.phy_sus = { 0x0100, 15, 0, 0, 0x1d1 }, .phy_sus = { 0x0100, 15, 0, 0, 0x1d1 },
.bvalid_det_en = { 0x0110, 2, 2, 0, 1 }, .bvalid_det_en = { 0x0110, 3, 2, 0, 3 },
.bvalid_det_st = { 0x0114, 2, 2, 0, 1 }, .bvalid_det_st = { 0x0114, 3, 2, 0, 3 },
.bvalid_det_clr = { 0x0118, 2, 2, 0, 1 }, .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_en = { 0x0110, 0, 0, 0, 1 },
.ls_det_st = { 0x0114, 0, 0, 0, 1 }, .ls_det_st = { 0x0114, 0, 0, 0, 1 },
.ls_det_clr = { 0x0118, 0, 0, 0, 1 }, .ls_det_clr = { 0x0118, 0, 0, 0, 1 },
.utmi_avalid = { 0x0120, 10, 10, 0, 1 }, .utmi_avalid = { 0x0120, 10, 10, 0, 1 },
.utmi_bvalid = { 0x0120, 9, 9, 0, 1 }, .utmi_bvalid = { 0x0120, 9, 9, 0, 1 },
.utmi_id = { 0x0120, 6, 6, 0, 1 },
.utmi_ls = { 0x0120, 5, 4, 0, 1 }, .utmi_ls = { 0x0120, 5, 4, 0, 1 },
}, },
[USB2PHY_PORT_HOST] = { [USB2PHY_PORT_HOST] = {
...@@ -1453,8 +1526,12 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = { ...@@ -1453,8 +1526,12 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
.bvalid_det_en = { 0xe3c0, 3, 3, 0, 1 }, .bvalid_det_en = { 0xe3c0, 3, 3, 0, 1 },
.bvalid_det_st = { 0xe3e0, 3, 3, 0, 1 }, .bvalid_det_st = { 0xe3e0, 3, 3, 0, 1 },
.bvalid_det_clr = { 0xe3d0, 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_avalid = { 0xe2ac, 7, 7, 0, 1 },
.utmi_bvalid = { 0xe2ac, 12, 12, 0, 1 }, .utmi_bvalid = { 0xe2ac, 12, 12, 0, 1 },
.utmi_id = { 0xe2ac, 8, 8, 0, 1 },
}, },
[USB2PHY_PORT_HOST] = { [USB2PHY_PORT_HOST] = {
.phy_sus = { 0xe458, 1, 0, 0x2, 0x1 }, .phy_sus = { 0xe458, 1, 0, 0x2, 0x1 },
...@@ -1488,8 +1565,12 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = { ...@@ -1488,8 +1565,12 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
.bvalid_det_en = { 0xe3c0, 8, 8, 0, 1 }, .bvalid_det_en = { 0xe3c0, 8, 8, 0, 1 },
.bvalid_det_st = { 0xe3e0, 8, 8, 0, 1 }, .bvalid_det_st = { 0xe3e0, 8, 8, 0, 1 },
.bvalid_det_clr = { 0xe3d0, 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_avalid = { 0xe2ac, 10, 10, 0, 1 },
.utmi_bvalid = { 0xe2ac, 16, 16, 0, 1 }, .utmi_bvalid = { 0xe2ac, 16, 16, 0, 1 },
.utmi_id = { 0xe2ac, 11, 11, 0, 1 },
}, },
[USB2PHY_PORT_HOST] = { [USB2PHY_PORT_HOST] = {
.phy_sus = { 0xe468, 1, 0, 0x2, 0x1 }, .phy_sus = { 0xe468, 1, 0, 0x2, 0x1 },
...@@ -1512,11 +1593,15 @@ static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = { ...@@ -1512,11 +1593,15 @@ static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = {
.port_cfgs = { .port_cfgs = {
[USB2PHY_PORT_OTG] = { [USB2PHY_PORT_OTG] = {
.phy_sus = { 0x0000, 8, 0, 0, 0x1d1 }, .phy_sus = { 0x0000, 8, 0, 0, 0x1d1 },
.bvalid_det_en = { 0x0080, 2, 2, 0, 1 }, .bvalid_det_en = { 0x0080, 3, 2, 0, 3 },
.bvalid_det_st = { 0x0084, 2, 2, 0, 1 }, .bvalid_det_st = { 0x0084, 3, 2, 0, 3 },
.bvalid_det_clr = { 0x0088, 2, 2, 0, 1 }, .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_avalid = { 0x00c0, 10, 10, 0, 1 },
.utmi_bvalid = { 0x00c0, 9, 9, 0, 1 }, .utmi_bvalid = { 0x00c0, 9, 9, 0, 1 },
.utmi_id = { 0x00c0, 6, 6, 0, 1 },
}, },
[USB2PHY_PORT_HOST] = { [USB2PHY_PORT_HOST] = {
/* Select suspend control from controller */ /* Select suspend control from controller */
......
...@@ -1105,15 +1105,14 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) ...@@ -1105,15 +1105,14 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
struct phy_provider *phy_provider; struct phy_provider *phy_provider;
struct resource *res; struct resource *res;
const struct rockchip_usb3phy_port_cfg *phy_cfgs; const struct rockchip_usb3phy_port_cfg *phy_cfgs;
const struct of_device_id *match;
int index, ret; int index, ret;
tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL); tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL);
if (!tcphy) if (!tcphy)
return -ENOMEM; return -ENOMEM;
match = of_match_device(dev->driver->of_match_table, dev); phy_cfgs = of_device_get_match_data(dev);
if (!match || !match->data) { if (!phy_cfgs) {
dev_err(dev, "phy configs are not assigned!\n"); dev_err(dev, "phy configs are not assigned!\n");
return -EINVAL; return -EINVAL;
} }
...@@ -1123,7 +1122,6 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) ...@@ -1123,7 +1122,6 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
if (IS_ERR(tcphy->base)) if (IS_ERR(tcphy->base))
return PTR_ERR(tcphy->base); return PTR_ERR(tcphy->base);
phy_cfgs = match->data;
/* find out a proper config which can be matched with dt. */ /* find out a proper config which can be matched with dt. */
index = 0; index = 0;
while (phy_cfgs[index].reg) { while (phy_cfgs[index].reg) {
......
/* 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 @@ ...@@ -17,6 +17,7 @@
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/phy/phy-dp.h> #include <linux/phy/phy-dp.h>
#include <linux/phy/phy-lvds.h>
#include <linux/phy/phy-mipi-dphy.h> #include <linux/phy/phy-mipi-dphy.h>
struct phy; struct phy;
...@@ -57,10 +58,13 @@ enum phy_media { ...@@ -57,10 +58,13 @@ enum phy_media {
* the MIPI_DPHY phy mode. * the MIPI_DPHY phy mode.
* @dp: Configuration set applicable for phys supporting * @dp: Configuration set applicable for phys supporting
* the DisplayPort protocol. * the DisplayPort protocol.
* @lvds: Configuration set applicable for phys supporting
* the LVDS phy mode.
*/ */
union phy_configure_opts { union phy_configure_opts {
struct phy_configure_opts_mipi_dphy mipi_dphy; struct phy_configure_opts_mipi_dphy mipi_dphy;
struct phy_configure_opts_dp dp; struct phy_configure_opts_dp dp;
struct phy_configure_opts_lvds lvds;
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment