phy-for-5.15

- Updates:
         - Yaml conversion for Freescale imx8mq usb phy, TI AM654 SERDES phy,
           Cadence torrent phy
         - Updates for Amlogic Meson8b-usb2 phy, Samsung ufs phy
 
   - New support:
         - UFS phy for Qualcomm SM6115
 	- PCIe & USB/DP phy for Qualcomm sc8180x
 	- USB3 PHY support for Qualcomm IPQ6018
 	- Renesas USB2.0 PHY for RZ/G2L
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmEkfloACgkQfBQHDyUj
 g0dwzA/9G658xS6jZSLTQX3PzWSpxk+mmmC2IR7fkeB5ShVcrju83PGRD0OQnpkG
 aRZRZy20iGbuKkrA/+oIliVgNEg44D32zqD5pojHAfmwMUNMUP6R4YmAFNreJ3Do
 sHXLlS3p9hhRZONKbl6VMg6rS4yTre79ozTovNH6HGyTlSObezAaKVjUTCofuSaa
 /AXL2/WCINJuCtZmm67/AHxgzptK/h7FSqJdg4JET7Dt6Y/HN/WrNCwcyOlloteQ
 Dyc+C0cdBncRK6A1og83A3jw7oiOhl2/72paCyQFljvS4v0BW8B3Sth1hukE2rsE
 RmtP4EYSLN8uWXdLsBjerS09WFfjZBlE8UeU46AhzffCWOwCwgRwdJFpqUjN/OCO
 ain9X16yQY8SBHShjxQAQMt5OtTNJCb0qhfcDa+47D5b+NNVJxfMoUTjPzqg7dpB
 JJZZzUgNyd2PxvLApzgkYj5yqv/PN1cXB6UYqOQN/YojmyZKtIB1U+9JvY01Qb8c
 9Dj92M7rUGzgfmUqLl4WPWhUZu56e0W/VRlYftFNOgAbQ+SehyG9CREaEqJCNzzl
 m9HAL4ZzpK8hGQbS5FHiWrplcX8IQWd+XF8vXhkVV+wiE+ryGiPB5LrkjKfvEmoa
 AgfpzHBOSATpR2nuRL/bruMZeHFhj2kzFQpg0MXhyfZAr06Zq5U=
 =3U1A
 -----END PGP SIGNATURE-----

Merge tag 'phy-for-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy into char-misc-next

Vinod writes:

phy-for-5.15

  - Updates:
        - Yaml conversion for Freescale imx8mq usb phy, TI AM654 SERDES phy,
          Cadence torrent phy
        - Updates for Amlogic Meson8b-usb2 phy, Samsung ufs phy

  - New support:
        - UFS phy for Qualcomm SM6115
	- PCIe & USB/DP phy for Qualcomm sc8180x
	- USB3 PHY support for Qualcomm IPQ6018
	- Renesas USB2.0 PHY for RZ/G2L

* tag 'phy-for-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (45 commits)
  phy: qcom-qmp: Add support for SM6115 UFS phy
  dt-bindings: phy: qcom,qmp: Add SM6115 UFS PHY bindings
  phy: qmp: Provide unique clock names for DP clocks
  phy: xilinx: zynqmp: skip PHY initialization and PLL lock for USB
  phy: amlogic: meson8b-usb2: don't log an error on -EPROBE_DEFER
  phy: amlogic: meson8b-usb2: Power off the PHY by putting it into reset mode
  phy: phy-mtk-mipi-dsi: convert to devm_platform_ioremap_resource
  phy: phy-mtk-mipi-dsi: remove dummy assignment of error number
  phy: phy-mtk-hdmi: convert to devm_platform_ioremap_resource
  phy: phy-mtk-ufs: use clock bulk to get clocks
  phy: phy-mtk-tphy: remove error log of ioremap failure
  phy: phy-mtk-tphy: print error log using child device
  phy: phy-mtk-tphy: support type switch by pericfg
  phy: phy-mtk-tphy: use clock bulk to get clocks
  dt-bindings: phy: mediatek: tphy: support type switch by pericfg
  phy: cadence-torrent: Check PIPE mode PHY status to be ready for operation
  phy: cadence-torrent: Add debug information for PHY configuration
  phy: cadence-torrent: Add separate functions for reusable code
  phy: cadence-torrent: Add PHY configuration for DP with 100MHz ref clock
  phy: cadence-torrent: Add PHY registers for DP in array format
  ...
This commit is contained in:
Greg Kroah-Hartman 2021-08-24 15:35:24 +02:00
commit 96e9df335a
29 changed files with 2398 additions and 1394 deletions

View File

@ -1,20 +0,0 @@
* Freescale i.MX8MQ USB3 PHY binding
Required properties:
- compatible: Should be "fsl,imx8mq-usb-phy" or "fsl,imx8mp-usb-phy"
- #phys-cells: must be 0 (see phy-bindings.txt in this directory)
- reg: The base address and length of the registers
- clocks: phandles to the clocks for each clock listed in clock-names
- clock-names: must contain "phy"
Optional properties:
- vbus-supply: A phandle to the regulator for USB VBUS.
Example:
usb3_phy0: phy@381f0040 {
compatible = "fsl,imx8mq-usb-phy";
reg = <0x381f0040 0x40>;
clocks = <&clk IMX8MQ_CLK_USB1_PHY_ROOT>;
clock-names = "phy";
#phy-cells = <0>;
};

View File

@ -0,0 +1,53 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/fsl,imx8mq-usb-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX8MQ USB3 PHY binding
maintainers:
- Li Jun <jun.li@nxp.com>
properties:
compatible:
enum:
- fsl,imx8mq-usb-phy
- fsl,imx8mp-usb-phy
reg:
maxItems: 1
"#phy-cells":
const: 0
clocks:
maxItems: 1
clock-names:
items:
- const: phy
vbus-supply:
description:
A phandle to the regulator for USB VBUS.
required:
- compatible
- reg
- "#phy-cells"
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx8mq-clock.h>
usb3_phy0: phy@381f0040 {
compatible = "fsl,imx8mq-usb-phy";
reg = <0x381f0040 0x40>;
clocks = <&clk IMX8MQ_CLK_USB1_PHY_ROOT>;
clock-names = "phy";
#phy-cells = <0>;
};

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/intel,phy-keembay-usb.yaml#
$id: http://devicetree.org/schemas/phy/intel,keembay-phy-usb.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intel Keem Bay USB PHY bindings

View File

@ -15,7 +15,7 @@ description: |
controllers on MediaTek SoCs, includes USB2.0, USB3.0, PCIe and SATA.
Layout differences of banks between T-PHY V1 (mt8173/mt2701) and
T-PHY V2 (mt2712) when works on USB mode:
T-PHY V2 (mt2712) / V3 (mt8195) when works on USB mode:
-----------------------------------
Version 1:
port offset bank
@ -34,7 +34,7 @@ description: |
u2 port2 0x1800 U2PHY_COM
...
Version 2:
Version 2/3:
port offset bank
u2 port0 0x0000 MISC
0x0100 FMREG
@ -59,7 +59,8 @@ description: |
SPLLC shared by u3 ports and FMREG shared by u2 ports on V1 are put back
into each port; a new bank MISC for u2 ports and CHIP for u3 ports are
added on V2.
added on V2; the FMREG bank for slew rate calibration is not used anymore
and reserved on V3;
properties:
$nodename:
@ -79,8 +80,11 @@ properties:
- mediatek,mt2712-tphy
- mediatek,mt7629-tphy
- mediatek,mt8183-tphy
- mediatek,mt8195-tphy
- const: mediatek,generic-tphy-v2
- items:
- enum:
- mediatek,mt8195-tphy
- const: mediatek,generic-tphy-v3
- const: mediatek,mt2701-u3phy
deprecated: true
- const: mediatek,mt2712-u3phy
@ -91,7 +95,7 @@ properties:
description:
Register shared by multiple ports, exclude port's private register.
It is needed for T-PHY V1, such as mt2701 and mt8173, but not for
T-PHY V2, such as mt2712.
T-PHY V2/V3, such as mt2712.
maxItems: 1
"#address-cells":
@ -197,6 +201,22 @@ patternProperties:
Specify the flag to enable BC1.2 if support it
type: boolean
mediatek,syscon-type:
$ref: /schemas/types.yaml#/definitions/phandle-array
maxItems: 1
description:
A phandle to syscon used to access the register of type switch,
the field should always be 3 cells long.
items:
items:
- description:
The first cell represents a phandle to syscon
- description:
The second cell represents the register offset
- description:
The third cell represents the index of config segment
enum: [0, 1, 2, 3]
required:
- reg
- "#phy-cells"

View File

@ -18,6 +18,7 @@ properties:
compatible:
enum:
- qcom,ipq6018-qmp-pcie-phy
- qcom,ipq6018-qmp-usb3-phy
- qcom,ipq8074-qmp-pcie-phy
- qcom,ipq8074-qmp-usb3-phy
- qcom,msm8996-qmp-pcie-phy
@ -27,6 +28,7 @@ properties:
- qcom,msm8998-qmp-ufs-phy
- qcom,msm8998-qmp-usb3-phy
- qcom,sc7180-qmp-usb3-phy
- qcom,sc8180x-qmp-pcie-phy
- qcom,sc8180x-qmp-ufs-phy
- qcom,sc8180x-qmp-usb3-phy
- qcom,sdm845-qhp-pcie-phy
@ -34,6 +36,7 @@ properties:
- qcom,sdm845-qmp-ufs-phy
- qcom,sdm845-qmp-usb3-phy
- qcom,sdm845-qmp-usb3-uni-phy
- qcom,sm6115-qmp-ufs-phy
- qcom,sm8150-qmp-ufs-phy
- qcom,sm8150-qmp-usb3-phy
- qcom,sm8150-qmp-usb3-uni-phy
@ -326,6 +329,7 @@ allOf:
compatible:
contains:
enum:
- qcom,sc8180x-qmp-pcie-phy
- qcom,sdm845-qhp-pcie-phy
- qcom,sdm845-qmp-pcie-phy
- qcom,sdx55-qmp-pcie-phy

View File

@ -14,6 +14,7 @@ properties:
compatible:
enum:
- qcom,sc7180-qmp-usb3-dp-phy
- qcom,sc8180x-qmp-usb3-dp-phy
- qcom,sdm845-qmp-usb3-dp-phy
- qcom,sm8250-qmp-usb3-dp-phy
reg:

View File

@ -30,6 +30,11 @@ properties:
- renesas,usb2-phy-r8a77995 # R-Car D3
- const: renesas,rcar-gen3-usb2-phy
- items:
- enum:
- renesas,usb2-phy-r9a07g044 # RZ/G2{L,LC}
- const: renesas,rzg2l-usb2-phy # RZ/G2L family
reg:
maxItems: 1
@ -91,6 +96,16 @@ required:
- clocks
- '#phy-cells'
allOf:
- if:
properties:
compatible:
contains:
const: renesas,rzg2l-usb2-phy
then:
required:
- resets
additionalProperties: false
examples:

View File

@ -16,6 +16,7 @@ properties:
compatible:
enum:
- samsung,exynos7-ufs-phy
- samsung,exynosautov9-ufs-phy
reg:
maxItems: 1

View File

@ -1,82 +0,0 @@
TI AM654 SERDES
Required properties:
- compatible: Should be "ti,phy-am654-serdes"
- reg : Address and length of the register set for the device.
- #phy-cells: determine the number of cells that should be given in the
phandle while referencing this phy. Should be "2". The 1st cell
corresponds to the phy type (should be one of the types specified in
include/dt-bindings/phy/phy.h) and the 2nd cell should be the serdes
lane function.
If SERDES0 is referenced 2nd cell should be:
0 - USB3
1 - PCIe0 Lane0
2 - ICSS2 SGMII Lane0
If SERDES1 is referenced 2nd cell should be:
0 - PCIe1 Lane0
1 - PCIe0 Lane1
2 - ICSS2 SGMII Lane1
- power-domains: As documented by the generic PM domain bindings in
Documentation/devicetree/bindings/power/power_domain.txt.
- clocks: List of clock-specifiers representing the input to the SERDES.
Should have 3 items representing the left input clock, external
reference clock and right input clock in that order.
- clock-output-names: List of clock names for each of the clock outputs of
SERDES. Should have 3 items for CMU reference clock,
left output clock and right output clock in that order.
- assigned-clocks: As defined in
Documentation/devicetree/bindings/clock/clock-bindings.txt
- assigned-clock-parents: As defined in
Documentation/devicetree/bindings/clock/clock-bindings.txt
- #clock-cells: Should be <1> to choose between the 3 output clocks.
Defined in Documentation/devicetree/bindings/clock/clock-bindings.txt
The following macros are defined in dt-bindings/phy/phy-am654-serdes.h
for selecting the correct reference clock. This can be used while
specifying the clocks created by SERDES.
=> AM654_SERDES_CMU_REFCLK
=> AM654_SERDES_LO_REFCLK
=> AM654_SERDES_RO_REFCLK
- mux-controls: Phandle to the multiplexer that is used to select the lane
function. See #phy-cells above to see the multiplex values.
Example:
Example for SERDES0 is given below. It has 3 clock inputs;
left input reference clock as indicated by <&k3_clks 153 4>, external
reference clock as indicated by <&k3_clks 153 1> and right input
reference clock as indicated by <&serdes1 AM654_SERDES_LO_REFCLK>. (The
right input of SERDES0 is connected to the left output of SERDES1).
SERDES0 registers 3 clock outputs as indicated in clock-output-names. The
first refers to the CMU reference clock, second refers to the left output
reference clock and the third refers to the right output reference clock.
The assigned-clocks and assigned-clock-parents is used here to set the
parent of left input reference clock to MAINHSDIV_CLKOUT4 and parent of
CMU reference clock to left input reference clock.
serdes0: serdes@900000 {
compatible = "ti,phy-am654-serdes";
reg = <0x0 0x900000 0x0 0x2000>;
reg-names = "serdes";
#phy-cells = <2>;
power-domains = <&k3_pds 153>;
clocks = <&k3_clks 153 4>, <&k3_clks 153 1>,
<&serdes1 AM654_SERDES_LO_REFCLK>;
clock-output-names = "serdes0_cmu_refclk", "serdes0_lo_refclk",
"serdes0_ro_refclk";
assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>;
assigned-clock-parents = <&k3_clks 153 8>, <&k3_clks 153 4>;
ti,serdes-clk = <&serdes0_clk>;
mux-controls = <&serdes_mux 0>;
#clock-cells = <1>;
};
Example for PCIe consumer node using the SERDES PHY specifier is given below.
&pcie0_rc {
num-lanes = <2>;
phys = <&serdes0 PHY_TYPE_PCIE 1>, <&serdes1 PHY_TYPE_PCIE 1>;
phy-names = "pcie-phy0", "pcie-phy1";
};

View File

@ -0,0 +1,103 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/ti,phy-am654-serdes.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI AM654 SERDES binding
description:
This binding describes the TI AM654 SERDES. AM654 SERDES can be configured
to be used with either PCIe or USB or SGMII.
maintainers:
- Kishon Vijay Abraham I <kishon@ti.com>
properties:
compatible:
enum:
- ti,phy-am654-serdes
reg:
maxItems: 1
reg-names:
items:
- const: serdes
power-domains:
maxItems: 1
clocks:
maxItems: 3
description:
Three input clocks referring to left input reference clock, refclk and right input reference
clock.
assigned-clocks:
$ref: "/schemas/types.yaml#/definitions/phandle-array"
assigned-clock-parents:
$ref: "/schemas/types.yaml#/definitions/phandle-array"
'#phy-cells':
const: 2
description:
The 1st cell corresponds to the phy type (should be one of the types specified in
include/dt-bindings/phy/phy.h) and the 2nd cell should be the serdes lane function.
ti,serdes-clk:
description: Phandle to the SYSCON entry required for configuring SERDES clock selection.
$ref: /schemas/types.yaml#/definitions/phandle
'#clock-cells':
const: 1
mux-controls:
maxItems: 1
description: Phandle to the SYSCON entry required for configuring SERDES lane function.
clock-output-names:
oneOf:
- description: Clock output names for SERDES 0
items:
- const: serdes0_cmu_refclk
- const: serdes0_lo_refclk
- const: serdes0_ro_refclk
- description: Clock output names for SERDES 1
items:
- const: serdes1_cmu_refclk
- const: serdes1_lo_refclk
- const: serdes1_ro_refclk
required:
- compatible
- reg
- power-domains
- clocks
- assigned-clocks
- assigned-clock-parents
- ti,serdes-clk
- mux-controls
- clock-output-names
additionalProperties: false
examples:
- |
#include <dt-bindings/phy/phy-am654-serdes.h>
serdes0: serdes@900000 {
compatible = "ti,phy-am654-serdes";
reg = <0x900000 0x2000>;
reg-names = "serdes";
#phy-cells = <2>;
power-domains = <&k3_pds 153>;
clocks = <&k3_clks 153 4>, <&k3_clks 153 1>,
<&serdes1 AM654_SERDES_LO_REFCLK>;
clock-output-names = "serdes0_cmu_refclk", "serdes0_lo_refclk", "serdes0_ro_refclk";
assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>;
assigned-clock-parents = <&k3_clks 153 8>, <&k3_clks 153 4>;
ti,serdes-clk = <&serdes0_clk>;
mux-controls = <&serdes_mux 0>;
#clock-cells = <1>;
};

View File

@ -219,6 +219,10 @@ static int phy_meson8b_usb2_power_off(struct phy *phy)
clk_disable_unprepare(priv->clk_usb);
clk_disable_unprepare(priv->clk_usb_general);
/* power off the PHY by putting it into reset mode */
regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET,
REG_CTRL_POWER_ON_RESET);
return 0;
}
@ -273,8 +277,8 @@ static int phy_meson8b_usb2_probe(struct platform_device *pdev)
phy = devm_phy_create(&pdev->dev, NULL, &phy_meson8b_usb2_ops);
if (IS_ERR(phy)) {
dev_err(&pdev->dev, "failed to create PHY\n");
return PTR_ERR(phy);
return dev_err_probe(&pdev->dev, PTR_ERR(phy),
"failed to create PHY\n");
}
phy_set_drvdata(phy, priv);

File diff suppressed because it is too large Load Diff

View File

@ -100,7 +100,6 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_hdmi_phy *hdmi_phy;
struct resource *mem;
struct clk *ref_clk;
const char *ref_clk_name;
struct clk_init_data clk_init = {
@ -116,11 +115,9 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev)
if (!hdmi_phy)
return -ENOMEM;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hdmi_phy->regs = devm_ioremap_resource(dev, mem);
if (IS_ERR(hdmi_phy->regs)) {
hdmi_phy->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(hdmi_phy->regs))
return PTR_ERR(hdmi_phy->regs);
}
ref_clk = devm_clk_get(dev, "pll_ref");
if (IS_ERR(ref_clk)) {

View File

@ -130,7 +130,6 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_mipi_tx *mipi_tx;
struct resource *mem;
const char *ref_clk_name;
struct clk *ref_clk;
struct clk_init_data clk_init = {
@ -148,11 +147,9 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
mipi_tx->driver_data = of_device_get_match_data(dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mipi_tx->regs = devm_ioremap_resource(dev, mem);
if (IS_ERR(mipi_tx->regs)) {
mipi_tx->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mipi_tx->regs))
return PTR_ERR(mipi_tx->regs);
}
ref_clk = devm_clk_get(dev, NULL);
if (IS_ERR(ref_clk)) {
@ -203,10 +200,8 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
phy_set_drvdata(phy, mipi_tx);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(phy_provider)) {
ret = PTR_ERR(phy_provider);
return ret;
}
if (IS_ERR(phy_provider))
return PTR_ERR(phy_provider);
mipi_tx->dev = dev;

View File

@ -10,11 +10,13 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
/* version V1 sub-banks offset base address */
/* banks shared by multiple phys */
@ -27,7 +29,8 @@
#define SSUSB_SIFSLV_V1_U3PHYD 0x000
#define SSUSB_SIFSLV_V1_U3PHYA 0x200
/* version V2 sub-banks offset base address */
/* version V2/V3 sub-banks offset base address */
/* V3: U2FREQ is not used anymore, but reserved */
/* u2 phy banks */
#define SSUSB_SIFSLV_V2_MISC 0x000
#define SSUSB_SIFSLV_V2_U2FREQ 0x100
@ -40,6 +43,8 @@
#define U3P_USBPHYACR0 0x000
#define PA0_RG_U2PLL_FORCE_ON BIT(15)
#define PA0_USB20_PLL_PREDIV GENMASK(7, 6)
#define PA0_USB20_PLL_PREDIV_VAL(x) ((0x3 & (x)) << 6)
#define PA0_RG_USB20_INTR_EN BIT(5)
#define U3P_USBPHYACR1 0x004
@ -51,6 +56,8 @@
#define PA1_RG_TERM_SEL_VAL(x) ((0x7 & (x)) << 8)
#define U3P_USBPHYACR2 0x008
#define PA2_RG_U2PLL_BW GENMASK(21, 19)
#define PA2_RG_U2PLL_BW_VAL(x) ((0x7 & (x)) << 19)
#define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18)
#define U3P_USBPHYACR5 0x014
@ -72,6 +79,14 @@
#define P2C_USB20_GPIO_MODE BIT(8)
#define P2C_U2_GPIO_CTR_MSK (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE)
#define U3P_U2PHYA_RESV 0x030
#define P2R_RG_U2PLL_FBDIV_26M 0x1bb13b
#define P2R_RG_U2PLL_FBDIV_48M 0x3c0000
#define U3P_U2PHYA_RESV1 0x044
#define P2R_RG_U2PLL_REFCLK_SEL BIT(5)
#define P2R_RG_U2PLL_FRA_EN BIT(3)
#define U3D_U2PHYDCR0 0x060
#define P2C_RG_SIF_U2PLL_FORCE_ON BIT(24)
@ -267,14 +282,31 @@
#define RG_CDR_BIRLTD0_GEN3_MSK GENMASK(4, 0)
#define RG_CDR_BIRLTD0_GEN3_VAL(x) (0x1f & (x))
/* PHY switch between pcie/usb3/sgmii/sata */
#define USB_PHY_SWITCH_CTRL 0x0
#define RG_PHY_SW_TYPE GENMASK(3, 0)
#define RG_PHY_SW_PCIE 0x0
#define RG_PHY_SW_USB3 0x1
#define RG_PHY_SW_SGMII 0x2
#define RG_PHY_SW_SATA 0x3
#define TPHY_CLKS_CNT 2
enum mtk_phy_version {
MTK_PHY_V1 = 1,
MTK_PHY_V2,
MTK_PHY_V3,
};
struct mtk_phy_pdata {
/* avoid RX sensitivity level degradation only for mt8173 */
bool avoid_rx_sen_degradation;
/*
* workaround only for mt8195, HW fix it for others of V3,
* u2phy should use integer mode instead of fractional mode of
* 48M PLL, fix it by switching PLL to 26M from default 48M
*/
bool sw_pll_48m_to_26m;
enum mtk_phy_version version;
};
@ -298,10 +330,12 @@ struct mtk_phy_instance {
struct u2phy_banks u2_banks;
struct u3phy_banks u3_banks;
};
struct clk *ref_clk; /* reference clock of (digital) phy */
struct clk *da_ref_clk; /* reference clock of analog phy */
struct clk_bulk_data clks[TPHY_CLKS_CNT];
u32 index;
u8 type;
u32 type;
struct regmap *type_sw;
u32 type_sw_reg;
u32 type_sw_index;
int eye_src;
int eye_vrt;
int eye_term;
@ -330,6 +364,10 @@ static void hs_slew_rate_calibrate(struct mtk_tphy *tphy,
int fm_out;
u32 tmp;
/* HW V3 doesn't support slew rate cal anymore */
if (tphy->pdata->version == MTK_PHY_V3)
return;
/* use force value */
if (instance->eye_src)
return;
@ -450,6 +488,33 @@ static void u3_phy_instance_init(struct mtk_tphy *tphy,
dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);
}
static void u2_phy_pll_26m_set(struct mtk_tphy *tphy,
struct mtk_phy_instance *instance)
{
struct u2phy_banks *u2_banks = &instance->u2_banks;
void __iomem *com = u2_banks->com;
u32 tmp;
if (!tphy->pdata->sw_pll_48m_to_26m)
return;
tmp = readl(com + U3P_USBPHYACR0);
tmp &= ~PA0_USB20_PLL_PREDIV;
tmp |= PA0_USB20_PLL_PREDIV_VAL(0);
writel(tmp, com + U3P_USBPHYACR0);
tmp = readl(com + U3P_USBPHYACR2);
tmp &= ~PA2_RG_U2PLL_BW;
tmp |= PA2_RG_U2PLL_BW_VAL(3);
writel(tmp, com + U3P_USBPHYACR2);
writel(P2R_RG_U2PLL_FBDIV_26M, com + U3P_U2PHYA_RESV);
tmp = readl(com + U3P_U2PHYA_RESV1);
tmp |= P2R_RG_U2PLL_FRA_EN | P2R_RG_U2PLL_REFCLK_SEL;
writel(tmp, com + U3P_U2PHYA_RESV1);
}
static void u2_phy_instance_init(struct mtk_tphy *tphy,
struct mtk_phy_instance *instance)
{
@ -509,6 +574,9 @@ static void u2_phy_instance_init(struct mtk_tphy *tphy,
tmp |= PA6_RG_U2_SQTH_VAL(2);
writel(tmp, com + U3P_USBPHYACR6);
/* Workaround only for mt8195, HW fix it for others (V3) */
u2_phy_pll_26m_set(tphy, instance);
dev_dbg(tphy->dev, "%s(%d)\n", __func__, index);
}
@ -878,7 +946,7 @@ static void u2_phy_props_set(struct mtk_tphy *tphy,
writel(tmp, com + U3P_U2PHYBC12C);
}
if (instance->eye_src) {
if (tphy->pdata->version < MTK_PHY_V3 && instance->eye_src) {
tmp = readl(com + U3P_USBPHYACR5);
tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(instance->eye_src);
@ -914,24 +982,73 @@ static void u2_phy_props_set(struct mtk_tphy *tphy,
}
}
/* type switch for usb3/pcie/sgmii/sata */
static int phy_type_syscon_get(struct mtk_phy_instance *instance,
struct device_node *dn)
{
struct of_phandle_args args;
int ret;
/* type switch function is optional */
if (!of_property_read_bool(dn, "mediatek,syscon-type"))
return 0;
ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type",
2, 0, &args);
if (ret)
return ret;
instance->type_sw_reg = args.args[0];
instance->type_sw_index = args.args[1] & 0x3; /* <=3 */
instance->type_sw = syscon_node_to_regmap(args.np);
of_node_put(args.np);
dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n",
instance->type_sw_reg, instance->type_sw_index);
return PTR_ERR_OR_ZERO(instance->type_sw);
}
static int phy_type_set(struct mtk_phy_instance *instance)
{
int type;
u32 mask;
if (!instance->type_sw)
return 0;
switch (instance->type) {
case PHY_TYPE_USB3:
type = RG_PHY_SW_USB3;
break;
case PHY_TYPE_PCIE:
type = RG_PHY_SW_PCIE;
break;
case PHY_TYPE_SGMII:
type = RG_PHY_SW_SGMII;
break;
case PHY_TYPE_SATA:
type = RG_PHY_SW_SATA;
break;
case PHY_TYPE_USB2:
default:
return 0;
}
mask = RG_PHY_SW_TYPE << (instance->type_sw_index * BITS_PER_BYTE);
regmap_update_bits(instance->type_sw, instance->type_sw_reg, mask, type);
return 0;
}
static int mtk_phy_init(struct phy *phy)
{
struct mtk_phy_instance *instance = phy_get_drvdata(phy);
struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
int ret;
ret = clk_prepare_enable(instance->ref_clk);
if (ret) {
dev_err(tphy->dev, "failed to enable ref_clk\n");
ret = clk_bulk_prepare_enable(TPHY_CLKS_CNT, instance->clks);
if (ret)
return ret;
}
ret = clk_prepare_enable(instance->da_ref_clk);
if (ret) {
dev_err(tphy->dev, "failed to enable da_ref\n");
clk_disable_unprepare(instance->ref_clk);
return ret;
}
switch (instance->type) {
case PHY_TYPE_USB2:
@ -947,10 +1064,12 @@ static int mtk_phy_init(struct phy *phy)
case PHY_TYPE_SATA:
sata_phy_instance_init(tphy, instance);
break;
case PHY_TYPE_SGMII:
/* nothing to do, only used to set type */
break;
default:
dev_err(tphy->dev, "incompatible PHY type\n");
clk_disable_unprepare(instance->ref_clk);
clk_disable_unprepare(instance->da_ref_clk);
clk_bulk_disable_unprepare(TPHY_CLKS_CNT, instance->clks);
return -EINVAL;
}
@ -993,8 +1112,7 @@ static int mtk_phy_exit(struct phy *phy)
if (instance->type == PHY_TYPE_USB2)
u2_phy_instance_exit(tphy, instance);
clk_disable_unprepare(instance->ref_clk);
clk_disable_unprepare(instance->da_ref_clk);
clk_bulk_disable_unprepare(TPHY_CLKS_CNT, instance->clks);
return 0;
}
@ -1037,21 +1155,27 @@ static struct phy *mtk_phy_xlate(struct device *dev,
if (!(instance->type == PHY_TYPE_USB2 ||
instance->type == PHY_TYPE_USB3 ||
instance->type == PHY_TYPE_PCIE ||
instance->type == PHY_TYPE_SATA)) {
instance->type == PHY_TYPE_SATA ||
instance->type == PHY_TYPE_SGMII)) {
dev_err(dev, "unsupported device type: %d\n", instance->type);
return ERR_PTR(-EINVAL);
}
if (tphy->pdata->version == MTK_PHY_V1) {
switch (tphy->pdata->version) {
case MTK_PHY_V1:
phy_v1_banks_init(tphy, instance);
} else if (tphy->pdata->version == MTK_PHY_V2) {
break;
case MTK_PHY_V2:
case MTK_PHY_V3:
phy_v2_banks_init(tphy, instance);
} else {
break;
default:
dev_err(dev, "phy version is not supported\n");
return ERR_PTR(-EINVAL);
}
phy_parse_property(tphy, instance);
phy_type_set(instance);
return instance->phy;
}
@ -1075,17 +1199,28 @@ static const struct mtk_phy_pdata tphy_v2_pdata = {
.version = MTK_PHY_V2,
};
static const struct mtk_phy_pdata tphy_v3_pdata = {
.version = MTK_PHY_V3,
};
static const struct mtk_phy_pdata mt8173_pdata = {
.avoid_rx_sen_degradation = true,
.version = MTK_PHY_V1,
};
static const struct mtk_phy_pdata mt8195_pdata = {
.sw_pll_48m_to_26m = true,
.version = MTK_PHY_V3,
};
static const struct of_device_id mtk_tphy_id_table[] = {
{ .compatible = "mediatek,mt2701-u3phy", .data = &tphy_v1_pdata },
{ .compatible = "mediatek,mt2712-u3phy", .data = &tphy_v2_pdata },
{ .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata },
{ .compatible = "mediatek,mt8195-tphy", .data = &mt8195_pdata },
{ .compatible = "mediatek,generic-tphy-v1", .data = &tphy_v1_pdata },
{ .compatible = "mediatek,generic-tphy-v2", .data = &tphy_v2_pdata },
{ .compatible = "mediatek,generic-tphy-v3", .data = &tphy_v3_pdata },
{ },
};
MODULE_DEVICE_TABLE(of, mtk_tphy_id_table);
@ -1129,16 +1264,21 @@ static int mtk_tphy_probe(struct platform_device *pdev)
}
}
tphy->src_ref_clk = U3P_REF_CLK;
tphy->src_coef = U3P_SLEW_RATE_COEF;
/* update parameters of slew rate calibrate if exist */
device_property_read_u32(dev, "mediatek,src-ref-clk-mhz",
&tphy->src_ref_clk);
device_property_read_u32(dev, "mediatek,src-coef", &tphy->src_coef);
if (tphy->pdata->version < MTK_PHY_V3) {
tphy->src_ref_clk = U3P_REF_CLK;
tphy->src_coef = U3P_SLEW_RATE_COEF;
/* update parameters of slew rate calibrate if exist */
device_property_read_u32(dev, "mediatek,src-ref-clk-mhz",
&tphy->src_ref_clk);
device_property_read_u32(dev, "mediatek,src-coef",
&tphy->src_coef);
}
port = 0;
for_each_child_of_node(np, child_np) {
struct mtk_phy_instance *instance;
struct clk_bulk_data *clks;
struct device *subdev;
struct phy *phy;
instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
@ -1156,16 +1296,16 @@ static int mtk_tphy_probe(struct platform_device *pdev)
goto put_child;
}
subdev = &phy->dev;
retval = of_address_to_resource(child_np, 0, &res);
if (retval) {
dev_err(dev, "failed to get address resource(id-%d)\n",
dev_err(subdev, "failed to get address resource(id-%d)\n",
port);
goto put_child;
}
instance->port_base = devm_ioremap_resource(&phy->dev, &res);
instance->port_base = devm_ioremap_resource(subdev, &res);
if (IS_ERR(instance->port_base)) {
dev_err(dev, "failed to remap phy regs\n");
retval = PTR_ERR(instance->port_base);
goto put_child;
}
@ -1175,20 +1315,16 @@ static int mtk_tphy_probe(struct platform_device *pdev)
phy_set_drvdata(phy, instance);
port++;
instance->ref_clk = devm_clk_get_optional(&phy->dev, "ref");
if (IS_ERR(instance->ref_clk)) {
dev_err(dev, "failed to get ref_clk(id-%d)\n", port);
retval = PTR_ERR(instance->ref_clk);
clks = instance->clks;
clks[0].id = "ref"; /* digital (& analog) clock */
clks[1].id = "da_ref"; /* analog clock */
retval = devm_clk_bulk_get_optional(subdev, TPHY_CLKS_CNT, clks);
if (retval)
goto put_child;
}
instance->da_ref_clk =
devm_clk_get_optional(&phy->dev, "da_ref");
if (IS_ERR(instance->da_ref_clk)) {
dev_err(dev, "failed to get da_ref_clk(id-%d)\n", port);
retval = PTR_ERR(instance->da_ref_clk);
retval = phy_type_syscon_get(instance, child_np);
if (retval)
goto put_child;
}
}
provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);

View File

@ -31,11 +31,12 @@
#define FRC_CDR_ISO_EN BIT(19)
#define CDR_ISO_EN BIT(20)
#define UFSPHY_CLKS_CNT 2
struct ufs_mtk_phy {
struct device *dev;
void __iomem *mmio;
struct clk *mp_clk;
struct clk *unipro_clk;
struct clk_bulk_data clks[UFSPHY_CLKS_CNT];
};
static inline u32 mphy_readl(struct ufs_mtk_phy *phy, u32 reg)
@ -74,20 +75,11 @@ static struct ufs_mtk_phy *get_ufs_mtk_phy(struct phy *generic_phy)
static int ufs_mtk_phy_clk_init(struct ufs_mtk_phy *phy)
{
struct device *dev = phy->dev;
struct clk_bulk_data *clks = phy->clks;
phy->unipro_clk = devm_clk_get(dev, "unipro");
if (IS_ERR(phy->unipro_clk)) {
dev_err(dev, "failed to get clock: unipro");
return PTR_ERR(phy->unipro_clk);
}
phy->mp_clk = devm_clk_get(dev, "mp");
if (IS_ERR(phy->mp_clk)) {
dev_err(dev, "failed to get clock: mp");
return PTR_ERR(phy->mp_clk);
}
return 0;
clks[0].id = "unipro";
clks[1].id = "mp";
return devm_clk_bulk_get(dev, UFSPHY_CLKS_CNT, clks);
}
static void ufs_mtk_phy_set_active(struct ufs_mtk_phy *phy)
@ -150,26 +142,13 @@ static int ufs_mtk_phy_power_on(struct phy *generic_phy)
struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy);
int ret;
ret = clk_prepare_enable(phy->unipro_clk);
if (ret) {
dev_err(phy->dev, "unipro_clk enable failed %d\n", ret);
goto out;
}
ret = clk_prepare_enable(phy->mp_clk);
if (ret) {
dev_err(phy->dev, "mp_clk enable failed %d\n", ret);
goto out_unprepare_unipro_clk;
}
ret = clk_bulk_prepare_enable(UFSPHY_CLKS_CNT, phy->clks);
if (ret)
return ret;
ufs_mtk_phy_set_active(phy);
return 0;
out_unprepare_unipro_clk:
clk_disable_unprepare(phy->unipro_clk);
out:
return ret;
}
static int ufs_mtk_phy_power_off(struct phy *generic_phy)
@ -178,8 +157,7 @@ static int ufs_mtk_phy_power_off(struct phy *generic_phy)
ufs_mtk_phy_set_deep_hibern(phy);
clk_disable_unprepare(phy->unipro_clk);
clk_disable_unprepare(phy->mp_clk);
clk_bulk_disable_unprepare(UFSPHY_CLKS_CNT, phy->clks);
return 0;
}

View File

@ -234,6 +234,11 @@ static const unsigned int sdm845_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_PCS_READY_STATUS] = 0x160,
};
static const unsigned int sm6115_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_START_CTRL] = 0x00,
[QPHY_PCS_READY_STATUS] = 0x168,
};
static const unsigned int sm8250_pcie_regs_layout[QPHY_LAYOUT_SIZE] = {
[QPHY_SW_RESET] = 0x00,
[QPHY_START_CTRL] = 0x44,
@ -1329,6 +1334,97 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60),
};
static const struct qmp_phy_init_tbl sm6115_ufsphy_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x0e),
QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30),
QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x02),
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x01),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x20),
QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x04),
QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05),
QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b),
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80),
QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x28),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x02),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xff),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE1, 0x98),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE1, 0x0b),
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE1, 0x16),
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE1, 0x28),
QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80),
QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE1, 0x32),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE1, 0x00),
QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_INITVAL1, 0xff),
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00),
/* Rate B */
QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x44),
};
static const struct qmp_phy_init_tbl sm6115_ufsphy_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45),
QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x06),
};
static const struct qmp_phy_init_tbl sm6115_ufsphy_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x24),
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x0F),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_INTERFACE_MODE, 0x40),
QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1E),
QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_TERM_BW, 0x5B),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xFF),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3F),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xFF),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x3F),
QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0D),
QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN_HALF, 0x04),
QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN, 0x04),
QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5B),
};
static const struct qmp_phy_init_tbl sm6115_ufsphy_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_RX_PWM_GEAR_BAND, 0x15),
QMP_PHY_INIT_CFG(QPHY_RX_SIGDET_CTRL2, 0x6d),
QMP_PHY_INIT_CFG(QPHY_TX_LARGE_AMP_DRV_LVL, 0x0f),
QMP_PHY_INIT_CFG(QPHY_TX_SMALL_AMP_DRV_LVL, 0x02),
QMP_PHY_INIT_CFG(QPHY_RX_MIN_STALL_NOCONFIG_TIME_CAP, 0x28),
QMP_PHY_INIT_CFG(QPHY_RX_SYM_RESYNC_CTRL, 0x03),
QMP_PHY_INIT_CFG(QPHY_TX_LARGE_AMP_POST_EMP_LVL, 0x12),
QMP_PHY_INIT_CFG(QPHY_TX_SMALL_AMP_POST_EMP_LVL, 0x0f),
QMP_PHY_INIT_CFG(QPHY_RX_MIN_HIBERN8_TIME, 0x9a), /* 8 us */
};
static const struct qmp_phy_init_tbl sdm845_ufsphy_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04),
@ -2035,6 +2131,113 @@ static const struct qmp_phy_init_tbl qmp_v4_dp_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_EMP_POST1_LVL, 0x20),
};
static const struct qmp_phy_init_tbl sc8180x_qmp_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x08),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x34),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE1, 0x08),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_IVCO, 0x0f),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x42),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE1_MODE0, 0x24),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE2_MODE1, 0x03),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE1_MODE1, 0xb4),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x11),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x82),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x03),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0x55),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE0, 0x55),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x1a),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE1, 0x68),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE1, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE1, 0xaa),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE1, 0xab),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE1, 0x34),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE1, 0x14),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x06),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x16),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x36),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE1, 0x06),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE1, 0x16),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE1, 0x36),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xca),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x18),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xa2),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_BUF_ENABLE, 0x07),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_EN_CENTER, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER1, 0x31),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER2, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0, 0xde),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0, 0x07),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1, 0x4c),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1, 0x06),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_ENABLE1, 0x90),
};
static const struct qmp_phy_init_tbl sc8180x_qmp_pcie_tx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_TX_RCV_DETECT_LVL_2, 0x12),
QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0x5),
};
static const struct qmp_phy_init_tbl sc8180x_qmp_pcie_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_CNTRL, 0x03),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_ENABLES, 0x1c),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL, 0x14),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL1, 0x07),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x6e),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x6e),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x4a),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_EN_TIMER, 0x04),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CONTROLS, 0x70),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL1, 0x54),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL2, 0x37),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_LOW, 0xd4),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH, 0x54),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH2, 0xdb),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH3, 0x39),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH4, 0x31),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0x24),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0xe4),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0xec),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH3, 0x39),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0x36),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_LOW, 0x7f),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH, 0xff),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0xff),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0xdb),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x75),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x00),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0xc0),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_AUX_DATA_TCOARSE_TFINE, 0xa0),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_RCLK_AUXDATA_SEL, 0xc0),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_DCC_CTRL1, 0x0c),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_GM_CAL, 0x05),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FO_GAIN, 0x0c),
QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_GAIN, 0x03),
};
static const struct qmp_phy_init_tbl sc8180x_qmp_pcie_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_RATE_SLEW_CNTRL1, 0x0b),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x0d),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG5, 0x01),
};
static const struct qmp_phy_init_tbl sc8180x_qmp_pcie_pcs_misc_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L, 0x01),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_INT_AUX_CLK_CONFIG1, 0x00),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_PRESET_P10_PRE, 0x00),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_PRESET_P10_POST, 0x58),
QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
};
static const struct qmp_phy_init_tbl sm8250_qmp_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x08),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x34),
@ -3289,6 +3492,31 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
.no_pcs_sw_reset = true,
};
static const struct qmp_phy_cfg sm6115_ufsphy_cfg = {
.type = PHY_TYPE_UFS,
.nlanes = 1,
.serdes_tbl = sm6115_ufsphy_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(sm6115_ufsphy_serdes_tbl),
.tx_tbl = sm6115_ufsphy_tx_tbl,
.tx_tbl_num = ARRAY_SIZE(sm6115_ufsphy_tx_tbl),
.rx_tbl = sm6115_ufsphy_rx_tbl,
.rx_tbl_num = ARRAY_SIZE(sm6115_ufsphy_rx_tbl),
.pcs_tbl = sm6115_ufsphy_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(sm6115_ufsphy_pcs_tbl),
.clk_list = sdm845_ufs_phy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = sm6115_ufsphy_regs_layout,
.start_ctrl = SERDES_START,
.pwrdn_ctrl = SW_PWRDN,
.is_dual_lane_phy = false,
.no_pcs_sw_reset = true,
};
static const struct qmp_phy_cfg msm8998_pciephy_cfg = {
.type = PHY_TYPE_PCIE,
.nlanes = 1,
@ -3399,6 +3627,76 @@ static const struct qmp_phy_cfg sm8150_usb3phy_cfg = {
.is_dual_lane_phy = true,
};
static const struct qmp_phy_cfg sc8180x_pciephy_cfg = {
.type = PHY_TYPE_PCIE,
.nlanes = 1,
.serdes_tbl = sc8180x_qmp_pcie_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(sm8250_qmp_pcie_serdes_tbl),
.tx_tbl = sc8180x_qmp_pcie_tx_tbl,
.tx_tbl_num = ARRAY_SIZE(sc8180x_qmp_pcie_tx_tbl),
.rx_tbl = sc8180x_qmp_pcie_rx_tbl,
.rx_tbl_num = ARRAY_SIZE(sc8180x_qmp_pcie_rx_tbl),
.pcs_tbl = sc8180x_qmp_pcie_pcs_tbl,
.pcs_tbl_num = ARRAY_SIZE(sc8180x_qmp_pcie_pcs_tbl),
.pcs_misc_tbl = sc8180x_qmp_pcie_pcs_misc_tbl,
.pcs_misc_tbl_num = ARRAY_SIZE(sc8180x_qmp_pcie_pcs_misc_tbl),
.clk_list = sdm845_pciephy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_pciephy_clk_l),
.reset_list = sdm845_pciephy_reset_l,
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = sm8250_pcie_regs_layout,
.start_ctrl = PCS_START | SERDES_START,
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.has_pwrdn_delay = true,
.pwrdn_delay_min = 995, /* us */
.pwrdn_delay_max = 1005, /* us */
};
static const struct qmp_phy_cfg sc8180x_dpphy_cfg = {
.type = PHY_TYPE_DP,
.nlanes = 1,
.serdes_tbl = qmp_v4_dp_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl),
.tx_tbl = qmp_v4_dp_tx_tbl,
.tx_tbl_num = ARRAY_SIZE(qmp_v4_dp_tx_tbl),
.serdes_tbl_rbr = qmp_v4_dp_serdes_tbl_rbr,
.serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_rbr),
.serdes_tbl_hbr = qmp_v4_dp_serdes_tbl_hbr,
.serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr),
.serdes_tbl_hbr2 = qmp_v4_dp_serdes_tbl_hbr2,
.serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr2),
.serdes_tbl_hbr3 = qmp_v4_dp_serdes_tbl_hbr3,
.serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr3),
.clk_list = qmp_v3_phy_clk_l,
.num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l),
.reset_list = sc7180_usb3phy_reset_l,
.num_resets = ARRAY_SIZE(sc7180_usb3phy_reset_l),
.vreg_list = qmp_phy_vreg_l,
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = qmp_v3_usb3phy_regs_layout,
.has_phy_dp_com_ctrl = true,
.is_dual_lane_phy = true,
.dp_aux_init = qcom_qmp_v4_phy_dp_aux_init,
.configure_dp_tx = qcom_qmp_v4_phy_configure_dp_tx,
.configure_dp_phy = qcom_qmp_v4_phy_configure_dp_phy,
.calibrate_dp_phy = qcom_qmp_v4_dp_phy_calibrate,
};
static const struct qmp_phy_combo_cfg sc8180x_usb3dpphy_cfg = {
.usb_cfg = &sm8150_usb3phy_cfg,
.dp_cfg = &sc8180x_dpphy_cfg,
};
static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = {
.type = PHY_TYPE_USB3,
.nlanes = 1,
@ -5018,6 +5316,7 @@ static int phy_dp_clks_register(struct qcom_qmp *qmp, struct qmp_phy *qphy,
{
struct clk_init_data init = { };
struct qmp_phy_dp_clks *dp_clks;
char name[64];
int ret;
dp_clks = devm_kzalloc(qmp->dev, sizeof(*dp_clks), GFP_KERNEL);
@ -5027,15 +5326,17 @@ static int phy_dp_clks_register(struct qcom_qmp *qmp, struct qmp_phy *qphy,
dp_clks->qphy = qphy;
qphy->dp_clks = dp_clks;
snprintf(name, sizeof(name), "%s::link_clk", dev_name(qmp->dev));
init.ops = &qcom_qmp_dp_link_clk_ops;
init.name = "qmp_dp_phy_pll_link_clk";
init.name = name;
dp_clks->dp_link_hw.init = &init;
ret = devm_clk_hw_register(qmp->dev, &dp_clks->dp_link_hw);
if (ret)
return ret;
snprintf(name, sizeof(name), "%s::vco_div_clk", dev_name(qmp->dev));
init.ops = &qcom_qmp_dp_pixel_clk_ops;
init.name = "qmp_dp_phy_pll_vco_div_clk";
init.name = name;
dp_clks->dp_pixel_hw.init = &init;
ret = devm_clk_hw_register(qmp->dev, &dp_clks->dp_pixel_hw);
if (ret)
@ -5225,18 +5526,27 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
}, {
.compatible = "qcom,ipq6018-qmp-pcie-phy",
.data = &ipq6018_pciephy_cfg,
}, {
.compatible = "qcom,ipq6018-qmp-usb3-phy",
.data = &ipq8074_usb3phy_cfg,
}, {
.compatible = "qcom,sc7180-qmp-usb3-phy",
.data = &sc7180_usb3phy_cfg,
}, {
.compatible = "qcom,sc7180-qmp-usb3-dp-phy",
/* It's a combo phy */
}, {
.compatible = "qcom,sc8180x-qmp-pcie-phy",
.data = &sc8180x_pciephy_cfg,
}, {
.compatible = "qcom,sc8180x-qmp-ufs-phy",
.data = &sm8150_ufsphy_cfg,
}, {
.compatible = "qcom,sc8180x-qmp-usb3-phy",
.data = &sm8150_usb3phy_cfg,
}, {
.compatible = "qcom,sc8180x-qmp-usb3-dp-phy",
/* It's a combo phy */
}, {
.compatible = "qcom,sdm845-qhp-pcie-phy",
.data = &sdm845_qhp_pciephy_cfg,
@ -5255,6 +5565,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
}, {
.compatible = "qcom,msm8998-qmp-usb3-phy",
.data = &msm8998_usb3phy_cfg,
}, {
.compatible = "qcom,sm6115-qmp-ufs-phy",
.data = &sm6115_ufsphy_cfg,
}, {
.compatible = "qcom,sm8150-qmp-ufs-phy",
.data = &sm8150_ufsphy_cfg,
@ -5314,6 +5627,10 @@ static const struct of_device_id qcom_qmp_combo_phy_of_match_table[] = {
.compatible = "qcom,sm8250-qmp-usb3-dp-phy",
.data = &sm8250_usb3dpphy_cfg,
},
{
.compatible = "qcom,sc8180x-qmp-usb3-dp-phy",
.data = &sc8180x_usb3dpphy_cfg,
},
{ }
};

View File

@ -191,6 +191,8 @@
#define QSERDES_COM_VCO_TUNE2_MODE0 0x130
#define QSERDES_COM_VCO_TUNE1_MODE1 0x134
#define QSERDES_COM_VCO_TUNE2_MODE1 0x138
#define QSERDES_COM_VCO_TUNE_INITVAL1 0x13c
#define QSERDES_COM_VCO_TUNE_INITVAL2 0x140
#define QSERDES_COM_VCO_TUNE_TIMER1 0x144
#define QSERDES_COM_VCO_TUNE_TIMER2 0x148
#define QSERDES_COM_BG_CTRL 0x170
@ -220,6 +222,10 @@
/* Only for QMP V2 PHY - RX registers */
#define QSERDES_RX_UCDR_SO_GAIN_HALF 0x010
#define QSERDES_RX_UCDR_SO_GAIN 0x01c
#define QSERDES_RX_UCDR_SVS_SO_GAIN_HALF 0x030
#define QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER 0x034
#define QSERDES_RX_UCDR_SVS_SO_GAIN_EIGHTH 0x038
#define QSERDES_RX_UCDR_SVS_SO_GAIN 0x03c
#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN 0x040
#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE 0x048
#define QSERDES_RX_RX_TERM_BW 0x090
@ -243,6 +249,10 @@
#define QPHY_POWER_DOWN_CONTROL 0x04
#define QPHY_TXDEEMPH_M6DB_V0 0x24
#define QPHY_TXDEEMPH_M3P5DB_V0 0x28
#define QPHY_TX_LARGE_AMP_DRV_LVL 0x34
#define QPHY_TX_LARGE_AMP_POST_EMP_LVL 0x38
#define QPHY_TX_SMALL_AMP_DRV_LVL 0x3c
#define QPHY_TX_SMALL_AMP_POST_EMP_LVL 0x40
#define QPHY_ENDPOINT_REFCLK_DRIVE 0x54
#define QPHY_RX_IDLE_DTCT_CNTRL 0x58
#define QPHY_POWER_STATE_CONFIG1 0x60
@ -253,6 +263,11 @@
#define QPHY_LOCK_DETECT_CONFIG3 0x88
#define QPHY_PWRUP_RESET_DLY_TIME_AUXCLK 0xa0
#define QPHY_LP_WAKEUP_DLY_TIME_AUXCLK 0xa4
#define QPHY_RX_MIN_STALL_NOCONFIG_TIME_CAP 0xcc
#define QPHY_RX_SYM_RESYNC_CTRL 0x13c
#define QPHY_RX_MIN_HIBERN8_TIME 0x140
#define QPHY_RX_SIGDET_CTRL2 0x148
#define QPHY_RX_PWM_GEAR_BAND 0x154
#define QPHY_PLL_LOCK_CHK_DLY_TIME_AUXCLK_LSB 0x1A8
#define QPHY_OSC_DTCT_ACTIONS 0x1AC
#define QPHY_RX_SIGDET_LVL 0x1D8
@ -280,6 +295,8 @@
#define QSERDES_V3_COM_SSC_PER2 0x020
#define QSERDES_V3_COM_SSC_STEP_SIZE1 0x024
#define QSERDES_V3_COM_SSC_STEP_SIZE2 0x028
#define QSERDES_V3_COM_POST_DIV 0x02c
#define QSERDES_V3_COM_POST_DIV_MUX 0x030
#define QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN 0x034
# define QSERDES_V3_COM_BIAS_EN 0x0001
# define QSERDES_V3_COM_BIAS_EN_MUX 0x0002
@ -291,6 +308,7 @@
#define QSERDES_V3_COM_CLK_ENABLE1 0x038
#define QSERDES_V3_COM_SYS_CLK_CTRL 0x03c
#define QSERDES_V3_COM_SYSCLK_BUF_ENABLE 0x040
#define QSERDES_V3_COM_PLL_EN 0x044
#define QSERDES_V3_COM_PLL_IVCO 0x048
#define QSERDES_V3_COM_LOCK_CMP1_MODE0 0x098
#define QSERDES_V3_COM_LOCK_CMP2_MODE0 0x09c

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
/*
* Copyright (C) 2016 Linaro Ltd
*/
#include <linux/module.h>

View File

@ -64,6 +64,7 @@
/* VBCTRL */
#define USB2_VBCTRL_OCCLREN BIT(16)
#define USB2_VBCTRL_DRVVBUSSEL BIT(8)
#define USB2_VBCTRL_VBOUT BIT(0)
/* LINECTRL1 */
#define USB2_LINECTRL1_DPRPD_EN BIT(19)
@ -78,6 +79,10 @@
#define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */
#define USB2_ADPCTRL_DRVVBUS BIT(4)
/* RZ/G2L specific */
#define USB2_OBINT_IDCHG_EN BIT(0)
#define USB2_LINECTRL1_USB2_IDMON BIT(0)
#define NUM_OF_PHYS 4
enum rcar_gen3_phy_index {
PHY_INDEX_BOTH_HC,
@ -112,9 +117,16 @@ struct rcar_gen3_chan {
struct mutex lock; /* protects rphys[...].powered */
enum usb_dr_mode dr_mode;
int irq;
u32 obint_enable_bits;
bool extcon_host;
bool is_otg_channel;
bool uses_otg_pins;
bool soc_no_adp_ctrl;
};
struct rcar_gen3_phy_drv_data {
const struct phy_ops *phy_usb2_ops;
bool no_adp_ctrl;
};
/*
@ -172,14 +184,22 @@ static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm)
static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus)
{
void __iomem *usb2_base = ch->base;
u32 val = readl(usb2_base + USB2_ADPCTRL);
u32 vbus_ctrl_reg = USB2_ADPCTRL;
u32 vbus_ctrl_val = USB2_ADPCTRL_DRVVBUS;
u32 val;
dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus);
if (ch->soc_no_adp_ctrl) {
vbus_ctrl_reg = USB2_VBCTRL;
vbus_ctrl_val = USB2_VBCTRL_VBOUT;
}
val = readl(usb2_base + vbus_ctrl_reg);
if (vbus)
val |= USB2_ADPCTRL_DRVVBUS;
val |= vbus_ctrl_val;
else
val &= ~USB2_ADPCTRL_DRVVBUS;
writel(val, usb2_base + USB2_ADPCTRL);
val &= ~vbus_ctrl_val;
writel(val, usb2_base + vbus_ctrl_reg);
}
static void rcar_gen3_control_otg_irq(struct rcar_gen3_chan *ch, int enable)
@ -188,9 +208,9 @@ static void rcar_gen3_control_otg_irq(struct rcar_gen3_chan *ch, int enable)
u32 val = readl(usb2_base + USB2_OBINTEN);
if (ch->uses_otg_pins && enable)
val |= USB2_OBINT_BITS;
val |= ch->obint_enable_bits;
else
val &= ~USB2_OBINT_BITS;
val &= ~ch->obint_enable_bits;
writel(val, usb2_base + USB2_OBINTEN);
}
@ -252,6 +272,9 @@ static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
if (!ch->uses_otg_pins)
return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true;
if (ch->soc_no_adp_ctrl)
return !!(readl(ch->base + USB2_LINECTRL1) & USB2_LINECTRL1_USB2_IDMON);
return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG);
}
@ -376,16 +399,17 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
USB2_LINECTRL1_DMRPD_EN | USB2_LINECTRL1_DM_RPD;
writel(val, usb2_base + USB2_LINECTRL1);
val = readl(usb2_base + USB2_VBCTRL);
val &= ~USB2_VBCTRL_OCCLREN;
writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL);
val = readl(usb2_base + USB2_ADPCTRL);
writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL);
if (!ch->soc_no_adp_ctrl) {
val = readl(usb2_base + USB2_VBCTRL);
val &= ~USB2_VBCTRL_OCCLREN;
writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL);
val = readl(usb2_base + USB2_ADPCTRL);
writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL);
}
msleep(20);
writel(0xffffffff, usb2_base + USB2_OBINTSTA);
writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTEN);
writel(ch->obint_enable_bits, usb2_base + USB2_OBINTEN);
rcar_gen3_device_recognition(ch);
}
@ -397,9 +421,9 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
u32 status = readl(usb2_base + USB2_OBINTSTA);
irqreturn_t ret = IRQ_NONE;
if (status & USB2_OBINT_BITS) {
if (status & ch->obint_enable_bits) {
dev_vdbg(ch->dev, "%s: %08x\n", __func__, status);
writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA);
writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA);
rcar_gen3_device_recognition(ch);
ret = IRQ_HANDLED;
}
@ -535,26 +559,45 @@ static const struct phy_ops rz_g1c_phy_usb2_ops = {
.owner = THIS_MODULE,
};
static const struct rcar_gen3_phy_drv_data rcar_gen3_phy_usb2_data = {
.phy_usb2_ops = &rcar_gen3_phy_usb2_ops,
.no_adp_ctrl = false,
};
static const struct rcar_gen3_phy_drv_data rz_g1c_phy_usb2_data = {
.phy_usb2_ops = &rz_g1c_phy_usb2_ops,
.no_adp_ctrl = false,
};
static const struct rcar_gen3_phy_drv_data rz_g2l_phy_usb2_data = {
.phy_usb2_ops = &rcar_gen3_phy_usb2_ops,
.no_adp_ctrl = true,
};
static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
{
.compatible = "renesas,usb2-phy-r8a77470",
.data = &rz_g1c_phy_usb2_ops,
.data = &rz_g1c_phy_usb2_data,
},
{
.compatible = "renesas,usb2-phy-r8a7795",
.data = &rcar_gen3_phy_usb2_ops,
.data = &rcar_gen3_phy_usb2_data,
},
{
.compatible = "renesas,usb2-phy-r8a7796",
.data = &rcar_gen3_phy_usb2_ops,
.data = &rcar_gen3_phy_usb2_data,
},
{
.compatible = "renesas,usb2-phy-r8a77965",
.data = &rcar_gen3_phy_usb2_ops,
.data = &rcar_gen3_phy_usb2_data,
},
{
.compatible = "renesas,rzg2l-usb2-phy",
.data = &rz_g2l_phy_usb2_data,
},
{
.compatible = "renesas,rcar-gen3-usb2-phy",
.data = &rcar_gen3_phy_usb2_ops,
.data = &rcar_gen3_phy_usb2_data,
},
{ /* sentinel */ },
};
@ -608,10 +651,10 @@ static enum usb_dr_mode rcar_gen3_get_dr_mode(struct device_node *np)
static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
{
const struct rcar_gen3_phy_drv_data *phy_data;
struct device *dev = &pdev->dev;
struct rcar_gen3_chan *channel;
struct phy_provider *provider;
const struct phy_ops *phy_usb2_ops;
int ret = 0, i;
if (!dev->of_node) {
@ -627,6 +670,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
if (IS_ERR(channel->base))
return PTR_ERR(channel->base);
channel->obint_enable_bits = USB2_OBINT_BITS;
/* get irq number here and request_irq for OTG in phy_init */
channel->irq = platform_get_irq_optional(pdev, 0);
channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node);
@ -653,16 +697,21 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
* And then, phy-core will manage runtime pm for this device.
*/
pm_runtime_enable(dev);
phy_usb2_ops = of_device_get_match_data(dev);
if (!phy_usb2_ops) {
phy_data = of_device_get_match_data(dev);
if (!phy_data) {
ret = -EINVAL;
goto error;
}
channel->soc_no_adp_ctrl = phy_data->no_adp_ctrl;
if (phy_data->no_adp_ctrl)
channel->obint_enable_bits = USB2_OBINT_IDCHG_EN;
mutex_init(&channel->lock);
for (i = 0; i < NUM_OF_PHYS; i++) {
channel->rphys[i].phy = devm_phy_create(dev, NULL,
phy_usb2_ops);
phy_data->phy_usb2_ops);
if (IS_ERR(channel->rphys[i].phy)) {
dev_err(dev, "Failed to create USB2 PHY\n");
ret = PTR_ERR(channel->rphys[i].phy);

View File

@ -1180,8 +1180,10 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
next_child:
/* to prevent out of boundary */
if (++index >= rphy->phy_cfg->num_ports)
if (++index >= rphy->phy_cfg->num_ports) {
of_node_put(child_np);
break;
}
}
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);

View File

@ -2,7 +2,10 @@
obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o
obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o
obj-$(CONFIG_PHY_EXYNOS_PCIE) += phy-exynos-pcie.o
obj-$(CONFIG_PHY_SAMSUNG_UFS) += phy-samsung-ufs.o
obj-$(CONFIG_PHY_SAMSUNG_UFS) += phy-exynos-ufs.o
phy-exynos-ufs-y += phy-samsung-ufs.o
phy-exynos-ufs-y += phy-exynos7-ufs.o
phy-exynos-ufs-y += phy-exynosautov9-ufs.o
obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o
phy-exynos-usb2-y += phy-samsung-usb2.o
phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o

View File

@ -1,11 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-only */
// SPDX-License-Identifier: GPL-2.0-only
/*
* UFS PHY driver data for Samsung EXYNOS7 SoC
*
* Copyright (C) 2020 Samsung Electronics Co., Ltd.
*/
#ifndef _PHY_EXYNOS7_UFS_H_
#define _PHY_EXYNOS7_UFS_H_
#include "phy-samsung-ufs.h"
@ -68,7 +66,7 @@ static const struct samsung_ufs_phy_cfg *exynos7_ufs_phy_cfgs[CFG_TAG_MAX] = {
[CFG_POST_PWR_HS] = exynos7_post_pwr_hs_cfg,
};
static struct samsung_ufs_phy_drvdata exynos7_ufs_phy = {
const struct samsung_ufs_phy_drvdata exynos7_ufs_phy = {
.cfg = exynos7_ufs_phy_cfgs,
.isol = {
.offset = EXYNOS7_EMBEDDED_COMBO_PHY_CTRL,
@ -77,5 +75,3 @@ static struct samsung_ufs_phy_drvdata exynos7_ufs_phy = {
},
.has_symbol_clk = 1,
};
#endif /* _PHY_EXYNOS7_UFS_H_ */

View File

@ -0,0 +1,67 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* UFS PHY driver data for Samsung EXYNOSAUTO v9 SoC
*
* Copyright (C) 2021 Samsung Electronics Co., Ltd.
*/
#include "phy-samsung-ufs.h"
#define EXYNOSAUTOV9_EMBEDDED_COMBO_PHY_CTRL 0x728
#define EXYNOSAUTOV9_EMBEDDED_COMBO_PHY_CTRL_MASK 0x1
#define EXYNOSAUTOV9_EMBEDDED_COMBO_PHY_CTRL_EN BIT(0)
#define PHY_TRSV_REG_CFG_AUTOV9(o, v, d) \
PHY_TRSV_REG_CFG_OFFSET(o, v, d, 0x50)
/* Calibration for phy initialization */
static const struct samsung_ufs_phy_cfg exynosautov9_pre_init_cfg[] = {
PHY_COMN_REG_CFG(0x023, 0x80, PWR_MODE_ANY),
PHY_COMN_REG_CFG(0x01d, 0x10, PWR_MODE_ANY),
PHY_TRSV_REG_CFG_AUTOV9(0x044, 0xb5, PWR_MODE_ANY),
PHY_TRSV_REG_CFG_AUTOV9(0x04d, 0x43, PWR_MODE_ANY),
PHY_TRSV_REG_CFG_AUTOV9(0x05b, 0x20, PWR_MODE_ANY),
PHY_TRSV_REG_CFG_AUTOV9(0x05e, 0xc0, PWR_MODE_ANY),
PHY_TRSV_REG_CFG_AUTOV9(0x038, 0x12, PWR_MODE_ANY),
PHY_TRSV_REG_CFG_AUTOV9(0x059, 0x58, PWR_MODE_ANY),
PHY_TRSV_REG_CFG_AUTOV9(0x06c, 0x18, PWR_MODE_ANY),
PHY_TRSV_REG_CFG_AUTOV9(0x06d, 0x02, PWR_MODE_ANY),
PHY_COMN_REG_CFG(0x023, 0xc0, PWR_MODE_ANY),
PHY_COMN_REG_CFG(0x023, 0x00, PWR_MODE_ANY),
PHY_TRSV_REG_CFG(0x042, 0x5d, PWR_MODE_ANY),
PHY_TRSV_REG_CFG(0x043, 0x80, PWR_MODE_ANY),
END_UFS_PHY_CFG,
};
/* Calibration for HS mode series A/B */
static const struct samsung_ufs_phy_cfg exynosautov9_pre_pwr_hs_cfg[] = {
PHY_TRSV_REG_CFG(0x032, 0xbc, PWR_MODE_HS_ANY),
PHY_TRSV_REG_CFG(0x03c, 0x7f, PWR_MODE_HS_ANY),
PHY_TRSV_REG_CFG(0x048, 0xc0, PWR_MODE_HS_ANY),
PHY_TRSV_REG_CFG(0x04a, 0x00, PWR_MODE_HS_G3_SER_B),
PHY_TRSV_REG_CFG(0x04b, 0x10, PWR_MODE_HS_G1_SER_B |
PWR_MODE_HS_G3_SER_B),
PHY_TRSV_REG_CFG(0x04d, 0x63, PWR_MODE_HS_G3_SER_B),
END_UFS_PHY_CFG,
};
static const struct samsung_ufs_phy_cfg *exynosautov9_ufs_phy_cfgs[CFG_TAG_MAX] = {
[CFG_PRE_INIT] = exynosautov9_pre_init_cfg,
[CFG_PRE_PWR_HS] = exynosautov9_pre_pwr_hs_cfg,
};
const struct samsung_ufs_phy_drvdata exynosautov9_ufs_phy = {
.cfg = exynosautov9_ufs_phy_cfgs,
.isol = {
.offset = EXYNOSAUTOV9_EMBEDDED_COMBO_PHY_CTRL,
.mask = EXYNOSAUTOV9_EMBEDDED_COMBO_PHY_CTRL_MASK,
.en = EXYNOSAUTOV9_EMBEDDED_COMBO_PHY_CTRL_EN,
},
.has_symbol_clk = 0,
};

View File

@ -347,6 +347,9 @@ static const struct of_device_id samsung_ufs_phy_match[] = {
{
.compatible = "samsung,exynos7-ufs-phy",
.data = &exynos7_ufs_phy,
}, {
.compatible = "samsung,exynosautov9-ufs-phy",
.data = &exynosautov9_ufs_phy,
},
{},
};

View File

@ -10,6 +10,9 @@
#ifndef _PHY_SAMSUNG_UFS_
#define _PHY_SAMSUNG_UFS_
#include <linux/phy/phy.h>
#include <linux/regmap.h>
#define PHY_COMN_BLK 1
#define PHY_TRSV_BLK 2
#define END_UFS_PHY_CFG { 0 }
@ -24,14 +27,17 @@
.id = PHY_COMN_BLK, \
}
#define PHY_TRSV_REG_CFG(o, v, d) { \
#define PHY_TRSV_REG_CFG_OFFSET(o, v, d, c) { \
.off_0 = PHY_APB_ADDR((o)), \
.off_1 = PHY_APB_ADDR((o) + PHY_TRSV_CH_OFFSET), \
.off_1 = PHY_APB_ADDR((o) + (c)), \
.val = (v), \
.desc = (d), \
.id = PHY_TRSV_BLK, \
}
#define PHY_TRSV_REG_CFG(o, v, d) \
PHY_TRSV_REG_CFG_OFFSET(o, v, d, PHY_TRSV_CH_OFFSET)
/* UFS PHY registers */
#define PHY_PLL_LOCK_STATUS 0x1e
#define PHY_CDR_LOCK_STATUS 0x5e
@ -134,6 +140,7 @@ static inline void samsung_ufs_phy_ctrl_isol(
phy->isol->mask, isol ? 0 : phy->isol->en);
}
#include "phy-exynos7-ufs.h"
extern const struct samsung_ufs_phy_drvdata exynos7_ufs_phy;
extern const struct samsung_ufs_phy_drvdata exynosautov9_ufs_phy;
#endif /* _PHY_SAMSUNG_UFS_ */

View File

@ -1273,7 +1273,7 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev)
return err;
}
static int tegra_xusb_padctl_suspend_noirq(struct device *dev)
static __maybe_unused int tegra_xusb_padctl_suspend_noirq(struct device *dev)
{
struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev);
@ -1283,7 +1283,7 @@ static int tegra_xusb_padctl_suspend_noirq(struct device *dev)
return 0;
}
static int tegra_xusb_padctl_resume_noirq(struct device *dev)
static __maybe_unused int tegra_xusb_padctl_resume_noirq(struct device *dev)
{
struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev);

View File

@ -162,6 +162,8 @@ struct twl4030_usb {
atomic_t connected;
bool vbus_supplied;
bool musb_mailbox_pending;
unsigned long runtime_suspended:1;
unsigned long needs_resume:1;
struct delayed_work id_workaround_work;
};
@ -384,6 +386,9 @@ static void __twl4030_phy_power(struct twl4030_usb *twl, int on)
WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
}
static int twl4030_usb_runtime_suspend(struct device *dev);
static int twl4030_usb_runtime_resume(struct device *dev);
static int __maybe_unused twl4030_usb_suspend(struct device *dev)
{
struct twl4030_usb *twl = dev_get_drvdata(dev);
@ -395,6 +400,10 @@ static int __maybe_unused twl4030_usb_suspend(struct device *dev)
*/
dev_dbg(twl->dev, "%s\n", __func__);
disable_irq(twl->irq);
if (!twl->runtime_suspended && !atomic_read(&twl->connected)) {
twl4030_usb_runtime_suspend(dev);
twl->needs_resume = 1;
}
return 0;
}
@ -405,9 +414,13 @@ static int __maybe_unused twl4030_usb_resume(struct device *dev)
dev_dbg(twl->dev, "%s\n", __func__);
enable_irq(twl->irq);
if (twl->needs_resume)
twl4030_usb_runtime_resume(dev);
/* check whether cable status changed */
twl4030_usb_irq(0, twl);
twl->runtime_suspended = 0;
return 0;
}
@ -422,6 +435,8 @@ static int __maybe_unused twl4030_usb_runtime_suspend(struct device *dev)
regulator_disable(twl->usb1v8);
regulator_disable(twl->usb3v1);
twl->runtime_suspended = 1;
return 0;
}

View File

@ -626,6 +626,9 @@ static int xpsgtr_phy_power_on(struct phy *phy)
struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy);
int ret = 0;
/* Skip initialization if not required. */
if (!xpsgtr_phy_init_required(gtr_phy))
return ret;
/*
* Wait for the PLL to lock. For DP, only wait on DP0 to avoid
* cumulating waits for both lanes. The user is expected to initialize