Commit 96e9df33 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

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

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
  ...
parents c446e40e 152a810e
* 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>;
};
# 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>;
};
# 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
......
......@@ -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"
......
......@@ -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
......
......@@ -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:
......
......@@ -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:
......
......@@ -16,6 +16,7 @@ properties:
compatible:
enum:
- samsung,exynos7-ufs-phy
- samsung,exynosautov9-ufs-phy
reg:
maxItems: 1
......
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";
};
# 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>;
};
......@@ -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);
......
......@@ -24,13 +24,15 @@
#include <linux/reset.h>
#include <linux/regmap.h>
#define REF_CLK_19_2MHz 19200000
#define REF_CLK_25MHz 25000000
#define REF_CLK_19_2MHZ 19200000
#define REF_CLK_25MHZ 25000000
#define REF_CLK_100MHZ 100000000
#define MAX_NUM_LANES 4
#define DEFAULT_MAX_BIT_RATE 8100 /* in Mbps */
#define NUM_SSC_MODE 3
#define NUM_REF_CLK 3
#define NUM_PHY_TYPE 6
#define POLL_TIMEOUT_US 5000
......@@ -49,6 +51,10 @@
#define TORRENT_PHY_PCS_COMMON_OFFSET(block_offset) \
(0xC000 << (block_offset))
#define TORRENT_PHY_PCS_LANE_CDB_OFFSET(ln, block_offset, reg_offset) \
((0xD000 << (block_offset)) + \
(((ln) << 8) << (reg_offset)))
#define TORRENT_PHY_PMA_COMMON_OFFSET(block_offset) \
(0xE000 << (block_offset))
......@@ -101,6 +107,7 @@
#define CMN_PLL0_FRACDIVH_M0 0x0092U
#define CMN_PLL0_HIGH_THR_M0 0x0093U
#define CMN_PLL0_DSM_DIAG_M0 0x0094U
#define CMN_PLL0_DSM_FBH_OVRD_M0 0x0095U
#define CMN_PLL0_SS_CTRL1_M0 0x0098U
#define CMN_PLL0_SS_CTRL2_M0 0x0099U
#define CMN_PLL0_SS_CTRL3_M0 0x009AU
......@@ -220,6 +227,9 @@
#define PHY_PIPE_USB3_GEN2_POST_CFG0 0x0022U
#define PHY_PIPE_USB3_GEN2_POST_CFG1 0x0023U
/* PHY PCS lane registers */
#define PHY_PCS_ISO_LINK_CTRL 0x000BU
/* PHY PMA common registers */
#define PHY_PMA_CMN_CTRL1 0x0000U
#define PHY_PMA_CMN_CTRL2 0x0001U
......@@ -244,6 +254,9 @@ static const struct reg_field phy_pma_pll_raw_ctrl =
static const struct reg_field phy_reset_ctrl =
REG_FIELD(PHY_RESET, 8, 8);
static const struct reg_field phy_pcs_iso_link_ctrl_1 =
REG_FIELD(PHY_PCS_ISO_LINK_CTRL, 1, 1);
static const struct reg_field phy_pipe_cmn_ctrl1_0 = REG_FIELD(PHY_PIPE_CMN_CTRL1, 0, 0);
#define REFCLK_OUT_NUM_CMN_CONFIG 5
......@@ -273,6 +286,12 @@ enum cdns_torrent_phy_type {
TYPE_USB,
};
enum cdns_torrent_ref_clk {
CLK_19_2_MHZ,
CLK_25_MHZ,
CLK_100_MHZ
};
enum cdns_torrent_ssc_mode {
NO_SSC,
EXTERNAL_SSC,
......@@ -296,7 +315,7 @@ struct cdns_torrent_phy {
struct reset_control *apb_rst;
struct device *dev;
struct clk *clk;
unsigned long ref_clk_rate;
enum cdns_torrent_ref_clk ref_clk_rate;
struct cdns_torrent_inst phys[MAX_NUM_LANES];
int nsubnodes;
const struct cdns_torrent_data *init_data;
......@@ -306,12 +325,14 @@ struct cdns_torrent_phy {
struct regmap *regmap_phy_pma_common_cdb;
struct regmap *regmap_tx_lane_cdb[MAX_NUM_LANES];
struct regmap *regmap_rx_lane_cdb[MAX_NUM_LANES];
struct regmap *regmap_phy_pcs_lane_cdb[MAX_NUM_LANES];
struct regmap *regmap_dptx_phy_reg;
struct regmap_field *phy_pll_cfg;
struct regmap_field *phy_pma_cmn_ctrl_1;
struct regmap_field *phy_pma_cmn_ctrl_2;
struct regmap_field *phy_pma_pll_raw_ctrl;
struct regmap_field *phy_reset_ctrl;
struct regmap_field *phy_pcs_iso_link_ctrl_1[MAX_NUM_LANES];
struct clk *clks[CDNS_TORRENT_REFCLK_DRIVER + 1];
struct clk_onecell_data clk_data;
};
......@@ -333,57 +354,6 @@ struct cdns_torrent_derived_refclk {
#define to_cdns_torrent_derived_refclk(_hw) \
container_of(_hw, struct cdns_torrent_derived_refclk, hw)
static int cdns_torrent_phy_init(struct phy *phy);
static int cdns_torrent_dp_init(struct phy *phy);
static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy,
u32 num_lanes);
static
int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy);
static void cdns_torrent_dp_pma_cfg(struct cdns_torrent_phy *cdns_phy,
struct cdns_torrent_inst *inst);
static
void cdns_torrent_dp_pma_cmn_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy);
static
void cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy,
u32 rate, bool ssc);
static
void cdns_torrent_dp_pma_cmn_cfg_25mhz(struct cdns_torrent_phy *cdns_phy);
static
void cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(struct cdns_torrent_phy *cdns_phy,
u32 rate, bool ssc);
static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy,
unsigned int lane);
static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy,
u32 rate, u32 num_lanes);
static int cdns_torrent_dp_configure(struct phy *phy,
union phy_configure_opts *opts);
static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy,
u32 num_lanes,
enum phy_powerstate powerstate);
static int cdns_torrent_phy_on(struct phy *phy);
static int cdns_torrent_phy_off(struct phy *phy);
static const struct phy_ops cdns_torrent_phy_ops = {
.init = cdns_torrent_phy_init,
.configure = cdns_torrent_dp_configure,
.power_on = cdns_torrent_phy_on,
.power_off = cdns_torrent_phy_off,
.owner = THIS_MODULE,
};
static int cdns_torrent_noop_phy_on(struct phy *phy)
{
/* Give 5ms to 10ms delay for the PIPE clock to be stable */
usleep_range(5000, 10000);
return 0;
}
static const struct phy_ops noop_ops = {
.power_on = cdns_torrent_noop_phy_on,
.owner = THIS_MODULE,
};
struct cdns_reg_pairs {
u32 val;
u32 off;
......@@ -403,12 +373,12 @@ struct cdns_torrent_data {
[NUM_SSC_MODE];
struct cdns_torrent_vals *pcs_cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE]
[NUM_SSC_MODE];
struct cdns_torrent_vals *cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE]
[NUM_SSC_MODE];
struct cdns_torrent_vals *tx_ln_vals[NUM_PHY_TYPE][NUM_PHY_TYPE]
[NUM_SSC_MODE];
struct cdns_torrent_vals *rx_ln_vals[NUM_PHY_TYPE][NUM_PHY_TYPE]
[NUM_SSC_MODE];
struct cdns_torrent_vals *cmn_vals[NUM_REF_CLK][NUM_PHY_TYPE]
[NUM_PHY_TYPE][NUM_SSC_MODE];
struct cdns_torrent_vals *tx_ln_vals[NUM_REF_CLK][NUM_PHY_TYPE]
[NUM_PHY_TYPE][NUM_SSC_MODE];
struct cdns_torrent_vals *rx_ln_vals[NUM_REF_CLK][NUM_PHY_TYPE]
[NUM_PHY_TYPE][NUM_SSC_MODE];
};
struct cdns_regmap_cdb_context {
......@@ -497,6 +467,22 @@ static const struct regmap_config cdns_torrent_common_cdb_config = {
.reg_read = cdns_regmap_read,
};
#define TORRENT_PHY_PCS_LANE_CDB_REGMAP_CONF(n) \
{ \
.name = "torrent_phy_pcs_lane" n "_cdb", \
.reg_stride = 1, \
.fast_io = true, \
.reg_write = cdns_regmap_write, \
.reg_read = cdns_regmap_read, \
}
static const struct regmap_config cdns_torrent_phy_pcs_lane_cdb_config[] = {
TORRENT_PHY_PCS_LANE_CDB_REGMAP_CONF("0"),
TORRENT_PHY_PCS_LANE_CDB_REGMAP_CONF("1"),
TORRENT_PHY_PCS_LANE_CDB_REGMAP_CONF("2"),
TORRENT_PHY_PCS_LANE_CDB_REGMAP_CONF("3"),
};
static const struct regmap_config cdns_torrent_phy_pcs_cmn_cdb_config = {
.name = "torrent_phy_pcs_cmn_cdb",
.reg_stride = 1,
......@@ -615,444 +601,500 @@ static const struct coefficients vltg_coeff[4][4] = {
}
};
/*
* Enable or disable PLL for selected lanes.
*/
static int cdns_torrent_dp_set_pll_en(struct cdns_torrent_phy *cdns_phy,
struct phy_configure_opts_dp *dp,
bool enable)
static const char *cdns_torrent_get_phy_type(enum cdns_torrent_phy_type phy_type)
{
u32 rd_val;
u32 ret;
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
/*
* Used to determine, which bits to check for or enable in
* PHY_PMA_XCVR_PLLCLK_EN register.
*/
u32 pll_bits;
/* Used to enable or disable lanes. */
u32 pll_val;
/* Select values of registers and mask, depending on enabled lane
* count.
*/
switch (dp->lanes) {
/* lane 0 */
case (1):
pll_bits = 0x00000001;
break;
/* lanes 0-1 */
case (2):
pll_bits = 0x00000003;
break;
/* lanes 0-3, all */
switch (phy_type) {
case TYPE_DP:
return "DisplayPort";
case TYPE_PCIE:
return "PCIe";
case TYPE_SGMII:
return "SGMII";
case TYPE_QSGMII:
return "QSGMII";
case TYPE_USB:
return "USB";
default:
pll_bits = 0x0000000F;
break;
return "None";
}
if (enable)
pll_val = pll_bits;
else
pll_val = 0x00000000;
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_val);
/* Wait for acknowledgment from PHY. */
ret = regmap_read_poll_timeout(regmap,
PHY_PMA_XCVR_PLLCLK_EN_ACK,
rd_val,
(rd_val & pll_bits) == pll_val,
0, POLL_TIMEOUT_US);
ndelay(100);
return ret;
}
/*
* Perform register operations related to setting link rate, once powerstate is
* set and PLL disable request was processed.
* Set registers responsible for enabling and configuring SSC, with second and
* third register values provided by parameters.
*/
static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy,
struct phy_configure_opts_dp *dp)
static
void cdns_torrent_dp_enable_ssc_19_2mhz(struct cdns_torrent_phy *cdns_phy,
u32 ctrl2_val, u32 ctrl3_val)
{
u32 ret;
u32 read_val;
/* Disable the cmn_pll0_en before re-programming the new data rate. */
regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x0);
/*
* Wait for PLL ready de-assertion.
* For PLL0 - PHY_PMA_CMN_CTRL2[2] == 1
*/
ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2,
read_val,
((read_val >> 2) & 0x01) != 0,
0, POLL_TIMEOUT_US);
if (ret)
return ret;
ndelay(200);
/* DP Rate Change - VCO Output settings. */
if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHz) {
/* PMA common configuration 19.2MHz */
cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, dp->link_rate,
dp->ssc);
cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy);
} else if (cdns_phy->ref_clk_rate == REF_CLK_25MHz) {
/* PMA common configuration 25MHz */
cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, dp->link_rate,
dp->ssc);
cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy);
}
cdns_torrent_dp_pma_cmn_rate(cdns_phy, dp->link_rate, dp->lanes);
/* Enable the cmn_pll0_en. */
regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x3);
struct regmap *regmap = cdns_phy->regmap_common_cdb;
/*
* Wait for PLL ready assertion.
* For PLL0 - PHY_PMA_CMN_CTRL2[0] == 1
*/
ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2,
read_val,
(read_val & 0x01) != 0,
0, POLL_TIMEOUT_US);
return ret;
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0001);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl2_val);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl3_val);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0003);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0001);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl2_val);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl3_val);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0003);
}
/*
* Verify, that parameters to configure PHY with are correct.
*/
static int cdns_torrent_dp_verify_config(struct cdns_torrent_inst *inst,
struct phy_configure_opts_dp *dp)
static
void cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy,
u32 rate, bool ssc)
{
u8 i;
struct regmap *regmap = cdns_phy->regmap_common_cdb;
/* If changing link rate was required, verify it's supported. */
if (dp->set_rate) {
switch (dp->link_rate) {
/* Assumes 19.2 MHz refclock */
switch (rate) {
/* Setting VCO for 10.8GHz */
case 2700:
case 5400:
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0119);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x4000);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x00BC);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0012);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0119);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x4000);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x00BC);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0012);
if (ssc)
cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x033A, 0x006A);
break;
/* Setting VCO for 9.72GHz */
case 1620:
case 2160:
case 2430:
case 2700:
case 3240:
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x01FA);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x4000);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0152);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x01FA);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x4000);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0152);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
if (ssc)
cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x05DD, 0x0069);
break;
/* Setting VCO for 8.64GHz */
case 2160:
case 4320:
case 5400:
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x01C2);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x012C);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x01C2);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x012C);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
if (ssc)
cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x0536, 0x0069);
break;
/* Setting VCO for 8.1GHz */
case 8100:
/* valid bit rate */
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x01A5);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0xE000);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x011A);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x01A5);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0xE000);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x011A);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
if (ssc)
cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x04D7, 0x006A);
break;
default:
return -EINVAL;
}
}
/* Verify lane count. */
switch (dp->lanes) {
case 1:
case 2:
case 4:
/* valid lane count. */
break;
default:
return -EINVAL;
if (ssc) {
cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_PLLCNT_START, 0x025E);
cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_PLLCNT_THR, 0x0005);
cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_PLLCNT_START, 0x025E);
cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_THR, 0x0005);
} else {
cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_PLLCNT_START, 0x0260);
cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_PLLCNT_START, 0x0260);
/* Set reset register values to disable SSC */
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL2_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL3_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_PLLCNT_THR, 0x0003);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL2_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL3_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_THR, 0x0003);
}
/* Check against actual number of PHY's lanes. */
if (dp->lanes > inst->num_lanes)
return -EINVAL;
cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_REFCNT_START, 0x0099);
cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_PLLCNT_START, 0x0099);
cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_REFCNT_START, 0x0099);
cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_START, 0x0099);
}
/*
* If changing voltages is required, check swing and pre-emphasis
* levels, per-lane.
/*
* Set registers responsible for enabling and configuring SSC, with second
* register value provided by a parameter.
*/
if (dp->set_voltages) {
/* Lane count verified previously. */
for (i = 0; i < dp->lanes; i++) {
if (dp->voltage[i] > 3 || dp->pre[i] > 3)
return -EINVAL;
static void cdns_torrent_dp_enable_ssc_25mhz(struct cdns_torrent_phy *cdns_phy,
u32 ctrl2_val)
{
struct regmap *regmap = cdns_phy->regmap_common_cdb;
/* Sum of voltage swing and pre-emphasis levels cannot
* exceed 3.
*/
if (dp->voltage[i] + dp->pre[i] > 3)
return -EINVAL;
}
}
return 0;
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0001);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl2_val);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x007F);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0003);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0001);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl2_val);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x007F);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0003);
}
/* Set power state A0 and PLL clock enable to 0 on enabled lanes. */
static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy,
u32 num_lanes)
static
void cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(struct cdns_torrent_phy *cdns_phy,
u32 rate, bool ssc)
{
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
u32 pwr_state = cdns_torrent_dp_read(regmap,
PHY_PMA_XCVR_POWER_STATE_REQ);
u32 pll_clk_en = cdns_torrent_dp_read(regmap,
PHY_PMA_XCVR_PLLCLK_EN);
/* Lane 0 is always enabled. */
pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
PHY_POWER_STATE_LN_0);
pll_clk_en &= ~0x01U;
struct regmap *regmap = cdns_phy->regmap_common_cdb;
if (num_lanes > 1) {
/* lane 1 */
pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
PHY_POWER_STATE_LN_1);
pll_clk_en &= ~(0x01U << 1);
/* Assumes 25 MHz refclock */
switch (rate) {
/* Setting VCO for 10.8GHz */
case 2700:
case 5400:
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x01B0);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0120);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x01B0);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0120);
if (ssc)
cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x0423);
break;
/* Setting VCO for 9.72GHz */
case 1620:
case 2430:
case 3240:
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0184);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0xCCCD);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0104);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0184);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0xCCCD);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0104);
if (ssc)
cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x03B9);
break;
/* Setting VCO for 8.64GHz */
case 2160:
case 4320:
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0159);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x999A);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x00E7);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0159);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x999A);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x00E7);
if (ssc)
cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x034F);
break;
/* Setting VCO for 8.1GHz */
case 8100:
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0144);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x00D8);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0144);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x00D8);
if (ssc)
cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x031A);
break;
}
if (num_lanes > 2) {
/* lanes 2 and 3 */
pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
PHY_POWER_STATE_LN_2);
pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
PHY_POWER_STATE_LN_3);
pll_clk_en &= ~(0x01U << 2);
pll_clk_en &= ~(0x01U << 3);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
if (ssc) {
cdns_torrent_phy_write(regmap,
CMN_PLL0_VCOCAL_PLLCNT_START, 0x0315);
cdns_torrent_phy_write(regmap,
CMN_PLL0_LOCK_PLLCNT_THR, 0x0005);
cdns_torrent_phy_write(regmap,
CMN_PLL1_VCOCAL_PLLCNT_START, 0x0315);
cdns_torrent_phy_write(regmap,
CMN_PLL1_LOCK_PLLCNT_THR, 0x0005);
} else {
cdns_torrent_phy_write(regmap,
CMN_PLL0_VCOCAL_PLLCNT_START, 0x0317);
cdns_torrent_phy_write(regmap,
CMN_PLL1_VCOCAL_PLLCNT_START, 0x0317);
/* Set reset register values to disable SSC */
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL2_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL3_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0000);
cdns_torrent_phy_write(regmap,
CMN_PLL0_LOCK_PLLCNT_THR, 0x0003);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL2_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL3_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0000);
cdns_torrent_phy_write(regmap,
CMN_PLL1_LOCK_PLLCNT_THR, 0x0003);
}
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, pwr_state);
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_clk_en);
cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_REFCNT_START, 0x00C7);
cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_PLLCNT_START, 0x00C7);
cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_REFCNT_START, 0x00C7);
cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_START, 0x00C7);
}
/* Configure lane count as required. */
static int cdns_torrent_dp_set_lanes(struct cdns_torrent_phy *cdns_phy,
struct phy_configure_opts_dp *dp)
static
void cdns_torrent_dp_pma_cmn_vco_cfg_100mhz(struct cdns_torrent_phy *cdns_phy,
u32 rate, bool ssc)
{
u32 value;
u32 ret;
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
u8 lane_mask = (1 << dp->lanes) - 1;
struct regmap *regmap = cdns_phy->regmap_common_cdb;
value = cdns_torrent_dp_read(regmap, PHY_RESET);
/* clear pma_tx_elec_idle_ln_* bits. */
value &= ~PMA_TX_ELEC_IDLE_MASK;
/* Assert pma_tx_elec_idle_ln_* for disabled lanes. */
value |= ((~lane_mask) << PMA_TX_ELEC_IDLE_SHIFT) &
PMA_TX_ELEC_IDLE_MASK;
cdns_torrent_dp_write(regmap, PHY_RESET, value);
/* Assumes 100 MHz refclock */
switch (rate) {
/* Setting VCO for 10.8GHz */
case 2700:
case 5400:
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0028);
cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_FBH_OVRD_M0, 0x0022);
cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_FBH_OVRD_M0, 0x0022);
cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_FBL_OVRD_M0, 0x000C);
break;
/* Setting VCO for 9.72GHz */
case 1620:
case 2430:
case 3240:
cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0061);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0061);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x3333);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x3333);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0042);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0042);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
break;
/* Setting VCO for 8.64GHz */
case 2160:
case 4320:
cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0056);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0056);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x6666);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x6666);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x003A);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x003A);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
break;
/* Setting VCO for 8.1GHz */
case 8100:
cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0051);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0051);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0036);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0036);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
break;
}
}
/* reset the link by asserting phy_l00_reset_n low */
cdns_torrent_dp_write(regmap, PHY_RESET,
value & (~PHY_L00_RESET_N_MASK));
/*
* Enable or disable PLL for selected lanes.
*/
static int cdns_torrent_dp_set_pll_en(struct cdns_torrent_phy *cdns_phy,
struct phy_configure_opts_dp *dp,
bool enable)
{
u32 rd_val;
u32 ret;
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
/*
* Assert lane reset on unused lanes and lane 0 so they remain in reset
* and powered down when re-enabling the link
* Used to determine, which bits to check for or enable in
* PHY_PMA_XCVR_PLLCLK_EN register.
*/
value = (value & 0x0000FFF0) | (0x0000000E & lane_mask);
cdns_torrent_dp_write(regmap, PHY_RESET, value);
u32 pll_bits;
/* Used to enable or disable lanes. */
u32 pll_val;
cdns_torrent_dp_set_a0_pll(cdns_phy, dp->lanes);
/* Select values of registers and mask, depending on enabled lane
* count.
*/
switch (dp->lanes) {
/* lane 0 */
case (1):
pll_bits = 0x00000001;
break;
/* lanes 0-1 */
case (2):
pll_bits = 0x00000003;
break;
/* lanes 0-3, all */
default:
pll_bits = 0x0000000F;
break;
}
/* release phy_l0*_reset_n based on used laneCount */
value = (value & 0x0000FFF0) | (0x0000000F & lane_mask);
cdns_torrent_dp_write(regmap, PHY_RESET, value);
if (enable)
pll_val = pll_bits;
else
pll_val = 0x00000000;
/* Wait, until PHY gets ready after releasing PHY reset signal. */
ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy);
if (ret)
return ret;
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_val);
/* Wait for acknowledgment from PHY. */
ret = regmap_read_poll_timeout(regmap,
PHY_PMA_XCVR_PLLCLK_EN_ACK,
rd_val,
(rd_val & pll_bits) == pll_val,
0, POLL_TIMEOUT_US);
ndelay(100);
/* release pma_xcvr_pllclk_en_ln_*, only for the master lane */
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001);
ret = cdns_torrent_dp_run(cdns_phy, dp->lanes);
return ret;
}
/* Configure link rate as required. */
static int cdns_torrent_dp_set_rate(struct cdns_torrent_phy *cdns_phy,
struct phy_configure_opts_dp *dp)
static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy,
u32 num_lanes,
enum phy_powerstate powerstate)
{
/* Register value for power state for a single byte. */
u32 value_part;
u32 value;
u32 mask;
u32 read_val;
u32 ret;
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes,
POWERSTATE_A3);
if (ret)
return ret;
ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, false);
if (ret)
return ret;
ndelay(200);
ret = cdns_torrent_dp_configure_rate(cdns_phy, dp);
if (ret)
return ret;
ndelay(200);
ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, true);
if (ret)
return ret;
ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes,
POWERSTATE_A2);
if (ret)
return ret;
ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes,
POWERSTATE_A0);
if (ret)
return ret;
ndelay(900);
return ret;
}
/* Configure voltage swing and pre-emphasis for all enabled lanes. */
static void cdns_torrent_dp_set_voltages(struct cdns_torrent_phy *cdns_phy,
struct phy_configure_opts_dp *dp)
{
u8 lane;
u16 val;
for (lane = 0; lane < dp->lanes; lane++) {
val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane],
TX_DIAG_ACYA);
/*
* Write 1 to register bit TX_DIAG_ACYA[0] to freeze the
* current state of the analog TX driver.
*/
val |= TX_DIAG_ACYA_HBDC_MASK;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_DIAG_ACYA, val);
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_TXCC_CTRL, 0x08A4);
val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].diag_tx_drv;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
DRV_DIAG_TX_DRV, val);
val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].mgnfs_mult;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_TXCC_MGNFS_MULT_000,
val);
val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].cpost_mult;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_TXCC_CPOST_MULT_00,
val);
val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane],
TX_DIAG_ACYA);
/*
* Write 0 to register bit TX_DIAG_ACYA[0] to allow the state of
* analog TX driver to reflect the new programmed one.
*/
val &= ~TX_DIAG_ACYA_HBDC_MASK;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_DIAG_ACYA, val);
}
};
static int cdns_torrent_dp_configure(struct phy *phy,
union phy_configure_opts *opts)
{
struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
int ret;
ret = cdns_torrent_dp_verify_config(inst, &opts->dp);
if (ret) {
dev_err(&phy->dev, "invalid params for phy configure\n");
return ret;
}
if (opts->dp.set_lanes) {
ret = cdns_torrent_dp_set_lanes(cdns_phy, &opts->dp);
if (ret) {
dev_err(&phy->dev, "cdns_torrent_dp_set_lanes failed\n");
return ret;
}
switch (powerstate) {
case (POWERSTATE_A0):
value_part = 0x01U;
break;
case (POWERSTATE_A2):
value_part = 0x04U;
break;
default:
/* Powerstate A3 */
value_part = 0x08U;
break;
}
if (opts->dp.set_rate) {
ret = cdns_torrent_dp_set_rate(cdns_phy, &opts->dp);
if (ret) {
dev_err(&phy->dev, "cdns_torrent_dp_set_rate failed\n");
return ret;
}
/* Select values of registers and mask, depending on enabled
* lane count.
*/
switch (num_lanes) {
/* lane 0 */
case (1):
value = value_part;
mask = 0x0000003FU;
break;
/* lanes 0-1 */
case (2):
value = (value_part
| (value_part << 8));
mask = 0x00003F3FU;
break;
/* lanes 0-3, all */
default:
value = (value_part
| (value_part << 8)
| (value_part << 16)
| (value_part << 24));
mask = 0x3F3F3F3FU;
break;
}
if (opts->dp.set_voltages)
cdns_torrent_dp_set_voltages(cdns_phy, &opts->dp);
/* Set power state A<n>. */
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, value);
/* Wait, until PHY acknowledges power state completion. */
ret = regmap_read_poll_timeout(regmap, PHY_PMA_XCVR_POWER_STATE_ACK,
read_val, (read_val & mask) == value, 0,
POLL_TIMEOUT_US);
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, 0x00000000);
ndelay(100);
return ret;
}
static int cdns_torrent_dp_init(struct phy *phy)
static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, u32 num_lanes)
{
unsigned char lane_bits;
unsigned int read_val;
int ret;
struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
switch (cdns_phy->ref_clk_rate) {
case REF_CLK_19_2MHz:
case REF_CLK_25MHz:
/* Valid Ref Clock Rate */
break;
default:
dev_err(cdns_phy->dev, "Unsupported Ref Clock Rate\n");
return -EINVAL;
}
cdns_torrent_dp_write(regmap, PHY_AUX_CTRL, 0x0003); /* enable AUX */
/* PHY PMA registers configuration function */
cdns_torrent_dp_pma_cfg(cdns_phy, inst);
/*
* Set lines power state to A0
* Set lines pll clk enable to 0
*/
cdns_torrent_dp_set_a0_pll(cdns_phy, inst->num_lanes);
/*
* release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on
* used lanes
* waiting for ACK of pma_xcvr_pllclk_en_ln_*, only for the
* master lane
*/
lane_bits = (1 << inst->num_lanes) - 1;
cdns_torrent_dp_write(regmap, PHY_RESET,
((0xF & ~lane_bits) << 4) | (0xF & lane_bits));
/* release pma_xcvr_pllclk_en_ln_*, only for the master lane */
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001);
/* PHY PMA registers configuration functions */
/* Initialize PHY with max supported link rate, without SSC. */
if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHz)
cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy,
cdns_phy->max_bit_rate,
false);
else if (cdns_phy->ref_clk_rate == REF_CLK_25MHz)
cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy,
cdns_phy->max_bit_rate,
false);
cdns_torrent_dp_pma_cmn_rate(cdns_phy, cdns_phy->max_bit_rate,
inst->num_lanes);
/* take out of reset */
regmap_field_write(cdns_phy->phy_reset_ctrl, 0x1);
ret = regmap_read_poll_timeout(regmap, PHY_PMA_XCVR_PLLCLK_EN_ACK,
read_val, read_val & 1,
0, POLL_TIMEOUT_US);
if (ret == -ETIMEDOUT) {
dev_err(cdns_phy->dev,
"timeout waiting for link PLL clock enable ack\n");
return ret;
}
cdns_torrent_phy_on(phy);
ndelay(100);
ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy);
ret = cdns_torrent_dp_set_power_state(cdns_phy, num_lanes,
POWERSTATE_A2);
if (ret)
return ret;
ret = cdns_torrent_dp_run(cdns_phy, inst->num_lanes);
ret = cdns_torrent_dp_set_power_state(cdns_phy, num_lanes,
POWERSTATE_A0);
return ret;
}
static
int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy)
static int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy)
{
unsigned int reg;
int ret;
......@@ -1069,599 +1111,508 @@ int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy)
return 0;
}
static void cdns_torrent_dp_pma_cfg(struct cdns_torrent_phy *cdns_phy,
struct cdns_torrent_inst *inst)
static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy,
u32 rate, u32 num_lanes)
{
unsigned int clk_sel_val = 0;
unsigned int hsclk_div_val = 0;
unsigned int i;
if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHz)
/* PMA common configuration 19.2MHz */
cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy);
else if (cdns_phy->ref_clk_rate == REF_CLK_25MHz)
/* PMA common configuration 25MHz */
cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy);
/* PMA lane configuration to deal with multi-link operation */
for (i = 0; i < inst->num_lanes; i++)
cdns_torrent_dp_pma_lane_cfg(cdns_phy, i);
}
static
void cdns_torrent_dp_pma_cmn_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy)
{
struct regmap *regmap = cdns_phy->regmap_common_cdb;
/* refclock registers - assumes 19.2 MHz refclock */
cdns_torrent_phy_write(regmap, CMN_SSM_BIAS_TMR, 0x0014);
cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLPRE_TMR, 0x0027);
cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLLOCK_TMR, 0x00A1);
cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLPRE_TMR, 0x0027);
cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLLOCK_TMR, 0x00A1);
cdns_torrent_phy_write(regmap, CMN_BGCAL_INIT_TMR, 0x0060);
cdns_torrent_phy_write(regmap, CMN_BGCAL_ITER_TMR, 0x0060);
cdns_torrent_phy_write(regmap, CMN_IBCAL_INIT_TMR, 0x0014);
cdns_torrent_phy_write(regmap, CMN_TXPUCAL_INIT_TMR, 0x0018);
cdns_torrent_phy_write(regmap, CMN_TXPUCAL_ITER_TMR, 0x0005);
cdns_torrent_phy_write(regmap, CMN_TXPDCAL_INIT_TMR, 0x0018);
cdns_torrent_phy_write(regmap, CMN_TXPDCAL_ITER_TMR, 0x0005);
cdns_torrent_phy_write(regmap, CMN_RXCAL_INIT_TMR, 0x0240);
cdns_torrent_phy_write(regmap, CMN_RXCAL_ITER_TMR, 0x0005);
cdns_torrent_phy_write(regmap, CMN_SD_CAL_INIT_TMR, 0x0002);
cdns_torrent_phy_write(regmap, CMN_SD_CAL_ITER_TMR, 0x0002);
cdns_torrent_phy_write(regmap, CMN_SD_CAL_REFTIM_START, 0x000B);
cdns_torrent_phy_write(regmap, CMN_SD_CAL_PLLCNT_START, 0x0137);
/* PLL registers */
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_INIT_TMR, 0x00C0);
cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_ITER_TMR, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_INIT_TMR, 0x00C0);
cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_ITER_TMR, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_REFTIM_START, 0x0260);
cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_TCTRL, 0x0003);
cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_REFTIM_START, 0x0260);
cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_TCTRL, 0x0003);
}
/*
* Set registers responsible for enabling and configuring SSC, with second and
* third register values provided by parameters.
*/
static
void cdns_torrent_dp_enable_ssc_19_2mhz(struct cdns_torrent_phy *cdns_phy,
u32 ctrl2_val, u32 ctrl3_val)
{
struct regmap *regmap = cdns_phy->regmap_common_cdb;
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0001);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl2_val);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl3_val);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0003);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0001);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl2_val);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl3_val);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0003);
}
static
void cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy,
u32 rate, bool ssc)
{
struct regmap *regmap = cdns_phy->regmap_common_cdb;
/* Assumes 19.2 MHz refclock */
switch (rate) {
/* Setting VCO for 10.8GHz */
case 2700:
case 5400:
cdns_torrent_phy_write(regmap,
CMN_PLL0_INTDIV_M0, 0x0119);
cdns_torrent_phy_write(regmap,
CMN_PLL0_FRACDIVL_M0, 0x4000);
cdns_torrent_phy_write(regmap,
CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap,
CMN_PLL0_HIGH_THR_M0, 0x00BC);
cdns_torrent_phy_write(regmap,
CMN_PDIAG_PLL0_CTRL_M0, 0x0012);
cdns_torrent_phy_write(regmap,
CMN_PLL1_INTDIV_M0, 0x0119);
cdns_torrent_phy_write(regmap,
CMN_PLL1_FRACDIVL_M0, 0x4000);
cdns_torrent_phy_write(regmap,
CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap,
CMN_PLL1_HIGH_THR_M0, 0x00BC);
cdns_torrent_phy_write(regmap,
CMN_PDIAG_PLL1_CTRL_M0, 0x0012);
if (ssc)
cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x033A,
0x006A);
break;
/* Setting VCO for 9.72GHz */
case 1620:
clk_sel_val = 0x0f01;
hsclk_div_val = 2;
break;
case 2160:
case 2430:
case 2700:
clk_sel_val = 0x0701;
hsclk_div_val = 1;
break;
case 3240:
cdns_torrent_phy_write(regmap,
CMN_PLL0_INTDIV_M0, 0x01FA);
cdns_torrent_phy_write(regmap,
CMN_PLL0_FRACDIVL_M0, 0x4000);
cdns_torrent_phy_write(regmap,
CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap,
CMN_PLL0_HIGH_THR_M0, 0x0152);
cdns_torrent_phy_write(regmap,
CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
cdns_torrent_phy_write(regmap,
CMN_PLL1_INTDIV_M0, 0x01FA);
cdns_torrent_phy_write(regmap,
CMN_PLL1_FRACDIVL_M0, 0x4000);
cdns_torrent_phy_write(regmap,
CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap,
CMN_PLL1_HIGH_THR_M0, 0x0152);
cdns_torrent_phy_write(regmap,
CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
if (ssc)
cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x05DD,
0x0069);
clk_sel_val = 0x0b00;
hsclk_div_val = 2;
break;
/* Setting VCO for 8.64GHz */
case 2160:
case 4320:
cdns_torrent_phy_write(regmap,
CMN_PLL0_INTDIV_M0, 0x01C2);
cdns_torrent_phy_write(regmap,
CMN_PLL0_FRACDIVL_M0, 0x0000);
cdns_torrent_phy_write(regmap,
CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap,
CMN_PLL0_HIGH_THR_M0, 0x012C);
cdns_torrent_phy_write(regmap,
CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
cdns_torrent_phy_write(regmap,
CMN_PLL1_INTDIV_M0, 0x01C2);
cdns_torrent_phy_write(regmap,
CMN_PLL1_FRACDIVL_M0, 0x0000);
cdns_torrent_phy_write(regmap,
CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap,
CMN_PLL1_HIGH_THR_M0, 0x012C);
cdns_torrent_phy_write(regmap,
CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
if (ssc)
cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x0536,
0x0069);
case 5400:
clk_sel_val = 0x0301;
hsclk_div_val = 0;
break;
/* Setting VCO for 8.1GHz */
case 8100:
cdns_torrent_phy_write(regmap,
CMN_PLL0_INTDIV_M0, 0x01A5);
cdns_torrent_phy_write(regmap,
CMN_PLL0_FRACDIVL_M0, 0xE000);
cdns_torrent_phy_write(regmap,
CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap,
CMN_PLL0_HIGH_THR_M0, 0x011A);
cdns_torrent_phy_write(regmap,
CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
cdns_torrent_phy_write(regmap,
CMN_PLL1_INTDIV_M0, 0x01A5);
cdns_torrent_phy_write(regmap,
CMN_PLL1_FRACDIVL_M0, 0xE000);
cdns_torrent_phy_write(regmap,
CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap,
CMN_PLL1_HIGH_THR_M0, 0x011A);
cdns_torrent_phy_write(regmap,
CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
if (ssc)
cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x04D7,
0x006A);
clk_sel_val = 0x0200;
hsclk_div_val = 0;
break;
}
if (ssc) {
cdns_torrent_phy_write(regmap,
CMN_PLL0_VCOCAL_PLLCNT_START, 0x025E);
cdns_torrent_phy_write(regmap,
CMN_PLL0_LOCK_PLLCNT_THR, 0x0005);
cdns_torrent_phy_write(regmap,
CMN_PLL1_VCOCAL_PLLCNT_START, 0x025E);
cdns_torrent_phy_write(regmap,
CMN_PLL1_LOCK_PLLCNT_THR, 0x0005);
} else {
cdns_torrent_phy_write(regmap,
CMN_PLL0_VCOCAL_PLLCNT_START, 0x0260);
cdns_torrent_phy_write(regmap,
CMN_PLL1_VCOCAL_PLLCNT_START, 0x0260);
/* Set reset register values to disable SSC */
cdns_torrent_phy_write(regmap,
CMN_PLL0_SS_CTRL1_M0, 0x0002);
cdns_torrent_phy_write(regmap,
CMN_PLL0_SS_CTRL2_M0, 0x0000);
cdns_torrent_phy_write(regmap,
CMN_PLL0_SS_CTRL3_M0, 0x0000);
cdns_torrent_phy_write(regmap,
CMN_PLL0_SS_CTRL4_M0, 0x0000);
cdns_torrent_phy_write(regmap,
CMN_PLL0_LOCK_PLLCNT_THR, 0x0003);
cdns_torrent_phy_write(regmap,
CMN_PLL1_SS_CTRL1_M0, 0x0002);
cdns_torrent_phy_write(regmap,
CMN_PLL1_SS_CTRL2_M0, 0x0000);
cdns_torrent_phy_write(regmap,
CMN_PLL1_SS_CTRL3_M0, 0x0000);
cdns_torrent_phy_write(regmap,
CMN_PLL1_SS_CTRL4_M0, 0x0000);
cdns_torrent_phy_write(regmap,
CMN_PLL1_LOCK_PLLCNT_THR, 0x0003);
}
cdns_torrent_phy_write(cdns_phy->regmap_common_cdb,
CMN_PDIAG_PLL0_CLK_SEL_M0, clk_sel_val);
cdns_torrent_phy_write(cdns_phy->regmap_common_cdb,
CMN_PDIAG_PLL1_CLK_SEL_M0, clk_sel_val);
cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_REFCNT_START, 0x0099);
cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_PLLCNT_START, 0x0099);
cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_REFCNT_START, 0x0099);
cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_START, 0x0099);
/* PMA lane configuration to deal with multi-link operation */
for (i = 0; i < num_lanes; i++)
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[i],
XCVR_DIAG_HSCLK_DIV, hsclk_div_val);
}
static
void cdns_torrent_dp_pma_cmn_cfg_25mhz(struct cdns_torrent_phy *cdns_phy)
/*
* Perform register operations related to setting link rate, once powerstate is
* set and PLL disable request was processed.
*/
static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy,
struct phy_configure_opts_dp *dp)
{
struct regmap *regmap = cdns_phy->regmap_common_cdb;
u32 read_val, ret;
/* refclock registers - assumes 25 MHz refclock */
cdns_torrent_phy_write(regmap, CMN_SSM_BIAS_TMR, 0x0019);
cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLPRE_TMR, 0x0032);
cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLLOCK_TMR, 0x00D1);
cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLPRE_TMR, 0x0032);
cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLLOCK_TMR, 0x00D1);
cdns_torrent_phy_write(regmap, CMN_BGCAL_INIT_TMR, 0x007D);
cdns_torrent_phy_write(regmap, CMN_BGCAL_ITER_TMR, 0x007D);
cdns_torrent_phy_write(regmap, CMN_IBCAL_INIT_TMR, 0x0019);
cdns_torrent_phy_write(regmap, CMN_TXPUCAL_INIT_TMR, 0x001E);
cdns_torrent_phy_write(regmap, CMN_TXPUCAL_ITER_TMR, 0x0006);
cdns_torrent_phy_write(regmap, CMN_TXPDCAL_INIT_TMR, 0x001E);
cdns_torrent_phy_write(regmap, CMN_TXPDCAL_ITER_TMR, 0x0006);
cdns_torrent_phy_write(regmap, CMN_RXCAL_INIT_TMR, 0x02EE);
cdns_torrent_phy_write(regmap, CMN_RXCAL_ITER_TMR, 0x0006);
cdns_torrent_phy_write(regmap, CMN_SD_CAL_INIT_TMR, 0x0002);
cdns_torrent_phy_write(regmap, CMN_SD_CAL_ITER_TMR, 0x0002);
cdns_torrent_phy_write(regmap, CMN_SD_CAL_REFTIM_START, 0x000E);
cdns_torrent_phy_write(regmap, CMN_SD_CAL_PLLCNT_START, 0x012B);
/* PLL registers */
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08);
cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_INIT_TMR, 0x00FA);
cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_ITER_TMR, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_INIT_TMR, 0x00FA);
cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_ITER_TMR, 0x0004);
cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_REFTIM_START, 0x0317);
cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_TCTRL, 0x0003);
cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_REFTIM_START, 0x0317);
cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_TCTRL, 0x0003);
}
/* Disable the cmn_pll0_en before re-programming the new data rate. */
regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x0);
/*
* Set registers responsible for enabling and configuring SSC, with second
* register value provided by a parameter.
/*
* Wait for PLL ready de-assertion.
* For PLL0 - PHY_PMA_CMN_CTRL2[2] == 1
*/
static void cdns_torrent_dp_enable_ssc_25mhz(struct cdns_torrent_phy *cdns_phy,
u32 ctrl2_val)
{
struct regmap *regmap = cdns_phy->regmap_common_cdb;
ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2,
read_val,
((read_val >> 2) & 0x01) != 0,
0, POLL_TIMEOUT_US);
if (ret)
return ret;
ndelay(200);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0001);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl2_val);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x007F);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0003);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0001);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl2_val);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x007F);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0003);
/* DP Rate Change - VCO Output settings. */
if (cdns_phy->ref_clk_rate == CLK_19_2_MHZ)
/* PMA common configuration 19.2MHz */
cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, dp->link_rate, dp->ssc);
else if (cdns_phy->ref_clk_rate == CLK_25_MHZ)
/* PMA common configuration 25MHz */
cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, dp->link_rate, dp->ssc);
else if (cdns_phy->ref_clk_rate == CLK_100_MHZ)
/* PMA common configuration 100MHz */
cdns_torrent_dp_pma_cmn_vco_cfg_100mhz(cdns_phy, dp->link_rate, dp->ssc);
cdns_torrent_dp_pma_cmn_rate(cdns_phy, dp->link_rate, dp->lanes);
/* Enable the cmn_pll0_en. */
regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x3);
/*
* Wait for PLL ready assertion.
* For PLL0 - PHY_PMA_CMN_CTRL2[0] == 1
*/
ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2,
read_val,
(read_val & 0x01) != 0,
0, POLL_TIMEOUT_US);
return ret;
}
static
void cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(struct cdns_torrent_phy *cdns_phy,
u32 rate, bool ssc)
/*
* Verify, that parameters to configure PHY with are correct.
*/
static int cdns_torrent_dp_verify_config(struct cdns_torrent_inst *inst,
struct phy_configure_opts_dp *dp)
{
struct regmap *regmap = cdns_phy->regmap_common_cdb;
u8 i;
/* Assumes 25 MHz refclock */
switch (rate) {
/* Setting VCO for 10.8GHz */
case 2700:
case 5400:
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x01B0);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0120);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x01B0);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0120);
if (ssc)
cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x0423);
break;
/* Setting VCO for 9.72GHz */
/* If changing link rate was required, verify it's supported. */
if (dp->set_rate) {
switch (dp->link_rate) {
case 1620:
case 2160:
case 2430:
case 2700:
case 3240:
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0184);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0xCCCD);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0104);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0184);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0xCCCD);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0104);
if (ssc)
cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x03B9);
break;
/* Setting VCO for 8.64GHz */
case 2160:
case 4320:
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0159);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x999A);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x00E7);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0159);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x999A);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x00E7);
if (ssc)
cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x034F);
break;
/* Setting VCO for 8.1GHz */
case 5400:
case 8100:
cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0144);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x00D8);
cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0144);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x00D8);
if (ssc)
cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x031A);
/* valid bit rate */
break;
default:
return -EINVAL;
}
}
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
/* Verify lane count. */
switch (dp->lanes) {
case 1:
case 2:
case 4:
/* valid lane count. */
break;
default:
return -EINVAL;
}
if (ssc) {
cdns_torrent_phy_write(regmap,
CMN_PLL0_VCOCAL_PLLCNT_START, 0x0315);
cdns_torrent_phy_write(regmap,
CMN_PLL0_LOCK_PLLCNT_THR, 0x0005);
cdns_torrent_phy_write(regmap,
CMN_PLL1_VCOCAL_PLLCNT_START, 0x0315);
cdns_torrent_phy_write(regmap,
CMN_PLL1_LOCK_PLLCNT_THR, 0x0005);
} else {
cdns_torrent_phy_write(regmap,
CMN_PLL0_VCOCAL_PLLCNT_START, 0x0317);
cdns_torrent_phy_write(regmap,
CMN_PLL1_VCOCAL_PLLCNT_START, 0x0317);
/* Set reset register values to disable SSC */
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL2_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL3_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0000);
cdns_torrent_phy_write(regmap,
CMN_PLL0_LOCK_PLLCNT_THR, 0x0003);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0002);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL2_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL3_M0, 0x0000);
cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0000);
cdns_torrent_phy_write(regmap,
CMN_PLL1_LOCK_PLLCNT_THR, 0x0003);
/* Check against actual number of PHY's lanes. */
if (dp->lanes > inst->num_lanes)
return -EINVAL;
/*
* If changing voltages is required, check swing and pre-emphasis
* levels, per-lane.
*/
if (dp->set_voltages) {
/* Lane count verified previously. */
for (i = 0; i < dp->lanes; i++) {
if (dp->voltage[i] > 3 || dp->pre[i] > 3)
return -EINVAL;
/* Sum of voltage swing and pre-emphasis levels cannot
* exceed 3.
*/
if (dp->voltage[i] + dp->pre[i] > 3)
return -EINVAL;
}
}
cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_REFCNT_START, 0x00C7);
cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_PLLCNT_START, 0x00C7);
cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_REFCNT_START, 0x00C7);
cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_START, 0x00C7);
return 0;
}
/* Set power state A0 and PLL clock enable to 0 on enabled lanes. */
static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy,
u32 num_lanes)
{
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
u32 pwr_state = cdns_torrent_dp_read(regmap,
PHY_PMA_XCVR_POWER_STATE_REQ);
u32 pll_clk_en = cdns_torrent_dp_read(regmap,
PHY_PMA_XCVR_PLLCLK_EN);
/* Lane 0 is always enabled. */
pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
PHY_POWER_STATE_LN_0);
pll_clk_en &= ~0x01U;
if (num_lanes > 1) {
/* lane 1 */
pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
PHY_POWER_STATE_LN_1);
pll_clk_en &= ~(0x01U << 1);
}
if (num_lanes > 2) {
/* lanes 2 and 3 */
pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
PHY_POWER_STATE_LN_2);
pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
PHY_POWER_STATE_LN_3);
pll_clk_en &= ~(0x01U << 2);
pll_clk_en &= ~(0x01U << 3);
}
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, pwr_state);
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_clk_en);
}
/* Configure lane count as required. */
static int cdns_torrent_dp_set_lanes(struct cdns_torrent_phy *cdns_phy,
struct phy_configure_opts_dp *dp)
{
u32 value;
u32 ret;
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
u8 lane_mask = (1 << dp->lanes) - 1;
value = cdns_torrent_dp_read(regmap, PHY_RESET);
/* clear pma_tx_elec_idle_ln_* bits. */
value &= ~PMA_TX_ELEC_IDLE_MASK;
/* Assert pma_tx_elec_idle_ln_* for disabled lanes. */
value |= ((~lane_mask) << PMA_TX_ELEC_IDLE_SHIFT) &
PMA_TX_ELEC_IDLE_MASK;
cdns_torrent_dp_write(regmap, PHY_RESET, value);
/* reset the link by asserting phy_l00_reset_n low */
cdns_torrent_dp_write(regmap, PHY_RESET,
value & (~PHY_L00_RESET_N_MASK));
/*
* Assert lane reset on unused lanes and lane 0 so they remain in reset
* and powered down when re-enabling the link
*/
value = (value & 0x0000FFF0) | (0x0000000E & lane_mask);
cdns_torrent_dp_write(regmap, PHY_RESET, value);
cdns_torrent_dp_set_a0_pll(cdns_phy, dp->lanes);
/* release phy_l0*_reset_n based on used laneCount */
value = (value & 0x0000FFF0) | (0x0000000F & lane_mask);
cdns_torrent_dp_write(regmap, PHY_RESET, value);
/* Wait, until PHY gets ready after releasing PHY reset signal. */
ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy);
if (ret)
return ret;
ndelay(100);
/* release pma_xcvr_pllclk_en_ln_*, only for the master lane */
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001);
ret = cdns_torrent_dp_run(cdns_phy, dp->lanes);
return ret;
}
/* Configure link rate as required. */
static int cdns_torrent_dp_set_rate(struct cdns_torrent_phy *cdns_phy,
struct phy_configure_opts_dp *dp)
{
u32 ret;
ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes,
POWERSTATE_A3);
if (ret)
return ret;
ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, false);
if (ret)
return ret;
ndelay(200);
ret = cdns_torrent_dp_configure_rate(cdns_phy, dp);
if (ret)
return ret;
ndelay(200);
ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, true);
if (ret)
return ret;
ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes,
POWERSTATE_A2);
if (ret)
return ret;
ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes,
POWERSTATE_A0);
if (ret)
return ret;
ndelay(900);
return ret;
}
/* Configure voltage swing and pre-emphasis for all enabled lanes. */
static void cdns_torrent_dp_set_voltages(struct cdns_torrent_phy *cdns_phy,
struct phy_configure_opts_dp *dp)
{
u8 lane;
u16 val;
for (lane = 0; lane < dp->lanes; lane++) {
val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane],
TX_DIAG_ACYA);
/*
* Write 1 to register bit TX_DIAG_ACYA[0] to freeze the
* current state of the analog TX driver.
*/
val |= TX_DIAG_ACYA_HBDC_MASK;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_DIAG_ACYA, val);
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_TXCC_CTRL, 0x08A4);
val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].diag_tx_drv;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
DRV_DIAG_TX_DRV, val);
val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].mgnfs_mult;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_TXCC_MGNFS_MULT_000,
val);
val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].cpost_mult;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_TXCC_CPOST_MULT_00,
val);
val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane],
TX_DIAG_ACYA);
/*
* Write 0 to register bit TX_DIAG_ACYA[0] to allow the state of
* analog TX driver to reflect the new programmed one.
*/
val &= ~TX_DIAG_ACYA_HBDC_MASK;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_DIAG_ACYA, val);
}
};
static int cdns_torrent_dp_configure(struct phy *phy,
union phy_configure_opts *opts)
{
struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
int ret;
ret = cdns_torrent_dp_verify_config(inst, &opts->dp);
if (ret) {
dev_err(&phy->dev, "invalid params for phy configure\n");
return ret;
}
if (opts->dp.set_lanes) {
ret = cdns_torrent_dp_set_lanes(cdns_phy, &opts->dp);
if (ret) {
dev_err(&phy->dev, "cdns_torrent_dp_set_lanes failed\n");
return ret;
}
}
if (opts->dp.set_rate) {
ret = cdns_torrent_dp_set_rate(cdns_phy, &opts->dp);
if (ret) {
dev_err(&phy->dev, "cdns_torrent_dp_set_rate failed\n");
return ret;
}
}
if (opts->dp.set_voltages)
cdns_torrent_dp_set_voltages(cdns_phy, &opts->dp);
return ret;
}
static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy,
u32 rate, u32 num_lanes)
static int cdns_torrent_phy_on(struct phy *phy)
{
unsigned int clk_sel_val = 0;
unsigned int hsclk_div_val = 0;
unsigned int i;
struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
u32 read_val;
int ret;
/* 16'h0000 for single DP link configuration */
regmap_field_write(cdns_phy->phy_pll_cfg, 0x0);
if (cdns_phy->nsubnodes == 1) {
/* Take the PHY lane group out of reset */
reset_control_deassert(inst->lnk_rst);
switch (rate) {
case 1620:
clk_sel_val = 0x0f01;
hsclk_div_val = 2;
break;
case 2160:
case 2430:
case 2700:
clk_sel_val = 0x0701;
hsclk_div_val = 1;
break;
case 3240:
clk_sel_val = 0x0b00;
hsclk_div_val = 2;
break;
case 4320:
case 5400:
clk_sel_val = 0x0301;
hsclk_div_val = 0;
break;
case 8100:
clk_sel_val = 0x0200;
hsclk_div_val = 0;
break;
/* Take the PHY out of reset */
ret = reset_control_deassert(cdns_phy->phy_rst);
if (ret)
return ret;
}
cdns_torrent_phy_write(cdns_phy->regmap_common_cdb,
CMN_PDIAG_PLL0_CLK_SEL_M0, clk_sel_val);
cdns_torrent_phy_write(cdns_phy->regmap_common_cdb,
CMN_PDIAG_PLL1_CLK_SEL_M0, clk_sel_val);
/*
* Wait for cmn_ready assertion
* PHY_PMA_CMN_CTRL1[0] == 1
*/
ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_1,
read_val, read_val, 1000,
PLL_LOCK_TIMEOUT);
if (ret) {
dev_err(cdns_phy->dev, "Timeout waiting for CMN ready\n");
return ret;
}
/* PMA lane configuration to deal with multi-link operation */
for (i = 0; i < num_lanes; i++)
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[i],
XCVR_DIAG_HSCLK_DIV, hsclk_div_val);
if (inst->phy_type == TYPE_PCIE || inst->phy_type == TYPE_USB) {
ret = regmap_field_read_poll_timeout(cdns_phy->phy_pcs_iso_link_ctrl_1[inst->mlane],
read_val, !read_val, 1000,
PLL_LOCK_TIMEOUT);
if (ret == -ETIMEDOUT) {
dev_err(cdns_phy->dev, "Timeout waiting for PHY status ready\n");
return ret;
}
}
return 0;
}
static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy,
unsigned int lane)
static int cdns_torrent_phy_off(struct phy *phy)
{
/* Per lane, refclock-dependent receiver detection setting */
if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHz)
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_RCVDET_ST_TMR, 0x0780);
else if (cdns_phy->ref_clk_rate == REF_CLK_25MHz)
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_RCVDET_ST_TMR, 0x09C4);
struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
int ret;
/* Writing Tx/Rx Power State Controllers registers */
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_PSC_A0, 0x00FB);
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_PSC_A2, 0x04AA);
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
TX_PSC_A3, 0x04AA);
cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane],
RX_PSC_A0, 0x0000);
cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane],
RX_PSC_A2, 0x0000);
cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane],
RX_PSC_A3, 0x0000);
cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane],
RX_PSC_CAL, 0x0000);
cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane],
RX_REE_GCSM1_CTRL, 0x0000);
cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane],
RX_REE_GCSM2_CTRL, 0x0000);
cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane],
RX_REE_PERGCSM_CTRL, 0x0000);
if (cdns_phy->nsubnodes != 1)
return 0;
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
XCVR_DIAG_BIDI_CTRL, 0x000F);
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
XCVR_DIAG_PLLDRC_CTRL, 0x0001);
cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
XCVR_DIAG_HSCLK_SEL, 0x0000);
ret = reset_control_assert(cdns_phy->phy_rst);
if (ret)
return ret;
return reset_control_assert(inst->lnk_rst);
}
static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy,
u32 num_lanes,
enum phy_powerstate powerstate)
static void cdns_torrent_dp_common_init(struct cdns_torrent_phy *cdns_phy,
struct cdns_torrent_inst *inst)
{
/* Register value for power state for a single byte. */
u32 value_part;
u32 value;
u32 mask;
u32 read_val;
u32 ret;
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
unsigned char lane_bits;
switch (powerstate) {
case (POWERSTATE_A0):
value_part = 0x01U;
break;
case (POWERSTATE_A2):
value_part = 0x04U;
break;
default:
/* Powerstate A3 */
value_part = 0x08U;
break;
}
cdns_torrent_dp_write(regmap, PHY_AUX_CTRL, 0x0003); /* enable AUX */
/* Select values of registers and mask, depending on enabled
* lane count.
/*
* Set lines power state to A0
* Set lines pll clk enable to 0
*/
switch (num_lanes) {
/* lane 0 */
case (1):
value = value_part;
mask = 0x0000003FU;
break;
/* lanes 0-1 */
case (2):
value = (value_part
| (value_part << 8));
mask = 0x00003F3FU;
break;
/* lanes 0-3, all */
default:
value = (value_part
| (value_part << 8)
| (value_part << 16)
| (value_part << 24));
mask = 0x3F3F3F3FU;
break;
}
cdns_torrent_dp_set_a0_pll(cdns_phy, inst->num_lanes);
/* Set power state A<n>. */
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, value);
/* Wait, until PHY acknowledges power state completion. */
ret = regmap_read_poll_timeout(regmap, PHY_PMA_XCVR_POWER_STATE_ACK,
read_val, (read_val & mask) == value, 0,
POLL_TIMEOUT_US);
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, 0x00000000);
ndelay(100);
/*
* release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on
* used lanes
*/
lane_bits = (1 << inst->num_lanes) - 1;
cdns_torrent_dp_write(regmap, PHY_RESET,
((0xF & ~lane_bits) << 4) | (0xF & lane_bits));
return ret;
/* release pma_xcvr_pllclk_en_ln_*, only for the master lane */
cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001);
/*
* PHY PMA registers configuration functions
* Initialize PHY with max supported link rate, without SSC.
*/
if (cdns_phy->ref_clk_rate == CLK_19_2_MHZ)
cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy,
cdns_phy->max_bit_rate,
false);
else if (cdns_phy->ref_clk_rate == CLK_25_MHZ)
cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy,
cdns_phy->max_bit_rate,
false);
else if (cdns_phy->ref_clk_rate == CLK_100_MHZ)
cdns_torrent_dp_pma_cmn_vco_cfg_100mhz(cdns_phy,
cdns_phy->max_bit_rate,
false);
cdns_torrent_dp_pma_cmn_rate(cdns_phy, cdns_phy->max_bit_rate,
inst->num_lanes);
/* take out of reset */
regmap_field_write(cdns_phy->phy_reset_ctrl, 0x1);
}
static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, u32 num_lanes)
static int cdns_torrent_dp_start(struct cdns_torrent_phy *cdns_phy,
struct cdns_torrent_inst *inst,
struct phy *phy)
{
unsigned int read_val;
int ret;
struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
/*
* waiting for ACK of pma_xcvr_pllclk_en_ln_*, only for the
* master lane
*/
ret = regmap_read_poll_timeout(regmap, PHY_PMA_XCVR_PLLCLK_EN_ACK,
read_val, read_val & 1,
0, POLL_TIMEOUT_US);
if (ret == -ETIMEDOUT) {
dev_err(cdns_phy->dev,
"timeout waiting for link PLL clock enable ack\n");
return ret;
}
ndelay(100);
cdns_torrent_phy_on(phy);
ret = cdns_torrent_dp_set_power_state(cdns_phy, num_lanes,
POWERSTATE_A2);
ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy);
if (ret)
return ret;
ret = cdns_torrent_dp_set_power_state(cdns_phy, num_lanes,
POWERSTATE_A0);
ret = cdns_torrent_dp_run(cdns_phy, inst->num_lanes);
return ret;
}
static int cdns_torrent_dp_init(struct phy *phy)
{
struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
switch (cdns_phy->ref_clk_rate) {
case CLK_19_2_MHZ:
case CLK_25_MHZ:
case CLK_100_MHZ:
/* Valid Ref Clock Rate */
break;
default:
dev_err(cdns_phy->dev, "Unsupported Ref Clock Rate\n");
return -EINVAL;
}
cdns_torrent_dp_common_init(cdns_phy, inst);
return cdns_torrent_dp_start(cdns_phy, inst, phy);
}
static int cdns_torrent_derived_refclk_enable(struct clk_hw *hw)
{
struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw);
......@@ -1733,85 +1684,35 @@ static int cdns_torrent_derived_refclk_register(struct cdns_torrent_phy *cdns_ph
}
init->ops = &cdns_torrent_derived_refclk_ops;
init->flags = 0;
init->name = clk_name;
regmap = cdns_phy->regmap_phy_pcs_common_cdb;
field = devm_regmap_field_alloc(dev, regmap, phy_pipe_cmn_ctrl1_0);
if (IS_ERR(field)) {
dev_err(dev, "phy_pipe_cmn_ctrl1_0 reg field init failed\n");
return PTR_ERR(field);
}
derived_refclk->phy_pipe_cmn_ctrl1_0 = field;
regmap = cdns_phy->regmap_common_cdb;
for (i = 0; i < REFCLK_OUT_NUM_CMN_CONFIG; i++) {
field = devm_regmap_field_alloc(dev, regmap, refclk_out_cmn_cfg[i]);
if (IS_ERR(field)) {
dev_err(dev, "CMN reg field init failed\n");
return PTR_ERR(field);
}
derived_refclk->cmn_fields[i] = field;
}
derived_refclk->hw.init = init;
clk = devm_clk_register(dev, &derived_refclk->hw);
if (IS_ERR(clk))
return PTR_ERR(clk);
cdns_phy->clks[CDNS_TORRENT_REFCLK_DRIVER] = clk;
return 0;
}
static int cdns_torrent_phy_on(struct phy *phy)
{
struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
u32 read_val;
int ret;
if (cdns_phy->nsubnodes == 1) {
/* Take the PHY lane group out of reset */
reset_control_deassert(inst->lnk_rst);
init->name = clk_name;
/* Take the PHY out of reset */
ret = reset_control_deassert(cdns_phy->phy_rst);
if (ret)
return ret;
regmap = cdns_phy->regmap_phy_pcs_common_cdb;
field = devm_regmap_field_alloc(dev, regmap, phy_pipe_cmn_ctrl1_0);
if (IS_ERR(field)) {
dev_err(dev, "phy_pipe_cmn_ctrl1_0 reg field init failed\n");
return PTR_ERR(field);
}
derived_refclk->phy_pipe_cmn_ctrl1_0 = field;
/*
* Wait for cmn_ready assertion
* PHY_PMA_CMN_CTRL1[0] == 1
*/
ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_1,
read_val, read_val, 1000,
PLL_LOCK_TIMEOUT);
if (ret) {
dev_err(cdns_phy->dev, "Timeout waiting for CMN ready\n");
return ret;
regmap = cdns_phy->regmap_common_cdb;
for (i = 0; i < REFCLK_OUT_NUM_CMN_CONFIG; i++) {
field = devm_regmap_field_alloc(dev, regmap, refclk_out_cmn_cfg[i]);
if (IS_ERR(field)) {
dev_err(dev, "CMN reg field init failed\n");
return PTR_ERR(field);
}
derived_refclk->cmn_fields[i] = field;
}
mdelay(10);
derived_refclk->hw.init = init;
return 0;
}
clk = devm_clk_register(dev, &derived_refclk->hw);
if (IS_ERR(clk))
return PTR_ERR(clk);
static int cdns_torrent_phy_off(struct phy *phy)
{
struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
int ret;
cdns_phy->clks[CDNS_TORRENT_REFCLK_DRIVER] = clk;
if (cdns_phy->nsubnodes != 1)
return 0;
ret = reset_control_assert(cdns_phy->phy_rst);
if (ret)
return ret;
return reset_control_assert(inst->lnk_rst);
}
static struct regmap *cdns_regmap_init(struct device *dev, void __iomem *base,
......@@ -1854,6 +1755,7 @@ static int cdns_torrent_regfield_init(struct cdns_torrent_phy *cdns_phy)
struct device *dev = cdns_phy->dev;
struct regmap_field *field;
struct regmap *regmap;
int i;
regmap = cdns_phy->regmap_phy_pcs_common_cdb;
field = devm_regmap_field_alloc(dev, regmap, phy_pll_cfg);
......@@ -1887,6 +1789,16 @@ static int cdns_torrent_regfield_init(struct cdns_torrent_phy *cdns_phy)
}
cdns_phy->phy_pma_pll_raw_ctrl = field;
for (i = 0; i < MAX_NUM_LANES; i++) {
regmap = cdns_phy->regmap_phy_pcs_lane_cdb[i];
field = devm_regmap_field_alloc(dev, regmap, phy_pcs_iso_link_ctrl_1);
if (IS_ERR(field)) {
dev_err(dev, "PHY_PCS_ISO_LINK_CTRL reg field init for ln %d failed\n", i);
return PTR_ERR(field);
}
cdns_phy->phy_pcs_iso_link_ctrl_1[i] = field;
}
return 0;
}
......@@ -1947,6 +1859,17 @@ static int cdns_torrent_regmap_init(struct cdns_torrent_phy *cdns_phy)
return PTR_ERR(regmap);
}
cdns_phy->regmap_rx_lane_cdb[i] = regmap;
block_offset = TORRENT_PHY_PCS_LANE_CDB_OFFSET(i, block_offset_shift,
reg_offset_shift);
regmap = cdns_regmap_init(dev, sd_base, block_offset,
reg_offset_shift,
&cdns_torrent_phy_pcs_lane_cdb_config[i]);
if (IS_ERR(regmap)) {
dev_err(dev, "Failed to init PHY PCS lane CDB regmap\n");
return PTR_ERR(regmap);
}
cdns_phy->regmap_phy_pcs_lane_cdb[i] = regmap;
}
block_offset = TORRENT_COMMON_CDB_OFFSET;
......@@ -1987,6 +1910,7 @@ static int cdns_torrent_phy_init(struct phy *phy)
struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
const struct cdns_torrent_data *init_data = cdns_phy->init_data;
struct cdns_torrent_vals *cmn_vals, *tx_ln_vals, *rx_ln_vals;
enum cdns_torrent_ref_clk ref_clk = cdns_phy->ref_clk_rate;
struct cdns_torrent_vals *link_cmn_vals, *xcvr_diag_vals;
struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
enum cdns_torrent_phy_type phy_type = inst->phy_type;
......@@ -2000,9 +1924,6 @@ static int cdns_torrent_phy_init(struct phy *phy)
if (cdns_phy->nsubnodes > 1)
return 0;
if (phy_type == TYPE_DP)
return cdns_torrent_dp_init(phy);
/**
* Spread spectrum generation is not required or supported
* for SGMII/QSGMII
......@@ -2052,7 +1973,7 @@ static int cdns_torrent_phy_init(struct phy *phy)
}
/* PMA common registers configurations */
cmn_vals = init_data->cmn_vals[phy_type][TYPE_NONE][ssc];
cmn_vals = init_data->cmn_vals[ref_clk][phy_type][TYPE_NONE][ssc];
if (cmn_vals) {
reg_pairs = cmn_vals->reg_pairs;
num_regs = cmn_vals->num_regs;
......@@ -2063,7 +1984,7 @@ static int cdns_torrent_phy_init(struct phy *phy)
}
/* PMA TX lane registers configurations */
tx_ln_vals = init_data->tx_ln_vals[phy_type][TYPE_NONE][ssc];
tx_ln_vals = init_data->tx_ln_vals[ref_clk][phy_type][TYPE_NONE][ssc];
if (tx_ln_vals) {
reg_pairs = tx_ln_vals->reg_pairs;
num_regs = tx_ln_vals->num_regs;
......@@ -2076,7 +1997,7 @@ static int cdns_torrent_phy_init(struct phy *phy)
}
/* PMA RX lane registers configurations */
rx_ln_vals = init_data->rx_ln_vals[phy_type][TYPE_NONE][ssc];
rx_ln_vals = init_data->rx_ln_vals[ref_clk][phy_type][TYPE_NONE][ssc];
if (rx_ln_vals) {
reg_pairs = rx_ln_vals->reg_pairs;
num_regs = rx_ln_vals->num_regs;
......@@ -2088,14 +2009,39 @@ static int cdns_torrent_phy_init(struct phy *phy)
}
}
if (phy_type == TYPE_DP)
return cdns_torrent_dp_init(phy);
return 0;
}
static const struct phy_ops cdns_torrent_phy_ops = {
.init = cdns_torrent_phy_init,
.configure = cdns_torrent_dp_configure,
.power_on = cdns_torrent_phy_on,
.power_off = cdns_torrent_phy_off,
.owner = THIS_MODULE,
};
static int cdns_torrent_noop_phy_on(struct phy *phy)
{
/* Give 5ms to 10ms delay for the PIPE clock to be stable */
usleep_range(5000, 10000);
return 0;
}
static const struct phy_ops noop_ops = {
.power_on = cdns_torrent_noop_phy_on,
.owner = THIS_MODULE,
};
static
int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy)
{
const struct cdns_torrent_data *init_data = cdns_phy->init_data;
struct cdns_torrent_vals *cmn_vals, *tx_ln_vals, *rx_ln_vals;
enum cdns_torrent_ref_clk ref_clk = cdns_phy->ref_clk_rate;
struct cdns_torrent_vals *link_cmn_vals, *xcvr_diag_vals;
enum cdns_torrent_phy_type phy_t1, phy_t2, tmp_phy_type;
struct cdns_torrent_vals *pcs_cmn_vals;
......@@ -2184,7 +2130,7 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy)
}
/* PMA common registers configurations */
cmn_vals = init_data->cmn_vals[phy_t1][phy_t2][ssc];
cmn_vals = init_data->cmn_vals[ref_clk][phy_t1][phy_t2][ssc];
if (cmn_vals) {
reg_pairs = cmn_vals->reg_pairs;
num_regs = cmn_vals->num_regs;
......@@ -2195,7 +2141,7 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy)
}
/* PMA TX lane registers configurations */
tx_ln_vals = init_data->tx_ln_vals[phy_t1][phy_t2][ssc];
tx_ln_vals = init_data->tx_ln_vals[ref_clk][phy_t1][phy_t2][ssc];
if (tx_ln_vals) {
reg_pairs = tx_ln_vals->reg_pairs;
num_regs = tx_ln_vals->num_regs;
......@@ -2208,7 +2154,7 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy)
}
/* PMA RX lane registers configurations */
rx_ln_vals = init_data->rx_ln_vals[phy_t1][phy_t2][ssc];
rx_ln_vals = init_data->rx_ln_vals[ref_clk][phy_t1][phy_t2][ssc];
if (rx_ln_vals) {
reg_pairs = rx_ln_vals->reg_pairs;
num_regs = rx_ln_vals->num_regs;
......@@ -2286,6 +2232,7 @@ static int cdns_torrent_reset(struct cdns_torrent_phy *cdns_phy)
static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy)
{
struct device *dev = cdns_phy->dev;
unsigned long ref_clk_rate;
int ret;
cdns_phy->clk = devm_clk_get(dev, "refclk");
......@@ -2300,13 +2247,29 @@ static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy)
return ret;
}
cdns_phy->ref_clk_rate = clk_get_rate(cdns_phy->clk);
if (!(cdns_phy->ref_clk_rate)) {
ref_clk_rate = clk_get_rate(cdns_phy->clk);
if (!ref_clk_rate) {
dev_err(cdns_phy->dev, "Failed to get ref clock rate\n");
clk_disable_unprepare(cdns_phy->clk);
return -EINVAL;
}
switch (ref_clk_rate) {
case REF_CLK_19_2MHZ:
cdns_phy->ref_clk_rate = CLK_19_2_MHZ;
break;
case REF_CLK_25MHZ:
cdns_phy->ref_clk_rate = CLK_25_MHZ;
break;
case REF_CLK_100MHZ:
cdns_phy->ref_clk_rate = CLK_100_MHZ;
break;
default:
dev_err(cdns_phy->dev, "Invalid Ref Clock Rate\n");
clk_disable_unprepare(cdns_phy->clk);
return -EINVAL;
}
return 0;
}
......@@ -2505,8 +2468,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
init_dp_regmap++;
}
dev_info(dev, "%d lanes, max bit rate %d.%03d Gbps\n",
cdns_phy->phys[node].num_lanes,
dev_dbg(dev, "DP max bit rate %d.%03d Gbps\n",
cdns_phy->max_bit_rate / 1000,
cdns_phy->max_bit_rate % 1000);
......@@ -2540,6 +2502,17 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev)
goto put_lnk_rst;
}
if (cdns_phy->nsubnodes > 1)
dev_dbg(dev, "Multi-link: %s (%d lanes) & %s (%d lanes)",
cdns_torrent_get_phy_type(cdns_phy->phys[0].phy_type),
cdns_phy->phys[0].num_lanes,
cdns_torrent_get_phy_type(cdns_phy->phys[1].phy_type),
cdns_phy->phys[1].num_lanes);
else
dev_dbg(dev, "Single link: %s (%d lanes)",
cdns_torrent_get_phy_type(cdns_phy->phys[0].phy_type),
cdns_phy->phys[0].num_lanes);
return 0;
put_child:
......@@ -2573,6 +2546,206 @@ static int cdns_torrent_phy_remove(struct platform_device *pdev)
return 0;
}
/* Single DisplayPort(DP) link configuration */
static struct cdns_reg_pairs sl_dp_link_cmn_regs[] = {
{0x0000, PHY_PLL_CFG},
};
static struct cdns_reg_pairs sl_dp_xcvr_diag_ln_regs[] = {
{0x0000, XCVR_DIAG_HSCLK_SEL},
{0x0001, XCVR_DIAG_PLLDRC_CTRL}
};
static struct cdns_torrent_vals sl_dp_link_cmn_vals = {
.reg_pairs = sl_dp_link_cmn_regs,
.num_regs = ARRAY_SIZE(sl_dp_link_cmn_regs),
};
static struct cdns_torrent_vals sl_dp_xcvr_diag_ln_vals = {
.reg_pairs = sl_dp_xcvr_diag_ln_regs,
.num_regs = ARRAY_SIZE(sl_dp_xcvr_diag_ln_regs),
};
/* Single DP, 19.2 MHz Ref clk, no SSC */
static struct cdns_reg_pairs sl_dp_19_2_no_ssc_cmn_regs[] = {
{0x0014, CMN_SSM_BIAS_TMR},
{0x0027, CMN_PLLSM0_PLLPRE_TMR},
{0x00A1, CMN_PLLSM0_PLLLOCK_TMR},
{0x0027, CMN_PLLSM1_PLLPRE_TMR},
{0x00A1, CMN_PLLSM1_PLLLOCK_TMR},
{0x0060, CMN_BGCAL_INIT_TMR},
{0x0060, CMN_BGCAL_ITER_TMR},
{0x0014, CMN_IBCAL_INIT_TMR},
{0x0018, CMN_TXPUCAL_INIT_TMR},
{0x0005, CMN_TXPUCAL_ITER_TMR},
{0x0018, CMN_TXPDCAL_INIT_TMR},
{0x0005, CMN_TXPDCAL_ITER_TMR},
{0x0240, CMN_RXCAL_INIT_TMR},
{0x0005, CMN_RXCAL_ITER_TMR},
{0x0002, CMN_SD_CAL_INIT_TMR},
{0x0002, CMN_SD_CAL_ITER_TMR},
{0x000B, CMN_SD_CAL_REFTIM_START},
{0x0137, CMN_SD_CAL_PLLCNT_START},
{0x0509, CMN_PDIAG_PLL0_CP_PADJ_M0},
{0x0F00, CMN_PDIAG_PLL0_CP_IADJ_M0},
{0x0F08, CMN_PDIAG_PLL0_FILT_PADJ_M0},
{0x0004, CMN_PLL0_DSM_DIAG_M0},
{0x0509, CMN_PDIAG_PLL1_CP_PADJ_M0},
{0x0F00, CMN_PDIAG_PLL1_CP_IADJ_M0},
{0x0F08, CMN_PDIAG_PLL1_FILT_PADJ_M0},
{0x0004, CMN_PLL1_DSM_DIAG_M0},
{0x00C0, CMN_PLL0_VCOCAL_INIT_TMR},
{0x0004, CMN_PLL0_VCOCAL_ITER_TMR},
{0x00C0, CMN_PLL1_VCOCAL_INIT_TMR},
{0x0004, CMN_PLL1_VCOCAL_ITER_TMR},
{0x0260, CMN_PLL0_VCOCAL_REFTIM_START},
{0x0003, CMN_PLL0_VCOCAL_TCTRL},
{0x0260, CMN_PLL1_VCOCAL_REFTIM_START},
{0x0003, CMN_PLL1_VCOCAL_TCTRL}
};
static struct cdns_reg_pairs sl_dp_19_2_no_ssc_tx_ln_regs[] = {
{0x0780, TX_RCVDET_ST_TMR},
{0x00FB, TX_PSC_A0},
{0x04AA, TX_PSC_A2},
{0x04AA, TX_PSC_A3},
{0x000F, XCVR_DIAG_BIDI_CTRL}
};
static struct cdns_reg_pairs sl_dp_19_2_no_ssc_rx_ln_regs[] = {
{0x0000, RX_PSC_A0},
{0x0000, RX_PSC_A2},
{0x0000, RX_PSC_A3},
{0x0000, RX_PSC_CAL},
{0x0000, RX_REE_GCSM1_CTRL},
{0x0000, RX_REE_GCSM2_CTRL},
{0x0000, RX_REE_PERGCSM_CTRL}
};
static struct cdns_torrent_vals sl_dp_19_2_no_ssc_cmn_vals = {
.reg_pairs = sl_dp_19_2_no_ssc_cmn_regs,
.num_regs = ARRAY_SIZE(sl_dp_19_2_no_ssc_cmn_regs),
};
static struct cdns_torrent_vals sl_dp_19_2_no_ssc_tx_ln_vals = {
.reg_pairs = sl_dp_19_2_no_ssc_tx_ln_regs,
.num_regs = ARRAY_SIZE(sl_dp_19_2_no_ssc_tx_ln_regs),
};
static struct cdns_torrent_vals sl_dp_19_2_no_ssc_rx_ln_vals = {
.reg_pairs = sl_dp_19_2_no_ssc_rx_ln_regs,
.num_regs = ARRAY_SIZE(sl_dp_19_2_no_ssc_rx_ln_regs),
};
/* Single DP, 25 MHz Ref clk, no SSC */
static struct cdns_reg_pairs sl_dp_25_no_ssc_cmn_regs[] = {
{0x0019, CMN_SSM_BIAS_TMR},
{0x0032, CMN_PLLSM0_PLLPRE_TMR},
{0x00D1, CMN_PLLSM0_PLLLOCK_TMR},
{0x0032, CMN_PLLSM1_PLLPRE_TMR},
{0x00D1, CMN_PLLSM1_PLLLOCK_TMR},
{0x007D, CMN_BGCAL_INIT_TMR},
{0x007D, CMN_BGCAL_ITER_TMR},
{0x0019, CMN_IBCAL_INIT_TMR},
{0x001E, CMN_TXPUCAL_INIT_TMR},
{0x0006, CMN_TXPUCAL_ITER_TMR},
{0x001E, CMN_TXPDCAL_INIT_TMR},
{0x0006, CMN_TXPDCAL_ITER_TMR},
{0x02EE, CMN_RXCAL_INIT_TMR},
{0x0006, CMN_RXCAL_ITER_TMR},
{0x0002, CMN_SD_CAL_INIT_TMR},
{0x0002, CMN_SD_CAL_ITER_TMR},
{0x000E, CMN_SD_CAL_REFTIM_START},
{0x012B, CMN_SD_CAL_PLLCNT_START},
{0x0509, CMN_PDIAG_PLL0_CP_PADJ_M0},
{0x0F00, CMN_PDIAG_PLL0_CP_IADJ_M0},
{0x0F08, CMN_PDIAG_PLL0_FILT_PADJ_M0},
{0x0004, CMN_PLL0_DSM_DIAG_M0},
{0x0509, CMN_PDIAG_PLL1_CP_PADJ_M0},
{0x0F00, CMN_PDIAG_PLL1_CP_IADJ_M0},
{0x0F08, CMN_PDIAG_PLL1_FILT_PADJ_M0},
{0x0004, CMN_PLL1_DSM_DIAG_M0},
{0x00FA, CMN_PLL0_VCOCAL_INIT_TMR},
{0x0004, CMN_PLL0_VCOCAL_ITER_TMR},
{0x00FA, CMN_PLL1_VCOCAL_INIT_TMR},
{0x0004, CMN_PLL1_VCOCAL_ITER_TMR},
{0x0317, CMN_PLL0_VCOCAL_REFTIM_START},
{0x0003, CMN_PLL0_VCOCAL_TCTRL},
{0x0317, CMN_PLL1_VCOCAL_REFTIM_START},
{0x0003, CMN_PLL1_VCOCAL_TCTRL}
};
static struct cdns_reg_pairs sl_dp_25_no_ssc_tx_ln_regs[] = {
{0x09C4, TX_RCVDET_ST_TMR},
{0x00FB, TX_PSC_A0},
{0x04AA, TX_PSC_A2},
{0x04AA, TX_PSC_A3},
{0x000F, XCVR_DIAG_BIDI_CTRL}
};
static struct cdns_reg_pairs sl_dp_25_no_ssc_rx_ln_regs[] = {
{0x0000, RX_PSC_A0},
{0x0000, RX_PSC_A2},
{0x0000, RX_PSC_A3},
{0x0000, RX_PSC_CAL},
{0x0000, RX_REE_GCSM1_CTRL},
{0x0000, RX_REE_GCSM2_CTRL},
{0x0000, RX_REE_PERGCSM_CTRL}
};
static struct cdns_torrent_vals sl_dp_25_no_ssc_cmn_vals = {
.reg_pairs = sl_dp_25_no_ssc_cmn_regs,
.num_regs = ARRAY_SIZE(sl_dp_25_no_ssc_cmn_regs),
};
static struct cdns_torrent_vals sl_dp_25_no_ssc_tx_ln_vals = {
.reg_pairs = sl_dp_25_no_ssc_tx_ln_regs,
.num_regs = ARRAY_SIZE(sl_dp_25_no_ssc_tx_ln_regs),
};
static struct cdns_torrent_vals sl_dp_25_no_ssc_rx_ln_vals = {
.reg_pairs = sl_dp_25_no_ssc_rx_ln_regs,
.num_regs = ARRAY_SIZE(sl_dp_25_no_ssc_rx_ln_regs),
};
/* Single DP, 100 MHz Ref clk, no SSC */
static struct cdns_reg_pairs sl_dp_100_no_ssc_cmn_regs[] = {
{0x0003, CMN_PLL0_VCOCAL_TCTRL},
{0x0003, CMN_PLL1_VCOCAL_TCTRL}
};
static struct cdns_reg_pairs sl_dp_100_no_ssc_tx_ln_regs[] = {
{0x00FB, TX_PSC_A0},
{0x04AA, TX_PSC_A2},
{0x04AA, TX_PSC_A3},
{0x000F, XCVR_DIAG_BIDI_CTRL}
};
static struct cdns_reg_pairs sl_dp_100_no_ssc_rx_ln_regs[] = {
{0x0000, RX_PSC_A0},
{0x0000, RX_PSC_A2},
{0x0000, RX_PSC_A3},
{0x0000, RX_PSC_CAL},
{0x0000, RX_REE_GCSM1_CTRL},
{0x0000, RX_REE_GCSM2_CTRL},
{0x0000, RX_REE_PERGCSM_CTRL}
};
static struct cdns_torrent_vals sl_dp_100_no_ssc_cmn_vals = {
.reg_pairs = sl_dp_100_no_ssc_cmn_regs,
.num_regs = ARRAY_SIZE(sl_dp_100_no_ssc_cmn_regs),
};
static struct cdns_torrent_vals sl_dp_100_no_ssc_tx_ln_vals = {
.reg_pairs = sl_dp_100_no_ssc_tx_ln_regs,
.num_regs = ARRAY_SIZE(sl_dp_100_no_ssc_tx_ln_regs),
};
static struct cdns_torrent_vals sl_dp_100_no_ssc_rx_ln_vals = {
.reg_pairs = sl_dp_100_no_ssc_rx_ln_regs,
.num_regs = ARRAY_SIZE(sl_dp_100_no_ssc_rx_ln_regs),
};
/* USB and SGMII/QSGMII link configuration */
static struct cdns_reg_pairs usb_sgmii_link_cmn_regs[] = {
{0x0002, PHY_PLL_CFG},
......@@ -3311,6 +3484,11 @@ static const struct cdns_torrent_data cdns_map_torrent = {
.block_offset_shift = 0x2,
.reg_offset_shift = 0x2,
.link_cmn_vals = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_link_cmn_vals,
},
},
[TYPE_PCIE] = {
[TYPE_NONE] = {
[NO_SSC] = NULL,
......@@ -3387,6 +3565,11 @@ static const struct cdns_torrent_data cdns_map_torrent = {
},
},
.xcvr_diag_vals = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_xcvr_diag_ln_vals,
},
},
[TYPE_PCIE] = {
[TYPE_NONE] = {
[NO_SSC] = NULL,
......@@ -3487,6 +3670,26 @@ static const struct cdns_torrent_data cdns_map_torrent = {
},
},
.cmn_vals = {
[CLK_19_2_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_19_2_no_ssc_cmn_vals,
},
},
},
[CLK_25_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_25_no_ssc_cmn_vals,
},
},
},
[CLK_100_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_100_no_ssc_cmn_vals,
},
},
[TYPE_PCIE] = {
[TYPE_NONE] = {
[NO_SSC] = NULL,
......@@ -3562,7 +3765,28 @@ static const struct cdns_torrent_data cdns_map_torrent = {
},
},
},
},
.tx_ln_vals = {
[CLK_19_2_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_19_2_no_ssc_tx_ln_vals,
},
},
},
[CLK_25_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_25_no_ssc_tx_ln_vals,
},
},
},
[CLK_100_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_100_no_ssc_tx_ln_vals,
},
},
[TYPE_PCIE] = {
[TYPE_NONE] = {
[NO_SSC] = NULL,
......@@ -3638,7 +3862,28 @@ static const struct cdns_torrent_data cdns_map_torrent = {
},
},
},
},
.rx_ln_vals = {
[CLK_19_2_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_19_2_no_ssc_rx_ln_vals,
},
},
},
[CLK_25_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_25_no_ssc_rx_ln_vals,
},
},
},
[CLK_100_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_100_no_ssc_rx_ln_vals,
},
},
[TYPE_PCIE] = {
[TYPE_NONE] = {
[NO_SSC] = &pcie_100_no_ssc_rx_ln_vals,
......@@ -3714,12 +3959,18 @@ static const struct cdns_torrent_data cdns_map_torrent = {
},
},
},
},
};
static const struct cdns_torrent_data ti_j721e_map_torrent = {
.block_offset_shift = 0x0,
.reg_offset_shift = 0x1,
.link_cmn_vals = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_link_cmn_vals,
},
},
[TYPE_PCIE] = {
[TYPE_NONE] = {
[NO_SSC] = NULL,
......@@ -3796,6 +4047,11 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
},
},
.xcvr_diag_vals = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_xcvr_diag_ln_vals,
},
},
[TYPE_PCIE] = {
[TYPE_NONE] = {
[NO_SSC] = NULL,
......@@ -3896,6 +4152,26 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
},
},
.cmn_vals = {
[CLK_19_2_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_19_2_no_ssc_cmn_vals,
},
},
},
[CLK_25_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_25_no_ssc_cmn_vals,
},
},
},
[CLK_100_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_100_no_ssc_cmn_vals,
},
},
[TYPE_PCIE] = {
[TYPE_NONE] = {
[NO_SSC] = NULL,
......@@ -3971,7 +4247,28 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
},
},
},
},
.tx_ln_vals = {
[CLK_19_2_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_19_2_no_ssc_tx_ln_vals,
},
},
},
[CLK_25_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_25_no_ssc_tx_ln_vals,
},
},
},
[CLK_100_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_100_no_ssc_tx_ln_vals,
},
},
[TYPE_PCIE] = {
[TYPE_NONE] = {
[NO_SSC] = NULL,
......@@ -4047,7 +4344,28 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
},
},
},
},
.rx_ln_vals = {
[CLK_19_2_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_19_2_no_ssc_rx_ln_vals,
},
},
},
[CLK_25_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_25_no_ssc_rx_ln_vals,
},
},
},
[CLK_100_MHZ] = {
[TYPE_DP] = {
[TYPE_NONE] = {
[NO_SSC] = &sl_dp_100_no_ssc_rx_ln_vals,
},
},
[TYPE_PCIE] = {
[TYPE_NONE] = {
[NO_SSC] = &pcie_100_no_ssc_rx_ln_vals,
......@@ -4123,6 +4441,7 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = {
},
},
},
},
};
static const struct of_device_id cdns_torrent_phy_of_match[] = {
......
......@@ -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)) {
......
......@@ -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;
......
......@@ -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,
}
}
static int mtk_phy_init(struct phy *phy)
/* type switch for usb3/pcie/sgmii/sata */
static int phy_type_syscon_get(struct mtk_phy_instance *instance,
struct device_node *dn)
{
struct mtk_phy_instance *instance = phy_get_drvdata(phy);
struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
struct of_phandle_args args;
int ret;
ret = clk_prepare_enable(instance->ref_clk);
if (ret) {
dev_err(tphy->dev, "failed to enable ref_clk\n");
/* 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;
}
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);
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_bulk_prepare_enable(TPHY_CLKS_CNT, instance->clks);
if (ret)
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)
}
}
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);
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,21 +1315,17 @@ 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);
......
......@@ -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;
}
......
......@@ -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,
},
{ }
};
......
......@@ -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
......
// SPDX-License-Identifier: GPL-2.0-only
/**
/*
* Copyright (C) 2016 Linaro Ltd
*/
#include <linux/module.h>
......
......@@ -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);
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);
......
......@@ -1180,9 +1180,11 @@ 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);
return PTR_ERR_OR_ZERO(provider);
......
......@@ -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
......
/* 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_ */
// 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,
};
......@@ -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,
},
{},
};
......
......@@ -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_ */
......@@ -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);
......
......@@ -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;
}
......
......@@ -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
......
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