mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
Merge tag 'phy-for-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy
Pull phy updates from Vinod Koul:
"A fairly moderate sized request for the generic phy subsystem with
some new device and driver support along with driver updates with
Samsung and Qualcomm ones being major ones.
New HW Support:
- Qualcomm X1P42100 PCIe Gen4x4, QCS615 qmp usbc, PCIe UNIPHY 28LP
driver, SM8750 QMP UFS PHY
- Rockchip rk3576 hdptx, rk3562 naneng-combo support
- Samsung MIPI D-/C-PHY driver, ExynosAutov920 ufs phy driver
Updates:
- Samsung USB3 Type-C lane orientation detection and configuration
for Google gs101
- Qualcomm support for dual lane PHY support for QCS8300 SoC"
* tag 'phy-for-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (47 commits)
phy: rockchip-naneng-combo: Support rk3562
dt-bindings: phy: rockchip: Add rk3562 naneng-combophy compatible
phy: rockchip: Add Samsung MIPI D-/C-PHY driver
dt-bindings: phy: Add Rockchip MIPI C-/D-PHY schema
phy: qcom: uniphy-28lp: add COMMON_CLK dependency
phy: rockchip: usbdp: Remove unnecessary bool conversion
phy: rockchip: usbdp: Avoid call hpd_event_trigger in dp_phy_init
phy: rockchip: usbdp: Only verify link rates/lanes/voltage when the corresponding set flags are set
phy: qcom-qmp-pcie: add dual lane PHY support for QCS8300
dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: Document the QCS8300 QMP PCIe PHY Gen4 x2
phy: qcom-qmp-ufs: Add PHY Configuration support for sm8750
dt-bindings: phy: qcom,sc8280xp-qmp-ufs-phy: document the SM8750 QMP UFS PHY
phy: qcom: Introduce PCIe UNIPHY 28LP driver
dt-bindings: phy: qcom,uniphy-pcie: Document PCIe uniphy
phy: qcom: qmp-usbc: Add qmp configuration for QCS615
phy: freescale: imx8m-pcie: assert phy reset and perst in power off
phy: freescale: imx8m-pcie: cleanup reset logic
phy: core: Remove unused phy_pm_runtime_(allow|forbid)
dt-bindings: phy: document Allwinner A523 USB-2.0 PHY
phy: phy-rockchip-samsung-hdptx: Add support for RK3576
...
This commit is contained in:
@@ -20,7 +20,9 @@ properties:
|
||||
- allwinner,sun20i-d1-usb-phy
|
||||
- allwinner,sun50i-a64-usb-phy
|
||||
- items:
|
||||
- const: allwinner,sun50i-a100-usb-phy
|
||||
- enum:
|
||||
- allwinner,sun50i-a100-usb-phy
|
||||
- allwinner,sun55i-a523-usb-phy
|
||||
- const: allwinner,sun20i-d1-usb-phy
|
||||
|
||||
reg:
|
||||
|
||||
@@ -12,6 +12,7 @@ maintainers:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- rockchip,rk3562-naneng-combphy
|
||||
- rockchip,rk3568-naneng-combphy
|
||||
- rockchip,rk3576-naneng-combphy
|
||||
- rockchip,rk3588-naneng-combphy
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/qcom,ipq5332-uniphy-pcie-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm UNIPHY PCIe 28LP PHY
|
||||
|
||||
maintainers:
|
||||
- Nitheesh Sekar <quic_nsekar@quicinc.com>
|
||||
- Varadarajan Narayanan <quic_varada@quicinc.com>
|
||||
|
||||
description:
|
||||
PCIe and USB combo PHY found in Qualcomm IPQ5332 SoC
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,ipq5332-uniphy-pcie-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: pcie pipe clock
|
||||
- description: pcie ahb clock
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: phy reset
|
||||
- description: ahb reset
|
||||
- description: cfg reset
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
num-lanes:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [1, 2]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- resets
|
||||
- "#phy-cells"
|
||||
- "#clock-cells"
|
||||
- num-lanes
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,ipq5332-gcc.h>
|
||||
|
||||
pcie0_phy: phy@4b0000 {
|
||||
compatible = "qcom,ipq5332-uniphy-pcie-phy";
|
||||
reg = <0x004b0000 0x800>;
|
||||
|
||||
clocks = <&gcc GCC_PCIE3X1_0_PIPE_CLK>,
|
||||
<&gcc GCC_PCIE3X1_PHY_AHB_CLK>;
|
||||
|
||||
resets = <&gcc GCC_PCIE3X1_0_PHY_BCR>,
|
||||
<&gcc GCC_PCIE3X1_PHY_AHB_CLK_ARES>,
|
||||
<&gcc GCC_PCIE3X1_0_PHY_PHY_BCR>;
|
||||
|
||||
#clock-cells = <0>;
|
||||
|
||||
#phy-cells = <0>;
|
||||
|
||||
num-lanes = <1>;
|
||||
};
|
||||
@@ -17,6 +17,7 @@ properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,qcs615-qmp-gen3x1-pcie-phy
|
||||
- qcom,qcs8300-qmp-gen4x2-pcie-phy
|
||||
- qcom,sa8775p-qmp-gen4x2-pcie-phy
|
||||
- qcom,sa8775p-qmp-gen4x4-pcie-phy
|
||||
- qcom,sar2130p-qmp-gen3x2-pcie-phy
|
||||
@@ -45,6 +46,7 @@ properties:
|
||||
- qcom,x1e80100-qmp-gen4x2-pcie-phy
|
||||
- qcom,x1e80100-qmp-gen4x4-pcie-phy
|
||||
- qcom,x1e80100-qmp-gen4x8-pcie-phy
|
||||
- qcom,x1p42100-qmp-gen4x4-pcie-phy
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
@@ -124,6 +126,7 @@ allOf:
|
||||
enum:
|
||||
- qcom,sc8280xp-qmp-gen3x4-pcie-phy
|
||||
- qcom,x1e80100-qmp-gen4x4-pcie-phy
|
||||
- qcom,x1p42100-qmp-gen4x4-pcie-phy
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
@@ -180,6 +183,7 @@ allOf:
|
||||
- qcom,x1e80100-qmp-gen4x2-pcie-phy
|
||||
- qcom,x1e80100-qmp-gen4x4-pcie-phy
|
||||
- qcom,x1e80100-qmp-gen4x8-pcie-phy
|
||||
- qcom,x1p42100-qmp-gen4x4-pcie-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
@@ -192,6 +196,7 @@ allOf:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,qcs8300-qmp-gen4x2-pcie-phy
|
||||
- qcom,sa8775p-qmp-gen4x2-pcie-phy
|
||||
- qcom,sa8775p-qmp-gen4x4-pcie-phy
|
||||
then:
|
||||
@@ -217,12 +222,6 @@ allOf:
|
||||
minItems: 2
|
||||
reset-names:
|
||||
minItems: 2
|
||||
else:
|
||||
properties:
|
||||
resets:
|
||||
maxItems: 1
|
||||
reset-names:
|
||||
maxItems: 1
|
||||
|
||||
- if:
|
||||
properties:
|
||||
|
||||
@@ -44,6 +44,7 @@ properties:
|
||||
- qcom,sm8475-qmp-ufs-phy
|
||||
- qcom,sm8550-qmp-ufs-phy
|
||||
- qcom,sm8650-qmp-ufs-phy
|
||||
- qcom,sm8750-qmp-ufs-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@@ -111,6 +112,7 @@ allOf:
|
||||
- qcom,sm8475-qmp-ufs-phy
|
||||
- qcom,sm8550-qmp-ufs-phy
|
||||
- qcom,sm8650-qmp-ufs-phy
|
||||
- qcom,sm8750-qmp-ufs-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
|
||||
@@ -11,8 +11,13 @@ maintainers:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- rockchip,rk3588-hdptx-phy
|
||||
oneOf:
|
||||
- enum:
|
||||
- rockchip,rk3588-hdptx-phy
|
||||
- items:
|
||||
- enum:
|
||||
- rockchip,rk3576-hdptx-phy
|
||||
- const: rockchip,rk3588-hdptx-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@@ -34,24 +39,12 @@ properties:
|
||||
const: 0
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: PHY reset line
|
||||
- description: APB reset line
|
||||
- description: INIT reset line
|
||||
- description: CMN reset line
|
||||
- description: LANE reset line
|
||||
- description: ROPLL reset line
|
||||
- description: LCPLL reset line
|
||||
minItems: 4
|
||||
maxItems: 7
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: phy
|
||||
- const: apb
|
||||
- const: init
|
||||
- const: cmn
|
||||
- const: lane
|
||||
- const: ropll
|
||||
- const: lcpll
|
||||
minItems: 4
|
||||
maxItems: 7
|
||||
|
||||
rockchip,grf:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
@@ -67,6 +60,39 @@ required:
|
||||
- reset-names
|
||||
- rockchip,grf
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- rockchip,rk3576-hdptx-phy
|
||||
then:
|
||||
properties:
|
||||
resets:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
reset-names:
|
||||
items:
|
||||
- const: apb
|
||||
- const: init
|
||||
- const: cmn
|
||||
- const: lane
|
||||
else:
|
||||
properties:
|
||||
resets:
|
||||
minItems: 7
|
||||
maxItems: 7
|
||||
reset-names:
|
||||
items:
|
||||
- const: phy
|
||||
- const: apb
|
||||
- const: init
|
||||
- const: cmn
|
||||
- const: lane
|
||||
- const: ropll
|
||||
- const: lcpll
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/rockchip,rk3588-mipi-dcphy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rockchip MIPI D-/C-PHY with Samsung IP block
|
||||
|
||||
maintainers:
|
||||
- Guochun Huang <hero.huang@rock-chips.com>
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- rockchip,rk3576-mipi-dcphy
|
||||
- rockchip,rk3588-mipi-dcphy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#phy-cells":
|
||||
const: 1
|
||||
description: |
|
||||
Argument is mode to operate in. Supported modes are:
|
||||
- PHY_TYPE_DPHY
|
||||
- PHY_TYPE_CPHY
|
||||
See include/dt-bindings/phy/phy.h for constants.
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: pclk
|
||||
- const: ref
|
||||
|
||||
resets:
|
||||
maxItems: 4
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: m_phy
|
||||
- const: apb
|
||||
- const: grf
|
||||
- const: s_phy
|
||||
|
||||
rockchip,grf:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to the syscon managing the 'mipi dcphy general register files'.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- reset-names
|
||||
- "#phy-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/rockchip,rk3588-cru.h>
|
||||
#include <dt-bindings/reset/rockchip,rk3588-cru.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
phy@feda0000 {
|
||||
compatible = "rockchip,rk3588-mipi-dcphy";
|
||||
reg = <0x0 0xfeda0000 0x0 0x10000>;
|
||||
clocks = <&cru PCLK_MIPI_DCPHY0>,
|
||||
<&cru CLK_USBDPPHY_MIPIDCPPHY_REF>;
|
||||
clock-names = "pclk", "ref";
|
||||
resets = <&cru SRST_M_MIPI_DCPHY0>,
|
||||
<&cru SRST_P_MIPI_DCPHY0>,
|
||||
<&cru SRST_P_MIPI_DCPHY0_GRF>,
|
||||
<&cru SRST_S_MIPI_DCPHY0>;
|
||||
reset-names = "m_phy", "apb", "grf", "s_phy";
|
||||
rockchip,grf = <&mipidcphy0_grf>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
};
|
||||
@@ -18,6 +18,7 @@ properties:
|
||||
- google,gs101-ufs-phy
|
||||
- samsung,exynos7-ufs-phy
|
||||
- samsung,exynosautov9-ufs-phy
|
||||
- samsung,exynosautov920-ufs-phy
|
||||
- tesla,fsd-ufs-phy
|
||||
|
||||
reg:
|
||||
|
||||
@@ -83,14 +83,19 @@ properties:
|
||||
|
||||
pll-supply:
|
||||
description: Power supply for the USB PLL.
|
||||
|
||||
dvdd-usb20-supply:
|
||||
description: DVDD power supply for the USB 2.0 phy.
|
||||
|
||||
vddh-usb20-supply:
|
||||
description: VDDh power supply for the USB 2.0 phy.
|
||||
|
||||
vdd33-usb20-supply:
|
||||
description: 3.3V power supply for the USB 2.0 phy.
|
||||
|
||||
vdda-usbdp-supply:
|
||||
description: VDDa power supply for the USB DP phy.
|
||||
|
||||
vddh-usbdp-supply:
|
||||
description: VDDh power supply for the USB DP phy.
|
||||
|
||||
@@ -109,6 +114,8 @@ allOf:
|
||||
contains:
|
||||
const: google,gs101-usb31drd-phy
|
||||
then:
|
||||
$ref: /schemas/usb/usb-switch.yaml#
|
||||
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
@@ -117,6 +124,7 @@ allOf:
|
||||
- description: Gate of control interface AXI clock
|
||||
- description: Gate of control interface APB clock
|
||||
- description: Gate of SCL APB clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: phy
|
||||
@@ -124,12 +132,17 @@ allOf:
|
||||
- const: ctrl_aclk
|
||||
- const: ctrl_pclk
|
||||
- const: scl_pclk
|
||||
|
||||
reg:
|
||||
minItems: 3
|
||||
|
||||
reg-names:
|
||||
minItems: 3
|
||||
|
||||
required:
|
||||
- reg-names
|
||||
- orientation-switch
|
||||
- port
|
||||
- pll-supply
|
||||
- dvdd-usb20-supply
|
||||
- vddh-usb20-supply
|
||||
@@ -149,6 +162,7 @@ allOf:
|
||||
clocks:
|
||||
minItems: 5
|
||||
maxItems: 5
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: phy
|
||||
@@ -156,8 +170,10 @@ allOf:
|
||||
- const: phy_utmi
|
||||
- const: phy_pipe
|
||||
- const: itp
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
reg-names:
|
||||
maxItems: 1
|
||||
|
||||
@@ -174,16 +190,19 @@ allOf:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: phy
|
||||
- const: ref
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
reg-names:
|
||||
maxItems: 1
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
@@ -198,8 +198,7 @@ pm_runtime_get_sync of PHY provider device because of parent-child relationship.
|
||||
It should also be noted that phy_power_on and phy_power_off performs
|
||||
phy_pm_runtime_get_sync and phy_pm_runtime_put respectively.
|
||||
There are exported APIs like phy_pm_runtime_get, phy_pm_runtime_get_sync,
|
||||
phy_pm_runtime_put, phy_pm_runtime_put_sync, phy_pm_runtime_allow and
|
||||
phy_pm_runtime_forbid for performing PM operations.
|
||||
phy_pm_runtime_put and phy_pm_runtime_put_sync for performing PM operations.
|
||||
|
||||
PHY Mappings
|
||||
============
|
||||
|
||||
@@ -5,6 +5,7 @@ if (ARCH_MXC && ARM64) || COMPILE_TEST
|
||||
config PHY_FSL_IMX8MQ_USB
|
||||
tristate "Freescale i.MX8M USB3 PHY"
|
||||
depends on OF && HAS_IOMEM
|
||||
depends on TYPEC || TYPEC=n
|
||||
select GENERIC_PHY
|
||||
default ARCH_MXC && ARM64
|
||||
|
||||
|
||||
@@ -141,15 +141,9 @@ static int imx8_pcie_phy_power_on(struct phy *phy)
|
||||
IMX8MM_GPR_PCIE_REF_CLK_PLL);
|
||||
usleep_range(100, 200);
|
||||
|
||||
switch (imx8_phy->drvdata->variant) {
|
||||
case IMX8MP:
|
||||
reset_control_deassert(imx8_phy->perst);
|
||||
fallthrough;
|
||||
case IMX8MM:
|
||||
reset_control_deassert(imx8_phy->reset);
|
||||
usleep_range(200, 500);
|
||||
break;
|
||||
}
|
||||
reset_control_deassert(imx8_phy->perst);
|
||||
reset_control_deassert(imx8_phy->reset);
|
||||
usleep_range(200, 500);
|
||||
|
||||
/* Do the PHY common block reset */
|
||||
regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
|
||||
@@ -162,6 +156,16 @@ static int imx8_pcie_phy_power_on(struct phy *phy)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx8_pcie_phy_power_off(struct phy *phy)
|
||||
{
|
||||
struct imx8_pcie_phy *imx8_phy = phy_get_drvdata(phy);
|
||||
|
||||
reset_control_assert(imx8_phy->reset);
|
||||
reset_control_assert(imx8_phy->perst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx8_pcie_phy_init(struct phy *phy)
|
||||
{
|
||||
struct imx8_pcie_phy *imx8_phy = phy_get_drvdata(phy);
|
||||
@@ -182,6 +186,7 @@ static const struct phy_ops imx8_pcie_phy_ops = {
|
||||
.init = imx8_pcie_phy_init,
|
||||
.exit = imx8_pcie_phy_exit,
|
||||
.power_on = imx8_pcie_phy_power_on,
|
||||
.power_off = imx8_pcie_phy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/usb/typec_mux.h>
|
||||
|
||||
#define PHY_CTRL0 0x0
|
||||
#define PHY_CTRL0_REF_SSP_EN BIT(2)
|
||||
@@ -50,11 +51,66 @@
|
||||
|
||||
#define PHY_TUNE_DEFAULT 0xffffffff
|
||||
|
||||
#define TCA_CLK_RST 0x00
|
||||
#define TCA_CLK_RST_SW BIT(9)
|
||||
#define TCA_CLK_RST_REF_CLK_EN BIT(1)
|
||||
#define TCA_CLK_RST_SUSPEND_CLK_EN BIT(0)
|
||||
|
||||
#define TCA_INTR_EN 0x04
|
||||
#define TCA_INTR_STS 0x08
|
||||
|
||||
#define TCA_GCFG 0x10
|
||||
#define TCA_GCFG_ROLE_HSTDEV BIT(4)
|
||||
#define TCA_GCFG_OP_MODE GENMASK(1, 0)
|
||||
#define TCA_GCFG_OP_MODE_SYSMODE 0
|
||||
#define TCA_GCFG_OP_MODE_SYNCMODE 1
|
||||
|
||||
#define TCA_TCPC 0x14
|
||||
#define TCA_TCPC_VALID BIT(4)
|
||||
#define TCA_TCPC_LOW_POWER_EN BIT(3)
|
||||
#define TCA_TCPC_ORIENTATION_NORMAL BIT(2)
|
||||
#define TCA_TCPC_MUX_CONTRL GENMASK(1, 0)
|
||||
#define TCA_TCPC_MUX_CONTRL_NO_CONN 0
|
||||
#define TCA_TCPC_MUX_CONTRL_USB_CONN 1
|
||||
|
||||
#define TCA_SYSMODE_CFG 0x18
|
||||
#define TCA_SYSMODE_TCPC_DISABLE BIT(3)
|
||||
#define TCA_SYSMODE_TCPC_FLIP BIT(2)
|
||||
|
||||
#define TCA_CTRLSYNCMODE_CFG0 0x20
|
||||
#define TCA_CTRLSYNCMODE_CFG1 0x20
|
||||
|
||||
#define TCA_PSTATE 0x30
|
||||
#define TCA_PSTATE_CM_STS BIT(4)
|
||||
#define TCA_PSTATE_TX_STS BIT(3)
|
||||
#define TCA_PSTATE_RX_PLL_STS BIT(2)
|
||||
#define TCA_PSTATE_PIPE0_POWER_DOWN GENMASK(1, 0)
|
||||
|
||||
#define TCA_GEN_STATUS 0x34
|
||||
#define TCA_GEN_DEV_POR BIT(12)
|
||||
#define TCA_GEN_REF_CLK_SEL BIT(8)
|
||||
#define TCA_GEN_TYPEC_FLIP_INVERT BIT(4)
|
||||
#define TCA_GEN_PHY_TYPEC_DISABLE BIT(3)
|
||||
#define TCA_GEN_PHY_TYPEC_FLIP BIT(2)
|
||||
|
||||
#define TCA_VBUS_CTRL 0x40
|
||||
#define TCA_VBUS_STATUS 0x44
|
||||
|
||||
#define TCA_INFO 0xfc
|
||||
|
||||
struct tca_blk {
|
||||
struct typec_switch_dev *sw;
|
||||
void __iomem *base;
|
||||
struct mutex mutex;
|
||||
enum typec_orientation orientation;
|
||||
};
|
||||
|
||||
struct imx8mq_usb_phy {
|
||||
struct phy *phy;
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
struct regulator *vbus;
|
||||
struct tca_blk *tca;
|
||||
u32 pcs_tx_swing_full;
|
||||
u32 pcs_tx_deemph_3p5db;
|
||||
u32 tx_vref_tune;
|
||||
@@ -64,6 +120,172 @@ struct imx8mq_usb_phy {
|
||||
u32 comp_dis_tune;
|
||||
};
|
||||
|
||||
|
||||
static void tca_blk_orientation_set(struct tca_blk *tca,
|
||||
enum typec_orientation orientation);
|
||||
|
||||
#ifdef CONFIG_TYPEC
|
||||
|
||||
static int tca_blk_typec_switch_set(struct typec_switch_dev *sw,
|
||||
enum typec_orientation orientation)
|
||||
{
|
||||
struct imx8mq_usb_phy *imx_phy = typec_switch_get_drvdata(sw);
|
||||
struct tca_blk *tca = imx_phy->tca;
|
||||
int ret;
|
||||
|
||||
if (tca->orientation == orientation)
|
||||
return 0;
|
||||
|
||||
ret = clk_prepare_enable(imx_phy->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tca_blk_orientation_set(tca, orientation);
|
||||
clk_disable_unprepare(imx_phy->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct typec_switch_dev *tca_blk_get_typec_switch(struct platform_device *pdev,
|
||||
struct imx8mq_usb_phy *imx_phy)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct typec_switch_dev *sw;
|
||||
struct typec_switch_desc sw_desc = { };
|
||||
|
||||
sw_desc.drvdata = imx_phy;
|
||||
sw_desc.fwnode = dev->fwnode;
|
||||
sw_desc.set = tca_blk_typec_switch_set;
|
||||
sw_desc.name = NULL;
|
||||
|
||||
sw = typec_switch_register(dev, &sw_desc);
|
||||
if (IS_ERR(sw)) {
|
||||
dev_err(dev, "Error register tca orientation switch: %ld",
|
||||
PTR_ERR(sw));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sw;
|
||||
}
|
||||
|
||||
static void tca_blk_put_typec_switch(struct typec_switch_dev *sw)
|
||||
{
|
||||
typec_switch_unregister(sw);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static struct typec_switch_dev *tca_blk_get_typec_switch(struct platform_device *pdev,
|
||||
struct imx8mq_usb_phy *imx_phy)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void tca_blk_put_typec_switch(struct typec_switch_dev *sw) {}
|
||||
|
||||
#endif /* CONFIG_TYPEC */
|
||||
|
||||
static void tca_blk_orientation_set(struct tca_blk *tca,
|
||||
enum typec_orientation orientation)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
mutex_lock(&tca->mutex);
|
||||
|
||||
if (orientation == TYPEC_ORIENTATION_NONE) {
|
||||
/*
|
||||
* use Controller Synced Mode for TCA low power enable and
|
||||
* put PHY to USB safe state.
|
||||
*/
|
||||
val = FIELD_PREP(TCA_GCFG_OP_MODE, TCA_GCFG_OP_MODE_SYNCMODE);
|
||||
writel(val, tca->base + TCA_GCFG);
|
||||
|
||||
val = TCA_TCPC_VALID | TCA_TCPC_LOW_POWER_EN;
|
||||
writel(val, tca->base + TCA_TCPC);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* use System Configuration Mode for TCA mux control. */
|
||||
val = FIELD_PREP(TCA_GCFG_OP_MODE, TCA_GCFG_OP_MODE_SYSMODE);
|
||||
writel(val, tca->base + TCA_GCFG);
|
||||
|
||||
/* Disable TCA module */
|
||||
val = readl(tca->base + TCA_SYSMODE_CFG);
|
||||
val |= TCA_SYSMODE_TCPC_DISABLE;
|
||||
writel(val, tca->base + TCA_SYSMODE_CFG);
|
||||
|
||||
if (orientation == TYPEC_ORIENTATION_REVERSE)
|
||||
val |= TCA_SYSMODE_TCPC_FLIP;
|
||||
else if (orientation == TYPEC_ORIENTATION_NORMAL)
|
||||
val &= ~TCA_SYSMODE_TCPC_FLIP;
|
||||
|
||||
writel(val, tca->base + TCA_SYSMODE_CFG);
|
||||
|
||||
/* Enable TCA module */
|
||||
val &= ~TCA_SYSMODE_TCPC_DISABLE;
|
||||
writel(val, tca->base + TCA_SYSMODE_CFG);
|
||||
|
||||
out:
|
||||
tca->orientation = orientation;
|
||||
mutex_unlock(&tca->mutex);
|
||||
}
|
||||
|
||||
static void tca_blk_init(struct tca_blk *tca)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* reset XBar block */
|
||||
val = readl(tca->base + TCA_CLK_RST);
|
||||
val &= ~TCA_CLK_RST_SW;
|
||||
writel(val, tca->base + TCA_CLK_RST);
|
||||
|
||||
udelay(100);
|
||||
|
||||
/* clear reset */
|
||||
val |= TCA_CLK_RST_SW;
|
||||
writel(val, tca->base + TCA_CLK_RST);
|
||||
|
||||
tca_blk_orientation_set(tca, tca->orientation);
|
||||
}
|
||||
|
||||
static struct tca_blk *imx95_usb_phy_get_tca(struct platform_device *pdev,
|
||||
struct imx8mq_usb_phy *imx_phy)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
struct tca_blk *tca;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
tca = devm_kzalloc(dev, sizeof(*tca), GFP_KERNEL);
|
||||
if (!tca)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
tca->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(tca->base))
|
||||
return ERR_CAST(tca->base);
|
||||
|
||||
mutex_init(&tca->mutex);
|
||||
|
||||
tca->orientation = TYPEC_ORIENTATION_NORMAL;
|
||||
tca->sw = tca_blk_get_typec_switch(pdev, imx_phy);
|
||||
|
||||
return tca;
|
||||
}
|
||||
|
||||
static void imx95_usb_phy_put_tca(struct imx8mq_usb_phy *imx_phy)
|
||||
{
|
||||
struct tca_blk *tca = imx_phy->tca;
|
||||
|
||||
if (!tca)
|
||||
return;
|
||||
|
||||
tca_blk_put_typec_switch(tca->sw);
|
||||
}
|
||||
|
||||
static u32 phy_tx_vref_tune_from_property(u32 percent)
|
||||
{
|
||||
percent = clamp(percent, 94U, 124U);
|
||||
@@ -315,6 +537,9 @@ static int imx8mp_usb_phy_init(struct phy *phy)
|
||||
|
||||
imx8m_phy_tune(imx_phy);
|
||||
|
||||
if (imx_phy->tca)
|
||||
tca_blk_init(imx_phy->tca);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -359,6 +584,8 @@ static const struct of_device_id imx8mq_usb_phy_of_match[] = {
|
||||
.data = &imx8mq_usb_phy_ops,},
|
||||
{.compatible = "fsl,imx8mp-usb-phy",
|
||||
.data = &imx8mp_usb_phy_ops,},
|
||||
{.compatible = "fsl,imx95-usb-phy",
|
||||
.data = &imx8mp_usb_phy_ops,},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx8mq_usb_phy_of_match);
|
||||
@@ -398,6 +625,11 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
|
||||
|
||||
phy_set_drvdata(imx_phy->phy, imx_phy);
|
||||
|
||||
imx_phy->tca = imx95_usb_phy_get_tca(pdev, imx_phy);
|
||||
if (IS_ERR(imx_phy->tca))
|
||||
return dev_err_probe(dev, PTR_ERR(imx_phy->tca),
|
||||
"failed to get tca\n");
|
||||
|
||||
imx8m_get_phy_tuning_data(imx_phy);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
@@ -405,8 +637,16 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
|
||||
return PTR_ERR_OR_ZERO(phy_provider);
|
||||
}
|
||||
|
||||
static void imx8mq_usb_phy_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct imx8mq_usb_phy *imx_phy = platform_get_drvdata(pdev);
|
||||
|
||||
imx95_usb_phy_put_tca(imx_phy);
|
||||
}
|
||||
|
||||
static struct platform_driver imx8mq_usb_phy_driver = {
|
||||
.probe = imx8mq_usb_phy_probe,
|
||||
.remove = imx8mq_usb_phy_remove,
|
||||
.driver = {
|
||||
.name = "imx8mq-usb-phy",
|
||||
.of_match_table = imx8mq_usb_phy_of_match,
|
||||
|
||||
@@ -668,7 +668,7 @@ static int fsl_samsung_hdmi_phy_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(phy->regs))
|
||||
return PTR_ERR(phy->regs);
|
||||
|
||||
phy->apbclk = devm_clk_get(phy->dev, "apb");
|
||||
phy->apbclk = devm_clk_get_enabled(phy->dev, "apb");
|
||||
if (IS_ERR(phy->apbclk))
|
||||
return dev_err_probe(phy->dev, PTR_ERR(phy->apbclk),
|
||||
"failed to get apb clk\n");
|
||||
@@ -678,12 +678,6 @@ static int fsl_samsung_hdmi_phy_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(phy->dev, PTR_ERR(phy->refclk),
|
||||
"failed to get ref clk\n");
|
||||
|
||||
ret = clk_prepare_enable(phy->apbclk);
|
||||
if (ret) {
|
||||
dev_err(phy->dev, "failed to enable apbclk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_runtime_get_noresume(phy->dev);
|
||||
pm_runtime_set_active(phy->dev);
|
||||
pm_runtime_enable(phy->dev);
|
||||
@@ -699,8 +693,6 @@ static int fsl_samsung_hdmi_phy_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
register_clk_failed:
|
||||
clk_disable_unprepare(phy->apbclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1195,7 +1195,7 @@ static int phy_type_syscon_get(struct mtk_phy_instance *instance,
|
||||
int ret;
|
||||
|
||||
/* type switch function is optional */
|
||||
if (!of_property_read_bool(dn, "mediatek,syscon-type"))
|
||||
if (!of_property_present(dn, "mediatek,syscon-type"))
|
||||
return 0;
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type",
|
||||
@@ -1258,7 +1258,7 @@ static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instanc
|
||||
}
|
||||
|
||||
/* software efuse is optional */
|
||||
instance->efuse_sw_en = device_property_read_bool(dev, "nvmem-cells");
|
||||
instance->efuse_sw_en = device_property_present(dev, "nvmem-cells");
|
||||
if (!instance->efuse_sw_en)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ config PHY_SPARX5_SERDES
|
||||
config PHY_LAN966X_SERDES
|
||||
tristate "SerDes PHY driver for Microchip LAN966X"
|
||||
select GENERIC_PHY
|
||||
depends on SOC_LAN966 || MCHP_LAN966X_PCI || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on MFD_SYSCON
|
||||
help
|
||||
|
||||
@@ -103,6 +103,7 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
|
||||
struct phy *phy;
|
||||
struct gpio_desc *standby_gpio;
|
||||
struct gpio_desc *enable_gpio;
|
||||
struct mux_state *mux_state;
|
||||
u32 max_bitrate = 0;
|
||||
int err;
|
||||
|
||||
@@ -113,13 +114,11 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
|
||||
match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node);
|
||||
drvdata = match->data;
|
||||
|
||||
if (of_property_read_bool(dev->of_node, "mux-states")) {
|
||||
struct mux_state *mux_state;
|
||||
|
||||
mux_state = devm_mux_state_get(dev, NULL);
|
||||
if (IS_ERR(mux_state))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(mux_state),
|
||||
"failed to get mux\n");
|
||||
mux_state = devm_mux_state_get(dev, NULL);
|
||||
if (IS_ERR(mux_state)) {
|
||||
if (PTR_ERR(mux_state) == -EPROBE_DEFER)
|
||||
return PTR_ERR(mux_state);
|
||||
} else {
|
||||
can_transceiver_phy->mux_state = mux_state;
|
||||
}
|
||||
|
||||
|
||||
@@ -214,30 +214,6 @@ int phy_pm_runtime_put_sync(struct phy *phy)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_pm_runtime_put_sync);
|
||||
|
||||
void phy_pm_runtime_allow(struct phy *phy)
|
||||
{
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
if (!pm_runtime_enabled(&phy->dev))
|
||||
return;
|
||||
|
||||
pm_runtime_allow(&phy->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_pm_runtime_allow);
|
||||
|
||||
void phy_pm_runtime_forbid(struct phy *phy)
|
||||
{
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
if (!pm_runtime_enabled(&phy->dev))
|
||||
return;
|
||||
|
||||
pm_runtime_forbid(&phy->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_pm_runtime_forbid);
|
||||
|
||||
/**
|
||||
* phy_init - phy internal initialization before phy operation
|
||||
* @phy: the phy returned by phy_get()
|
||||
@@ -405,13 +381,14 @@ EXPORT_SYMBOL_GPL(phy_power_off);
|
||||
|
||||
int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (!phy || !phy->ops->set_mode)
|
||||
if (!phy)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&phy->mutex);
|
||||
ret = phy->ops->set_mode(phy, mode, submode);
|
||||
if (phy->ops->set_mode)
|
||||
ret = phy->ops->set_mode(phy, mode, submode);
|
||||
if (!ret)
|
||||
phy->attrs.mode = mode;
|
||||
mutex_unlock(&phy->mutex);
|
||||
|
||||
@@ -154,6 +154,19 @@ config PHY_QCOM_M31_USB
|
||||
management. This driver is required even for peripheral only or
|
||||
host only mode configurations.
|
||||
|
||||
config PHY_QCOM_UNIPHY_PCIE_28LP
|
||||
bool "PCIE UNIPHY 28LP PHY driver"
|
||||
depends on ARCH_QCOM
|
||||
depends on COMMON_CLK
|
||||
depends on HAS_IOMEM
|
||||
depends on OF
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support the PCIe UNIPHY 28LP phy transceiver that
|
||||
is used with PCIe controllers on Qualcomm IPQ5332 chips. It
|
||||
handles PHY initialization, clock management required after
|
||||
resetting the hardware and power management.
|
||||
|
||||
config PHY_QCOM_USB_HS
|
||||
tristate "Qualcomm USB HS PHY module"
|
||||
depends on USB_ULPI_BUS
|
||||
|
||||
@@ -17,6 +17,7 @@ obj-$(CONFIG_PHY_QCOM_QMP_USB_LEGACY) += phy-qcom-qmp-usb-legacy.o
|
||||
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
|
||||
obj-$(CONFIG_PHY_QCOM_SNPS_EUSB2) += phy-qcom-snps-eusb2.o
|
||||
obj-$(CONFIG_PHY_QCOM_EUSB2_REPEATER) += phy-qcom-eusb2-repeater.o
|
||||
obj-$(CONFIG_PHY_QCOM_UNIPHY_PCIE_28LP) += phy-qcom-uniphy-pcie-28lp.o
|
||||
obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o
|
||||
obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o
|
||||
obj-$(CONFIG_PHY_QCOM_USB_HS_28NM) += phy-qcom-usb-hs-28nm.o
|
||||
|
||||
@@ -805,6 +805,58 @@ static const struct qmp_phy_init_tbl qcs615_pcie_pcs_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QPHY_V2_PCS_TXDEEMPH_M3P5DB_V0, 0xe),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl qcs8300_qmp_gen4x2_pcie_rx_alt_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_PI_CONTROLS, 0x16),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B0, 0x9b),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B1, 0xb0),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B2, 0xd2),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B3, 0xf0),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B4, 0x42),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B5, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B6, 0x20),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B0, 0x9b),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B1, 0xfb),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B2, 0xd2),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B3, 0xec),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B4, 0x43),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B5, 0xdd),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B6, 0x0d),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B0, 0xf3),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B1, 0xf8),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B2, 0xec),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B3, 0xd6),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B4, 0x83),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B5, 0xf5),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B6, 0x5e),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_PHPRE_CTRL, 0x20),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_0_1, 0x3f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_2_3, 0x37),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_3, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE3, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH2_RATE3, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH3_RATE3, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH4_RATE3, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH5_RATE3, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH6_RATE3, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE210, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH2_RATE210, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH3_RATE210, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_Q_PI_INTRINSIC_BIAS_RATE32, 0x09),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE2, 0x0c),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE3, 0x08),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_SO_GAIN_RATE3, 0x04),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_VGA_CAL_CNTRL1, 0x04),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_VGA_CAL_MAN_VAL, 0x08),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0b),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x7c),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_IDAC_SAOFFSET, 0x10),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_DAC_ENABLE1, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_GM_CAL, 0x05),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH1, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH2, 0x1f),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl sdm845_qmp_pcie_serdes_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x14),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
|
||||
@@ -3336,6 +3388,40 @@ static const struct qmp_phy_cfg qcs615_pciephy_cfg = {
|
||||
.phy_status = PHYSTATUS,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg qcs8300_qmp_gen4x2_pciephy_cfg = {
|
||||
.lanes = 2,
|
||||
.offsets = &qmp_pcie_offsets_v5_20,
|
||||
|
||||
.tbls = {
|
||||
.serdes = sa8775p_qmp_gen4x2_pcie_serdes_alt_tbl,
|
||||
.serdes_num = ARRAY_SIZE(sa8775p_qmp_gen4x2_pcie_serdes_alt_tbl),
|
||||
.tx = sa8775p_qmp_gen4_pcie_tx_tbl,
|
||||
.tx_num = ARRAY_SIZE(sa8775p_qmp_gen4_pcie_tx_tbl),
|
||||
.rx = qcs8300_qmp_gen4x2_pcie_rx_alt_tbl,
|
||||
.rx_num = ARRAY_SIZE(qcs8300_qmp_gen4x2_pcie_rx_alt_tbl),
|
||||
.pcs = sa8775p_qmp_gen4x2_pcie_pcs_alt_tbl,
|
||||
.pcs_num = ARRAY_SIZE(sa8775p_qmp_gen4x2_pcie_pcs_alt_tbl),
|
||||
.pcs_misc = sa8775p_qmp_gen4_pcie_pcs_misc_tbl,
|
||||
.pcs_misc_num = ARRAY_SIZE(sa8775p_qmp_gen4_pcie_pcs_misc_tbl),
|
||||
},
|
||||
|
||||
.tbls_rc = &(const struct qmp_phy_cfg_tbls) {
|
||||
.serdes = sa8775p_qmp_gen4x2_pcie_rc_serdes_alt_tbl,
|
||||
.serdes_num = ARRAY_SIZE(sa8775p_qmp_gen4x2_pcie_rc_serdes_alt_tbl),
|
||||
.pcs_misc = sa8775p_qmp_gen4_pcie_rc_pcs_misc_tbl,
|
||||
.pcs_misc_num = ARRAY_SIZE(sa8775p_qmp_gen4_pcie_rc_pcs_misc_tbl),
|
||||
},
|
||||
|
||||
.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 = pciephy_v5_regs_layout,
|
||||
|
||||
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
|
||||
.phy_status = PHYSTATUS_4_20,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg sdm845_qmp_pciephy_cfg = {
|
||||
.lanes = 1,
|
||||
|
||||
@@ -4156,6 +4242,21 @@ static const struct qmp_phy_cfg x1e80100_qmp_gen4x8_pciephy_cfg = {
|
||||
.has_nocsr_reset = true,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg qmp_v6_gen4x4_pciephy_cfg = {
|
||||
.lanes = 4,
|
||||
|
||||
.offsets = &qmp_pcie_offsets_v6_20,
|
||||
|
||||
.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 = pciephy_v6_regs_layout,
|
||||
|
||||
.pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
|
||||
.phy_status = PHYSTATUS_4_20,
|
||||
};
|
||||
|
||||
static void qmp_pcie_init_port_b(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls)
|
||||
{
|
||||
const struct qmp_phy_cfg *cfg = qmp->cfg;
|
||||
@@ -4876,6 +4977,9 @@ static const struct of_device_id qmp_pcie_of_match_table[] = {
|
||||
}, {
|
||||
.compatible = "qcom,qcs615-qmp-gen3x1-pcie-phy",
|
||||
.data = &qcs615_pciephy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,qcs8300-qmp-gen4x2-pcie-phy",
|
||||
.data = &qcs8300_qmp_gen4x2_pciephy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,sa8775p-qmp-gen4x2-pcie-phy",
|
||||
.data = &sa8775p_qmp_gen4x2_pciephy_cfg,
|
||||
@@ -4960,6 +5064,9 @@ static const struct of_device_id qmp_pcie_of_match_table[] = {
|
||||
}, {
|
||||
.compatible = "qcom,x1e80100-qmp-gen4x8-pcie-phy",
|
||||
.data = &x1e80100_qmp_gen4x8_pciephy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,x1p42100-qmp-gen4x4-pcie-phy",
|
||||
.data = &qmp_v6_gen4x4_pciephy_cfg,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
@@ -86,4 +86,11 @@
|
||||
#define QSERDES_V6_COM_CMN_STATUS 0x1d0
|
||||
#define QSERDES_V6_COM_C_READY_STATUS 0x1f8
|
||||
|
||||
#define QSERDES_V6_COM_ADAPTIVE_ANALOG_CONFIG 0x268
|
||||
#define QSERDES_V6_COM_CP_CTRL_ADAPTIVE_MODE0 0x26c
|
||||
#define QSERDES_V6_COM_PLL_RCCTRL_ADAPTIVE_MODE0 0x270
|
||||
#define QSERDES_V6_COM_PLL_CCTRL_ADAPTIVE_MODE0 0x274
|
||||
#define QSERDES_V6_COM_CP_CTRL_ADAPTIVE_MODE1 0x278
|
||||
#define QSERDES_V6_COM_PLL_RCCTRL_ADAPTIVE_MODE1 0x27c
|
||||
#define QSERDES_V6_COM_PLL_CCTRL_ADAPTIVE_MODE1 0x280
|
||||
#endif
|
||||
|
||||
67
drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v7.h
Normal file
67
drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v7.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2024, Linaro Limited
|
||||
*/
|
||||
|
||||
#ifndef QCOM_PHY_QMP_QSERDES_TXRX_UFS_V7_H_
|
||||
#define QCOM_PHY_QMP_QSERDES_TXRX_UFS_V7_H_
|
||||
|
||||
#define QSERDES_UFS_V7_TX_RES_CODE_LANE_TX 0x28
|
||||
#define QSERDES_UFS_V7_TX_RES_CODE_LANE_RX 0x2c
|
||||
#define QSERDES_UFS_V7_TX_RES_CODE_LANE_OFFSET_TX 0x30
|
||||
#define QSERDES_UFS_V7_TX_RES_CODE_LANE_OFFSET_RX 0x34
|
||||
#define QSERDES_UFS_V7_TX_LANE_MODE_1 0x7c
|
||||
#define QSERDES_UFS_V7_TX_FR_DCC_CTRL 0x108
|
||||
|
||||
#define QSERDES_UFS_V7_RX_UCDR_FASTLOCK_FO_GAIN_RATE4 0x10
|
||||
#define QSERDES_UFS_V7_RX_UCDR_FASTLOCK_SO_GAIN_RATE4 0x24
|
||||
#define QSERDES_UFS_V7_RX_UCDR_SO_SATURATION 0x28
|
||||
#define QSERDES_UFS_V7_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4 0x54
|
||||
#define QSERDES_UFS_V7_RX_UCDR_PI_CTRL1 0x58
|
||||
#define QSERDES_UFS_V7_RX_TERM_BW_CTRL0 0xc4
|
||||
#define QSERDES_UFS_V7_RX_UCDR_FO_GAIN_RATE2 0xd4
|
||||
#define QSERDES_UFS_V7_RX_UCDR_FO_GAIN_RATE4 0xdc
|
||||
#define QSERDES_UFS_V7_RX_UCDR_SO_GAIN_RATE4 0xf0
|
||||
#define QSERDES_UFS_V7_RX_UCDR_PI_CONTROLS 0xf4
|
||||
#define QSERDES_UFS_V7_RX_VGA_CAL_MAN_VAL 0x178
|
||||
#define QSERDES_UFS_V7_RX_EQU_ADAPTOR_CNTRL4 0x1b4
|
||||
#define QSERDES_UFS_V7_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x1cc
|
||||
#define QSERDES_UFS_V7_RX_OFFSET_ADAPTOR_CNTRL3 0x1d4
|
||||
#define QSERDES_UFS_V7_RX_INTERFACE_MODE 0x1f0
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE_0_1_B0 0x218
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE_0_1_B1 0x21C
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE_0_1_B2 0x220
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE_0_1_B3 0x224
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE_0_1_B4 0x228
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE_0_1_B6 0x230
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE_0_1_B7 0x234
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE2_B3 0x248
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE2_B6 0x254
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE2_B7 0x258
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE3_B0 0x260
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE3_B1 0x264
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE3_B2 0x268
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE3_B3 0x26c
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE3_B4 0x270
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE3_B5 0x274
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE3_B7 0x27c
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE3_B8 0x280
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B0 0x284
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B1 0x288
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B2 0x28c
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B3 0x290
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B4 0x294
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B5 0x298
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B6 0x29c
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B7 0x2a0
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B0 0x2a8
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B1 0x2ac
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B2 0x2b0
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B3 0x2b4
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B4 0x2b8
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B5 0x2bc
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B6 0x2c0
|
||||
#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B7 0x2c4
|
||||
#define QSERDES_UFS_V7_RX_DLL0_FTUNE_CTRL 0x348
|
||||
#define QSERDES_UFS_V7_RX_SIGDET_CAL_TRIM 0x380
|
||||
#endif
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "phy-qcom-qmp-pcs-ufs-v6.h"
|
||||
|
||||
#include "phy-qcom-qmp-qserdes-txrx-ufs-v6.h"
|
||||
#include "phy-qcom-qmp-qserdes-txrx-ufs-v7.h"
|
||||
|
||||
/* QPHY_PCS_READY_STATUS bit */
|
||||
#define PCS_READY BIT(0)
|
||||
@@ -949,6 +950,124 @@ static const struct qmp_phy_init_tbl sm8650_ufsphy_g5_pcs[] = {
|
||||
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME, 0x9e),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl sm8750_ufsphy_serdes[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_CFG, 0x60),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO_MODE1, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x07),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x20),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_CTRL, 0x40),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_ADAPTIVE_ANALOG_CONFIG, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_ADAPTIVE_MODE0, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCCTRL_ADAPTIVE_MODE0, 0x18),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_ADAPTIVE_MODE0, 0x14),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x92),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x14),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_ADAPTIVE_MODE1, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCCTRL_ADAPTIVE_MODE1, 0x18),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_ADAPTIVE_MODE1, 0x14),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x99),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x07),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xbe),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x23),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl sm8750_ufsphy_tx[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_TX_LANE_MODE_1, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_TX_RES_CODE_LANE_OFFSET_TX, 0x07),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_TX_RES_CODE_LANE_OFFSET_RX, 0x17),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl sm8750_ufsphy_rx[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_FO_GAIN_RATE2, 0x0c),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_FO_GAIN_RATE4, 0x0c),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_SO_GAIN_RATE4, 0x04),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_PI_CONTROLS, 0x07),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_VGA_CAL_MAN_VAL, 0x8e),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_EQU_ADAPTOR_CNTRL4, 0x0f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE_0_1_B0, 0xce),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE_0_1_B1, 0xce),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE_0_1_B2, 0x18),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE_0_1_B3, 0x1a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE_0_1_B4, 0x0f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE_0_1_B6, 0x60),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE_0_1_B7, 0x62),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE2_B3, 0x9a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE2_B6, 0xe2),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE2_B7, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B0, 0x1b),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B1, 0x1b),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B2, 0x98),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B3, 0x9b),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B4, 0x2a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B5, 0x12),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B7, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B8, 0x01),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B0, 0x93),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B1, 0x93),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B2, 0x60),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B3, 0x99),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B4, 0x5f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B5, 0x92),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B6, 0xe3),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B7, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B0, 0x9b),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B1, 0x9b),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B2, 0x60),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B3, 0x99),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B4, 0x5f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B5, 0x92),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B6, 0xfb),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B7, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_SO_SATURATION, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_PI_CTRL1, 0x94),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_TERM_BW_CTRL0, 0xfa),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_DLL0_FTUNE_CTRL, 0x30),
|
||||
QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_SIGDET_CAL_TRIM, 0x77),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl sm8750_ufsphy_pcs[] = {
|
||||
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
|
||||
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
|
||||
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PCS_CTRL1, 0x40),
|
||||
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
|
||||
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x68),
|
||||
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S4, 0x0e),
|
||||
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S5, 0x12),
|
||||
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S6, 0x15),
|
||||
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S7, 0x19),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl sm8750_ufsphy_g4_pcs[] = {
|
||||
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04),
|
||||
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl sm8750_ufsphy_hs_b_pcs[] = {
|
||||
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PCS_CTRL1, 0x41),
|
||||
};
|
||||
|
||||
struct qmp_ufs_offsets {
|
||||
u16 serdes;
|
||||
u16 pcs;
|
||||
@@ -1523,6 +1642,45 @@ static const struct qmp_phy_cfg sm8650_ufsphy_cfg = {
|
||||
.regs = ufsphy_v6_regs_layout,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg sm8750_ufsphy_cfg = {
|
||||
.lanes = 2,
|
||||
|
||||
.offsets = &qmp_ufs_offsets_v6,
|
||||
.max_supported_gear = UFS_HS_G5,
|
||||
|
||||
.tbls = {
|
||||
.serdes = sm8750_ufsphy_serdes,
|
||||
.serdes_num = ARRAY_SIZE(sm8750_ufsphy_serdes),
|
||||
.tx = sm8750_ufsphy_tx,
|
||||
.tx_num = ARRAY_SIZE(sm8750_ufsphy_tx),
|
||||
.rx = sm8750_ufsphy_rx,
|
||||
.rx_num = ARRAY_SIZE(sm8750_ufsphy_rx),
|
||||
.pcs = sm8750_ufsphy_pcs,
|
||||
.pcs_num = ARRAY_SIZE(sm8750_ufsphy_pcs),
|
||||
},
|
||||
|
||||
.tbls_hs_b = {
|
||||
.pcs = sm8750_ufsphy_hs_b_pcs,
|
||||
.pcs_num = ARRAY_SIZE(sm8750_ufsphy_hs_b_pcs),
|
||||
},
|
||||
|
||||
.tbls_hs_overlay[0] = {
|
||||
.pcs = sm8750_ufsphy_g4_pcs,
|
||||
.pcs_num = ARRAY_SIZE(sm8750_ufsphy_g4_pcs),
|
||||
.max_gear = UFS_HS_G4,
|
||||
},
|
||||
.tbls_hs_overlay[1] = {
|
||||
.pcs = sm8650_ufsphy_g5_pcs,
|
||||
.pcs_num = ARRAY_SIZE(sm8650_ufsphy_g5_pcs),
|
||||
.max_gear = UFS_HS_G5,
|
||||
},
|
||||
|
||||
.vreg_list = qmp_phy_vreg_l,
|
||||
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||
.regs = ufsphy_v6_regs_layout,
|
||||
|
||||
};
|
||||
|
||||
static void qmp_ufs_serdes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls)
|
||||
{
|
||||
void __iomem *serdes = qmp->serdes;
|
||||
@@ -1578,23 +1736,25 @@ static int qmp_ufs_get_gear_overlay(struct qmp_ufs *qmp, const struct qmp_phy_cf
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qmp_ufs_init_all(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls)
|
||||
{
|
||||
qmp_ufs_serdes_init(qmp, tbls);
|
||||
qmp_ufs_lanes_init(qmp, tbls);
|
||||
qmp_ufs_pcs_init(qmp, tbls);
|
||||
}
|
||||
|
||||
static void qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
|
||||
{
|
||||
int i;
|
||||
|
||||
qmp_ufs_serdes_init(qmp, &cfg->tbls);
|
||||
qmp_ufs_lanes_init(qmp, &cfg->tbls);
|
||||
qmp_ufs_pcs_init(qmp, &cfg->tbls);
|
||||
qmp_ufs_init_all(qmp, &cfg->tbls);
|
||||
|
||||
i = qmp_ufs_get_gear_overlay(qmp, cfg);
|
||||
if (i >= 0) {
|
||||
qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_overlay[i]);
|
||||
qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_overlay[i]);
|
||||
qmp_ufs_pcs_init(qmp, &cfg->tbls_hs_overlay[i]);
|
||||
qmp_ufs_init_all(qmp, &cfg->tbls_hs_overlay[i]);
|
||||
}
|
||||
|
||||
if (qmp->mode == PHY_MODE_UFS_HS_B)
|
||||
qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_b);
|
||||
qmp_ufs_init_all(qmp, &cfg->tbls_hs_b);
|
||||
}
|
||||
|
||||
static int qmp_ufs_com_init(struct qmp_ufs *qmp)
|
||||
@@ -2061,7 +2221,11 @@ static const struct of_device_id qmp_ufs_of_match_table[] = {
|
||||
}, {
|
||||
.compatible = "qcom,sm8650-qmp-ufs-phy",
|
||||
.data = &sm8650_ufsphy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,sm8750-qmp-ufs-phy",
|
||||
.data = &sm8750_ufsphy_cfg,
|
||||
},
|
||||
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qmp_ufs_of_match_table);
|
||||
|
||||
@@ -1124,6 +1124,9 @@ static const struct of_device_id qmp_usbc_of_match_table[] = {
|
||||
}, {
|
||||
.compatible = "qcom,qcm2290-qmp-usb3-phy",
|
||||
.data = &qcm2290_usb3phy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,qcs615-qmp-usb3-phy",
|
||||
.data = &qcm2290_usb3phy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,sdm660-qmp-usb3-phy",
|
||||
.data = &sdm660_usb3phy_cfg,
|
||||
|
||||
286
drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
Normal file
286
drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
Normal file
@@ -0,0 +1,286 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2025, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#define RST_ASSERT_DELAY_MIN_US 100
|
||||
#define RST_ASSERT_DELAY_MAX_US 150
|
||||
#define PIPE_CLK_DELAY_MIN_US 5000
|
||||
#define PIPE_CLK_DELAY_MAX_US 5100
|
||||
#define CLK_EN_DELAY_MIN_US 30
|
||||
#define CLK_EN_DELAY_MAX_US 50
|
||||
#define CDR_CTRL_REG_1 0x80
|
||||
#define CDR_CTRL_REG_2 0x84
|
||||
#define CDR_CTRL_REG_3 0x88
|
||||
#define CDR_CTRL_REG_4 0x8c
|
||||
#define CDR_CTRL_REG_5 0x90
|
||||
#define CDR_CTRL_REG_6 0x94
|
||||
#define CDR_CTRL_REG_7 0x98
|
||||
#define SSCG_CTRL_REG_1 0x9c
|
||||
#define SSCG_CTRL_REG_2 0xa0
|
||||
#define SSCG_CTRL_REG_3 0xa4
|
||||
#define SSCG_CTRL_REG_4 0xa8
|
||||
#define SSCG_CTRL_REG_5 0xac
|
||||
#define SSCG_CTRL_REG_6 0xb0
|
||||
#define PCS_INTERNAL_CONTROL_2 0x2d8
|
||||
|
||||
#define PHY_CFG_PLLCFG 0x220
|
||||
#define PHY_CFG_EIOS_DTCT_REG 0x3e4
|
||||
#define PHY_CFG_GEN3_ALIGN_HOLDOFF_TIME 0x3e8
|
||||
|
||||
enum qcom_uniphy_pcie_type {
|
||||
PHY_TYPE_PCIE = 1,
|
||||
PHY_TYPE_PCIE_GEN2,
|
||||
PHY_TYPE_PCIE_GEN3,
|
||||
};
|
||||
|
||||
struct qcom_uniphy_pcie_regs {
|
||||
u32 offset;
|
||||
u32 val;
|
||||
};
|
||||
|
||||
struct qcom_uniphy_pcie_data {
|
||||
int lane_offset; /* offset between the lane register bases */
|
||||
u32 phy_type;
|
||||
const struct qcom_uniphy_pcie_regs *init_seq;
|
||||
u32 init_seq_num;
|
||||
u32 pipe_clk_rate;
|
||||
};
|
||||
|
||||
struct qcom_uniphy_pcie {
|
||||
struct phy phy;
|
||||
struct device *dev;
|
||||
const struct qcom_uniphy_pcie_data *data;
|
||||
struct clk_bulk_data *clks;
|
||||
int num_clks;
|
||||
struct reset_control *resets;
|
||||
void __iomem *base;
|
||||
int lanes;
|
||||
};
|
||||
|
||||
#define phy_to_dw_phy(x) container_of((x), struct qca_uni_pcie_phy, phy)
|
||||
|
||||
static const struct qcom_uniphy_pcie_regs ipq5332_regs[] = {
|
||||
{
|
||||
.offset = PHY_CFG_PLLCFG,
|
||||
.val = 0x30,
|
||||
}, {
|
||||
.offset = PHY_CFG_EIOS_DTCT_REG,
|
||||
.val = 0x53ef,
|
||||
}, {
|
||||
.offset = PHY_CFG_GEN3_ALIGN_HOLDOFF_TIME,
|
||||
.val = 0xcf,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct qcom_uniphy_pcie_data ipq5332_data = {
|
||||
.lane_offset = 0x800,
|
||||
.phy_type = PHY_TYPE_PCIE_GEN3,
|
||||
.init_seq = ipq5332_regs,
|
||||
.init_seq_num = ARRAY_SIZE(ipq5332_regs),
|
||||
.pipe_clk_rate = 250 * MEGA,
|
||||
};
|
||||
|
||||
static void qcom_uniphy_pcie_init(struct qcom_uniphy_pcie *phy)
|
||||
{
|
||||
const struct qcom_uniphy_pcie_data *data = phy->data;
|
||||
const struct qcom_uniphy_pcie_regs *init_seq;
|
||||
void __iomem *base = phy->base;
|
||||
int lane, i;
|
||||
|
||||
for (lane = 0; lane < phy->lanes; lane++) {
|
||||
init_seq = data->init_seq;
|
||||
|
||||
for (i = 0; i < data->init_seq_num; i++)
|
||||
writel(init_seq[i].val, base + init_seq[i].offset);
|
||||
|
||||
base += data->lane_offset;
|
||||
}
|
||||
}
|
||||
|
||||
static int qcom_uniphy_pcie_power_off(struct phy *x)
|
||||
{
|
||||
struct qcom_uniphy_pcie *phy = phy_get_drvdata(x);
|
||||
|
||||
clk_bulk_disable_unprepare(phy->num_clks, phy->clks);
|
||||
|
||||
return reset_control_assert(phy->resets);
|
||||
}
|
||||
|
||||
static int qcom_uniphy_pcie_power_on(struct phy *x)
|
||||
{
|
||||
struct qcom_uniphy_pcie *phy = phy_get_drvdata(x);
|
||||
int ret;
|
||||
|
||||
ret = reset_control_assert(phy->resets);
|
||||
if (ret) {
|
||||
dev_err(phy->dev, "reset assert failed (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
usleep_range(RST_ASSERT_DELAY_MIN_US, RST_ASSERT_DELAY_MAX_US);
|
||||
|
||||
ret = reset_control_deassert(phy->resets);
|
||||
if (ret) {
|
||||
dev_err(phy->dev, "reset deassert failed (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
usleep_range(PIPE_CLK_DELAY_MIN_US, PIPE_CLK_DELAY_MAX_US);
|
||||
|
||||
ret = clk_bulk_prepare_enable(phy->num_clks, phy->clks);
|
||||
if (ret) {
|
||||
dev_err(phy->dev, "clk prepare and enable failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
usleep_range(CLK_EN_DELAY_MIN_US, CLK_EN_DELAY_MAX_US);
|
||||
|
||||
qcom_uniphy_pcie_init(phy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int qcom_uniphy_pcie_get_resources(struct platform_device *pdev,
|
||||
struct qcom_uniphy_pcie *phy)
|
||||
{
|
||||
struct resource *res;
|
||||
|
||||
phy->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(phy->base))
|
||||
return PTR_ERR(phy->base);
|
||||
|
||||
phy->num_clks = devm_clk_bulk_get_all(phy->dev, &phy->clks);
|
||||
if (phy->num_clks < 0)
|
||||
return phy->num_clks;
|
||||
|
||||
phy->resets = devm_reset_control_array_get_exclusive(phy->dev);
|
||||
if (IS_ERR(phy->resets))
|
||||
return PTR_ERR(phy->resets);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a fixed rate pipe clock.
|
||||
*
|
||||
* The <s>_pipe_clksrc generated by PHY goes to the GCC that gate
|
||||
* controls it. The <s>_pipe_clk coming out of the GCC is requested
|
||||
* by the PHY driver for its operations.
|
||||
* We register the <s>_pipe_clksrc here. The gcc driver takes care
|
||||
* of assigning this <s>_pipe_clksrc as parent to <s>_pipe_clk.
|
||||
* Below picture shows this relationship.
|
||||
*
|
||||
* +---------------+
|
||||
* | PHY block |<<---------------------------------------+
|
||||
* | | |
|
||||
* | +-------+ | +-----+ |
|
||||
* I/P---^-->| PLL |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+
|
||||
* clk | +-------+ | +-----+
|
||||
* +---------------+
|
||||
*/
|
||||
static inline int phy_pipe_clk_register(struct qcom_uniphy_pcie *phy, int id)
|
||||
{
|
||||
const struct qcom_uniphy_pcie_data *data = phy->data;
|
||||
struct clk_hw *hw;
|
||||
char name[64];
|
||||
|
||||
snprintf(name, sizeof(name), "phy%d_pipe_clk_src", id);
|
||||
hw = devm_clk_hw_register_fixed_rate(phy->dev, name, NULL, 0,
|
||||
data->pipe_clk_rate);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(phy->dev, PTR_ERR(hw),
|
||||
"Unable to register %s\n", name);
|
||||
|
||||
return devm_of_clk_add_hw_provider(phy->dev, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
|
||||
static const struct of_device_id qcom_uniphy_pcie_id_table[] = {
|
||||
{
|
||||
.compatible = "qcom,ipq5332-uniphy-pcie-phy",
|
||||
.data = &ipq5332_data,
|
||||
}, {
|
||||
/* Sentinel */
|
||||
},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qcom_uniphy_pcie_id_table);
|
||||
|
||||
static const struct phy_ops pcie_ops = {
|
||||
.power_on = qcom_uniphy_pcie_power_on,
|
||||
.power_off = qcom_uniphy_pcie_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int qcom_uniphy_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct phy_provider *phy_provider;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct qcom_uniphy_pcie *phy;
|
||||
struct phy *generic_phy;
|
||||
int ret;
|
||||
|
||||
phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
|
||||
if (!phy)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, phy);
|
||||
phy->dev = &pdev->dev;
|
||||
|
||||
phy->data = of_device_get_match_data(dev);
|
||||
if (!phy->data)
|
||||
return -EINVAL;
|
||||
|
||||
ret = of_property_read_u32(dev_of_node(dev), "num-lanes", &phy->lanes);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Couldn't read num-lanes\n");
|
||||
|
||||
ret = qcom_uniphy_pcie_get_resources(pdev, phy);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"failed to get resources: %d\n", ret);
|
||||
|
||||
generic_phy = devm_phy_create(phy->dev, NULL, &pcie_ops);
|
||||
if (IS_ERR(generic_phy))
|
||||
return PTR_ERR(generic_phy);
|
||||
|
||||
phy_set_drvdata(generic_phy, phy);
|
||||
|
||||
ret = phy_pipe_clk_register(phy, generic_phy->id);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "failed to register phy pipe clk\n");
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(phy->dev,
|
||||
of_phy_simple_xlate);
|
||||
if (IS_ERR(phy_provider))
|
||||
return PTR_ERR(phy_provider);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver qcom_uniphy_pcie_driver = {
|
||||
.probe = qcom_uniphy_pcie_probe,
|
||||
.driver = {
|
||||
.name = "qcom-uniphy-pcie",
|
||||
.of_match_table = qcom_uniphy_pcie_id_table,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(qcom_uniphy_pcie_driver);
|
||||
|
||||
MODULE_DESCRIPTION("PCIE QCOM UNIPHY driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -83,6 +83,18 @@ config PHY_ROCKCHIP_PCIE
|
||||
help
|
||||
Enable this to support the Rockchip PCIe PHY.
|
||||
|
||||
config PHY_ROCKCHIP_SAMSUNG_DCPHY
|
||||
tristate "Rockchip Samsung MIPI DCPHY driver"
|
||||
depends on (ARCH_ROCKCHIP || COMPILE_TEST)
|
||||
select GENERIC_PHY
|
||||
select GENERIC_PHY_MIPI_DPHY
|
||||
help
|
||||
Enable this to support the Rockchip MIPI DCPHY with
|
||||
Samsung IP block.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called phy-rockchip-samsung-dcphy
|
||||
|
||||
config PHY_ROCKCHIP_SAMSUNG_HDPTX
|
||||
tristate "Rockchip Samsung HDMI/eDP Combo PHY driver"
|
||||
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
|
||||
|
||||
@@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI) += phy-rockchip-inno-hdmi.o
|
||||
obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o
|
||||
obj-$(CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY) += phy-rockchip-naneng-combphy.o
|
||||
obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o
|
||||
obj-$(CONFIG_PHY_ROCKCHIP_SAMSUNG_DCPHY) += phy-rockchip-samsung-dcphy.o
|
||||
obj-$(CONFIG_PHY_ROCKCHIP_SAMSUNG_HDPTX) += phy-rockchip-samsung-hdptx.o
|
||||
obj-$(CONFIG_PHY_ROCKCHIP_SNPS_PCIE3) += phy-rockchip-snps-pcie3.o
|
||||
obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
|
||||
|
||||
@@ -440,7 +440,7 @@ static int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy)
|
||||
struct extcon_dev *edev;
|
||||
int ret;
|
||||
|
||||
if (of_property_read_bool(node, "extcon")) {
|
||||
if (of_property_present(node, "extcon")) {
|
||||
edev = extcon_get_edev_by_phandle(rphy->dev, 0);
|
||||
if (IS_ERR(edev))
|
||||
return dev_err_probe(rphy->dev, PTR_ERR(edev),
|
||||
@@ -1323,7 +1323,7 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!of_property_read_bool(rphy->dev->of_node, "extcon")) {
|
||||
if (!of_property_present(rphy->dev->of_node, "extcon")) {
|
||||
/* do initial sync of usb state */
|
||||
id = property_enabled(rphy->grf, &rport->port_cfg->utmi_id);
|
||||
extcon_set_state_sync(rphy->edev, EXTCON_USB_HOST, !id);
|
||||
|
||||
@@ -396,6 +396,154 @@ static int rockchip_combphy_probe(struct platform_device *pdev)
|
||||
return PTR_ERR_OR_ZERO(phy_provider);
|
||||
}
|
||||
|
||||
static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv)
|
||||
{
|
||||
const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
|
||||
unsigned long rate;
|
||||
u32 val;
|
||||
|
||||
switch (priv->type) {
|
||||
case PHY_TYPE_PCIE:
|
||||
/* Set SSC downward spread spectrum */
|
||||
rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK,
|
||||
PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT,
|
||||
PHYREG32);
|
||||
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_pcie, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->con3_for_pcie, true);
|
||||
break;
|
||||
case PHY_TYPE_USB3:
|
||||
/* Set SSC downward spread spectrum */
|
||||
rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK,
|
||||
PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT,
|
||||
PHYREG32);
|
||||
|
||||
/* Enable adaptive CTLE for USB3.0 Rx */
|
||||
rockchip_combphy_updatel(priv, PHYREG15_CTLE_EN,
|
||||
PHYREG15_CTLE_EN, PHYREG15);
|
||||
|
||||
/* Set PLL KVCO fine tuning signals */
|
||||
rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, BIT(3), PHYREG33);
|
||||
|
||||
/* Set PLL LPF R1 to su_trim[10:7]=1001 */
|
||||
writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12);
|
||||
|
||||
/* Set PLL input clock divider 1/2 */
|
||||
val = FIELD_PREP(PHYREG6_PLL_DIV_MASK, PHYREG6_PLL_DIV_2);
|
||||
rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, val, PHYREG6);
|
||||
|
||||
/* Set PLL loop divider */
|
||||
writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18);
|
||||
|
||||
/* Set PLL KVCO to min and set PLL charge pump current to max */
|
||||
writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11);
|
||||
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_sel_usb, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->usb_mode_set, true);
|
||||
break;
|
||||
default:
|
||||
dev_err(priv->dev, "incompatible PHY type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rate = clk_get_rate(priv->refclk);
|
||||
|
||||
switch (rate) {
|
||||
case REF_CLOCK_24MHz:
|
||||
if (priv->type == PHY_TYPE_USB3) {
|
||||
/* Set ssc_cnt[9:0]=0101111101 & 31.5KHz */
|
||||
val = FIELD_PREP(PHYREG15_SSC_CNT_MASK, PHYREG15_SSC_CNT_VALUE);
|
||||
rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK,
|
||||
val, PHYREG15);
|
||||
|
||||
writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16);
|
||||
}
|
||||
break;
|
||||
case REF_CLOCK_25MHz:
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_25m, true);
|
||||
break;
|
||||
case REF_CLOCK_100MHz:
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true);
|
||||
if (priv->type == PHY_TYPE_PCIE) {
|
||||
/* PLL KVCO tuning fine */
|
||||
val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE);
|
||||
rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK,
|
||||
val, PHYREG33);
|
||||
|
||||
/* Enable controlling random jitter, aka RMJ */
|
||||
writel(0x4, priv->mmio + PHYREG12);
|
||||
|
||||
val = PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT;
|
||||
rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK,
|
||||
val, PHYREG6);
|
||||
|
||||
writel(0x32, priv->mmio + PHYREG18);
|
||||
writel(0xf0, priv->mmio + PHYREG11);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(priv->dev, "Unsupported rate: %lu\n", rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (priv->ext_refclk) {
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true);
|
||||
if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) {
|
||||
val = PHYREG13_RESISTER_HIGH_Z << PHYREG13_RESISTER_SHIFT;
|
||||
val |= PHYREG13_CKRCV_AMP0;
|
||||
rockchip_combphy_updatel(priv, PHYREG13_RESISTER_MASK, val, PHYREG13);
|
||||
|
||||
val = readl(priv->mmio + PHYREG14);
|
||||
val |= PHYREG14_CKRCV_AMP1;
|
||||
writel(val, priv->mmio + PHYREG14);
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->enable_ssc) {
|
||||
val = readl(priv->mmio + PHYREG8);
|
||||
val |= PHYREG8_SSC_EN;
|
||||
writel(val, priv->mmio + PHYREG8);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rockchip_combphy_grfcfg rk3562_combphy_grfcfgs = {
|
||||
/* pipe-phy-grf */
|
||||
.pcie_mode_set = { 0x0000, 5, 0, 0x00, 0x11 },
|
||||
.usb_mode_set = { 0x0000, 5, 0, 0x00, 0x04 },
|
||||
.pipe_rxterm_set = { 0x0000, 12, 12, 0x00, 0x01 },
|
||||
.pipe_txelec_set = { 0x0004, 1, 1, 0x00, 0x01 },
|
||||
.pipe_txcomp_set = { 0x0004, 4, 4, 0x00, 0x01 },
|
||||
.pipe_clk_25m = { 0x0004, 14, 13, 0x00, 0x01 },
|
||||
.pipe_clk_100m = { 0x0004, 14, 13, 0x00, 0x02 },
|
||||
.pipe_phymode_sel = { 0x0008, 1, 1, 0x00, 0x01 },
|
||||
.pipe_rate_sel = { 0x0008, 2, 2, 0x00, 0x01 },
|
||||
.pipe_rxterm_sel = { 0x0008, 8, 8, 0x00, 0x01 },
|
||||
.pipe_txelec_sel = { 0x0008, 12, 12, 0x00, 0x01 },
|
||||
.pipe_txcomp_sel = { 0x0008, 15, 15, 0x00, 0x01 },
|
||||
.pipe_clk_ext = { 0x000c, 9, 8, 0x02, 0x01 },
|
||||
.pipe_sel_usb = { 0x000c, 14, 13, 0x00, 0x01 },
|
||||
.pipe_phy_status = { 0x0034, 6, 6, 0x01, 0x00 },
|
||||
.con0_for_pcie = { 0x0000, 15, 0, 0x00, 0x1000 },
|
||||
.con1_for_pcie = { 0x0004, 15, 0, 0x00, 0x0000 },
|
||||
.con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x0101 },
|
||||
.con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 },
|
||||
};
|
||||
|
||||
static const struct rockchip_combphy_cfg rk3562_combphy_cfgs = {
|
||||
.num_phys = 1,
|
||||
.phy_ids = {
|
||||
0xff750000
|
||||
},
|
||||
.grfcfg = &rk3562_combphy_grfcfgs,
|
||||
.combphy_cfg = rk3562_combphy_cfg,
|
||||
};
|
||||
|
||||
static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv)
|
||||
{
|
||||
const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
|
||||
@@ -1049,6 +1197,10 @@ static const struct rockchip_combphy_cfg rk3588_combphy_cfgs = {
|
||||
};
|
||||
|
||||
static const struct of_device_id rockchip_combphy_of_match[] = {
|
||||
{
|
||||
.compatible = "rockchip,rk3562-naneng-combphy",
|
||||
.data = &rk3562_combphy_cfgs,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3568-naneng-combphy",
|
||||
.data = &rk3568_combphy_cfgs,
|
||||
|
||||
1719
drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
Normal file
1719
drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -187,6 +187,8 @@ struct rk_udphy {
|
||||
u32 dp_aux_din_sel;
|
||||
bool dp_sink_hpd_sel;
|
||||
bool dp_sink_hpd_cfg;
|
||||
unsigned int link_rate;
|
||||
unsigned int lanes;
|
||||
u8 bw;
|
||||
int id;
|
||||
|
||||
@@ -978,7 +980,7 @@ static int rk_udphy_parse_dt(struct rk_udphy *udphy)
|
||||
|
||||
if (device_property_present(dev, "maximum-speed")) {
|
||||
maximum_speed = usb_get_maximum_speed(dev);
|
||||
udphy->hs = maximum_speed <= USB_SPEED_HIGH ? true : false;
|
||||
udphy->hs = maximum_speed <= USB_SPEED_HIGH;
|
||||
}
|
||||
|
||||
ret = rk_udphy_clk_init(udphy, dev);
|
||||
@@ -1045,7 +1047,6 @@ static int rk_udphy_dp_phy_init(struct phy *phy)
|
||||
mutex_lock(&udphy->mutex);
|
||||
|
||||
udphy->dp_in_use = true;
|
||||
rk_udphy_dp_hpd_event_trigger(udphy, udphy->dp_sink_hpd_cfg);
|
||||
|
||||
mutex_unlock(&udphy->mutex);
|
||||
|
||||
@@ -1103,13 +1104,35 @@ static int rk_udphy_dp_phy_power_off(struct phy *phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk_udphy_dp_phy_verify_link_rate(unsigned int link_rate)
|
||||
/*
|
||||
* Verify link rate
|
||||
*/
|
||||
static int rk_udphy_dp_phy_verify_link_rate(struct rk_udphy *udphy,
|
||||
struct phy_configure_opts_dp *dp)
|
||||
{
|
||||
switch (link_rate) {
|
||||
switch (dp->link_rate) {
|
||||
case 1620:
|
||||
case 2700:
|
||||
case 5400:
|
||||
case 8100:
|
||||
udphy->link_rate = dp->link_rate;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk_udphy_dp_phy_verify_lanes(struct rk_udphy *udphy,
|
||||
struct phy_configure_opts_dp *dp)
|
||||
{
|
||||
switch (dp->lanes) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
/* valid lane count. */
|
||||
udphy->lanes = dp->lanes;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1119,45 +1142,26 @@ static int rk_udphy_dp_phy_verify_link_rate(unsigned int link_rate)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk_udphy_dp_phy_verify_config(struct rk_udphy *udphy,
|
||||
struct phy_configure_opts_dp *dp)
|
||||
/*
|
||||
* If changing voltages is required, check swing and pre-emphasis
|
||||
* levels, per-lane.
|
||||
*/
|
||||
static int rk_udphy_dp_phy_verify_voltages(struct rk_udphy *udphy,
|
||||
struct phy_configure_opts_dp *dp)
|
||||
{
|
||||
int i, ret;
|
||||
int i;
|
||||
|
||||
/* If changing link rate was required, verify it's supported. */
|
||||
ret = rk_udphy_dp_phy_verify_link_rate(dp->link_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Lane count verified previously. */
|
||||
for (i = 0; i < udphy->lanes; i++) {
|
||||
if (dp->voltage[i] > 3 || dp->pre[i] > 3)
|
||||
return -EINVAL;
|
||||
|
||||
/* Verify lane count. */
|
||||
switch (dp->lanes) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
/* valid lane count. */
|
||||
break;
|
||||
|
||||
default:
|
||||
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;
|
||||
}
|
||||
/*
|
||||
* Sum of voltage swing and pre-emphasis levels cannot
|
||||
* exceed 3.
|
||||
*/
|
||||
if (dp->voltage[i] + dp->pre[i] > 3)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1197,9 +1201,23 @@ static int rk_udphy_dp_phy_configure(struct phy *phy,
|
||||
u32 i, val, lane;
|
||||
int ret;
|
||||
|
||||
ret = rk_udphy_dp_phy_verify_config(udphy, dp);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (dp->set_rate) {
|
||||
ret = rk_udphy_dp_phy_verify_link_rate(udphy, dp);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dp->set_lanes) {
|
||||
ret = rk_udphy_dp_phy_verify_lanes(udphy, dp);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dp->set_voltages) {
|
||||
ret = rk_udphy_dp_phy_verify_voltages(udphy, dp);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dp->set_rate) {
|
||||
regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET,
|
||||
@@ -1244,9 +1262,9 @@ static int rk_udphy_dp_phy_configure(struct phy *phy,
|
||||
}
|
||||
|
||||
if (dp->set_voltages) {
|
||||
for (i = 0; i < dp->lanes; i++) {
|
||||
for (i = 0; i < udphy->lanes; i++) {
|
||||
lane = udphy->dp_lane_sel[i];
|
||||
switch (dp->link_rate) {
|
||||
switch (udphy->link_rate) {
|
||||
case 1620:
|
||||
case 2700:
|
||||
regmap_update_bits(udphy->pma_regmap,
|
||||
|
||||
@@ -81,6 +81,7 @@ config PHY_EXYNOS5_USBDRD
|
||||
tristate "Exynos5 SoC series USB DRD PHY driver"
|
||||
depends on (ARCH_EXYNOS && OF) || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
depends on TYPEC || !TYPEC
|
||||
depends on USB_DWC3_EXYNOS
|
||||
select GENERIC_PHY
|
||||
select MFD_SYSCON
|
||||
|
||||
@@ -7,6 +7,7 @@ phy-exynos-ufs-y += phy-gs101-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
|
||||
phy-exynos-ufs-y += phy-exynosautov920-ufs.o
|
||||
phy-exynos-ufs-y += phy-fsd-ufs.o
|
||||
obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o
|
||||
phy-exynos-usb2-y += phy-samsung-usb2.o
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/soc/samsung/exynos-regs-pmu.h>
|
||||
#include <linux/usb/typec.h>
|
||||
#include <linux/usb/typec_mux.h>
|
||||
|
||||
/* Exynos USB PHY registers */
|
||||
#define EXYNOS5_FSEL_9MHZ6 0x0
|
||||
@@ -209,6 +211,10 @@
|
||||
|
||||
#define EXYNOS9_PMA_USBDP_CMN_REG00B8 0x02e0
|
||||
#define CMN_REG00B8_LANE_MUX_SEL_DP GENMASK(3, 0)
|
||||
#define CMN_REG00B8_LANE_MUX_SEL_DP_LANE3 BIT(3)
|
||||
#define CMN_REG00B8_LANE_MUX_SEL_DP_LANE2 BIT(2)
|
||||
#define CMN_REG00B8_LANE_MUX_SEL_DP_LANE1 BIT(1)
|
||||
#define CMN_REG00B8_LANE_MUX_SEL_DP_LANE0 BIT(0)
|
||||
|
||||
#define EXYNOS9_PMA_USBDP_CMN_REG01C0 0x0700
|
||||
#define CMN_REG01C0_ANA_LCPLL_LOCK_DONE BIT(7)
|
||||
@@ -383,11 +389,14 @@ struct exynos5_usbdrd_phy_drvdata {
|
||||
* @clks: clocks for register access
|
||||
* @core_clks: core clocks for phy (ref, pipe3, utmi+, ITP, etc. as required)
|
||||
* @drv_data: pointer to SoC level driver data structure
|
||||
* @phy_mutex: mutex protecting phy_init/exit & TCPC callbacks
|
||||
* @phys: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY
|
||||
* instances each with its 'phy' and 'phy_cfg'.
|
||||
* @extrefclk: frequency select settings when using 'separate
|
||||
* reference clocks' for SS and HS operations
|
||||
* @regulators: regulators for phy
|
||||
* @sw: TypeC orientation switch handle
|
||||
* @orientation: TypeC connector orientation - normal or flipped
|
||||
*/
|
||||
struct exynos5_usbdrd_phy {
|
||||
struct device *dev;
|
||||
@@ -397,6 +406,7 @@ struct exynos5_usbdrd_phy {
|
||||
struct clk_bulk_data *clks;
|
||||
struct clk_bulk_data *core_clks;
|
||||
const struct exynos5_usbdrd_phy_drvdata *drv_data;
|
||||
struct mutex phy_mutex;
|
||||
struct phy_usb_instance {
|
||||
struct phy *phy;
|
||||
u32 index;
|
||||
@@ -406,6 +416,9 @@ struct exynos5_usbdrd_phy {
|
||||
} phys[EXYNOS5_DRDPHYS_NUM];
|
||||
u32 extrefclk;
|
||||
struct regulator_bulk_data *regulators;
|
||||
|
||||
struct typec_switch_dev *sw;
|
||||
enum typec_orientation orientation;
|
||||
};
|
||||
|
||||
static inline
|
||||
@@ -647,22 +660,38 @@ exynos5_usbdrd_usbdp_g2_v4_pma_lane_mux_sel(struct exynos5_usbdrd_phy *phy_drd)
|
||||
/* lane configuration: USB on all lanes */
|
||||
reg = readl(regs_base + EXYNOS9_PMA_USBDP_CMN_REG00B8);
|
||||
reg &= ~CMN_REG00B8_LANE_MUX_SEL_DP;
|
||||
/*
|
||||
* USB on lanes 0 & 1 in normal mode, or 2 & 3 if reversed, DP on the
|
||||
* other ones.
|
||||
*/
|
||||
reg |= FIELD_PREP(CMN_REG00B8_LANE_MUX_SEL_DP,
|
||||
((phy_drd->orientation == TYPEC_ORIENTATION_NORMAL)
|
||||
? (CMN_REG00B8_LANE_MUX_SEL_DP_LANE3
|
||||
| CMN_REG00B8_LANE_MUX_SEL_DP_LANE2)
|
||||
: (CMN_REG00B8_LANE_MUX_SEL_DP_LANE1
|
||||
| CMN_REG00B8_LANE_MUX_SEL_DP_LANE0)));
|
||||
writel(reg, regs_base + EXYNOS9_PMA_USBDP_CMN_REG00B8);
|
||||
|
||||
/*
|
||||
* FIXME: below code supports one connector orientation only. It needs
|
||||
* updating once we can receive connector events.
|
||||
*/
|
||||
/* override of TX receiver detector and comparator: lane 1 */
|
||||
reg = readl(regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0413);
|
||||
reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_COMP_EN;
|
||||
reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_EN;
|
||||
if (phy_drd->orientation == TYPEC_ORIENTATION_NORMAL) {
|
||||
reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_COMP_EN;
|
||||
reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_EN;
|
||||
} else {
|
||||
reg |= TRSV_REG0413_OVRD_LN1_TX_RXD_COMP_EN;
|
||||
reg |= TRSV_REG0413_OVRD_LN1_TX_RXD_EN;
|
||||
}
|
||||
writel(reg, regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0413);
|
||||
|
||||
/* lane 3 */
|
||||
reg = readl(regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0813);
|
||||
reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_COMP_EN;
|
||||
reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_EN;
|
||||
if (phy_drd->orientation == TYPEC_ORIENTATION_NORMAL) {
|
||||
reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_COMP_EN;
|
||||
reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_EN;
|
||||
} else {
|
||||
reg &= ~TRSV_REG0813_OVRD_LN3_TX_RXD_COMP_EN;
|
||||
reg &= ~TRSV_REG0813_OVRD_LN3_TX_RXD_EN;
|
||||
}
|
||||
writel(reg, regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0813);
|
||||
}
|
||||
|
||||
@@ -700,21 +729,18 @@ exynos5_usbdrd_usbdp_g2_v4_pma_check_cdr_lock(struct exynos5_usbdrd_phy *phy_drd
|
||||
int err;
|
||||
|
||||
err = readl_poll_timeout(
|
||||
phy_drd->reg_pma + EXYNOS9_PMA_USBDP_TRSV_REG03C3,
|
||||
reg, (reg & locked) == locked, sleep_us, timeout_us);
|
||||
if (!err)
|
||||
return;
|
||||
|
||||
dev_err(phy_drd->dev,
|
||||
"timed out waiting for CDR lock (l0): %#.8x, retrying\n", reg);
|
||||
|
||||
/* based on cable orientation, this might be on the other phy port */
|
||||
err = readl_poll_timeout(
|
||||
phy_drd->reg_pma + EXYNOS9_PMA_USBDP_TRSV_REG07C3,
|
||||
/* lane depends on cable orientation */
|
||||
(phy_drd->reg_pma
|
||||
+ ((phy_drd->orientation == TYPEC_ORIENTATION_NORMAL)
|
||||
? EXYNOS9_PMA_USBDP_TRSV_REG03C3
|
||||
: EXYNOS9_PMA_USBDP_TRSV_REG07C3)),
|
||||
reg, (reg & locked) == locked, sleep_us, timeout_us);
|
||||
if (err)
|
||||
dev_err(phy_drd->dev,
|
||||
"timed out waiting for CDR lock (l2): %#.8x\n", reg);
|
||||
"timed out waiting for CDR(l%d) lock: %#.8x\n",
|
||||
((phy_drd->orientation == TYPEC_ORIENTATION_NORMAL)
|
||||
? 0
|
||||
: 2), reg);
|
||||
}
|
||||
|
||||
static void exynos5_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
|
||||
@@ -1111,13 +1137,15 @@ static void exynos850_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
|
||||
reg |= LINKCTRL_BUS_FILTER_BYPASS(0xf);
|
||||
writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL);
|
||||
|
||||
reg = readl(regs_base + EXYNOS850_DRD_UTMI);
|
||||
reg |= UTMI_FORCE_BVALID | UTMI_FORCE_VBUSVALID;
|
||||
writel(reg, regs_base + EXYNOS850_DRD_UTMI);
|
||||
if (!phy_drd->sw) {
|
||||
reg = readl(regs_base + EXYNOS850_DRD_UTMI);
|
||||
reg |= UTMI_FORCE_BVALID | UTMI_FORCE_VBUSVALID;
|
||||
writel(reg, regs_base + EXYNOS850_DRD_UTMI);
|
||||
|
||||
reg = readl(regs_base + EXYNOS850_DRD_HSP);
|
||||
reg |= HSP_VBUSVLDEXT | HSP_VBUSVLDEXTSEL;
|
||||
writel(reg, regs_base + EXYNOS850_DRD_HSP);
|
||||
reg = readl(regs_base + EXYNOS850_DRD_HSP);
|
||||
reg |= HSP_VBUSVLDEXT | HSP_VBUSVLDEXTSEL;
|
||||
writel(reg, regs_base + EXYNOS850_DRD_HSP);
|
||||
}
|
||||
|
||||
reg = readl(regs_base + EXYNOS850_DRD_SSPPLLCTL);
|
||||
reg &= ~SSPPLLCTL_FSEL;
|
||||
@@ -1184,7 +1212,8 @@ static int exynos850_usbdrd_phy_init(struct phy *phy)
|
||||
return ret;
|
||||
|
||||
/* UTMI or PIPE3 specific init */
|
||||
inst->phy_cfg->phy_init(phy_drd);
|
||||
scoped_guard(mutex, &phy_drd->phy_mutex)
|
||||
inst->phy_cfg->phy_init(phy_drd);
|
||||
|
||||
clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
|
||||
|
||||
@@ -1203,6 +1232,8 @@ static int exynos850_usbdrd_phy_exit(struct phy *phy)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
guard(mutex)(&phy_drd->phy_mutex);
|
||||
|
||||
/* Set PHY clock and control HS PHY */
|
||||
reg = readl(regs_base + EXYNOS850_DRD_UTMI);
|
||||
reg &= ~(UTMI_DP_PULLDOWN | UTMI_DM_PULLDOWN);
|
||||
@@ -1374,6 +1405,87 @@ static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos5_usbdrd_orien_sw_set(struct typec_switch_dev *sw,
|
||||
enum typec_orientation orientation)
|
||||
{
|
||||
struct exynos5_usbdrd_phy *phy_drd = typec_switch_get_drvdata(sw);
|
||||
int ret;
|
||||
|
||||
ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks);
|
||||
if (ret) {
|
||||
dev_err(phy_drd->dev, "Failed to enable PHY clocks(s)\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
scoped_guard(mutex, &phy_drd->phy_mutex) {
|
||||
void __iomem * const regs_base = phy_drd->reg_phy;
|
||||
unsigned int reg;
|
||||
|
||||
if (orientation == TYPEC_ORIENTATION_NONE) {
|
||||
reg = readl(regs_base + EXYNOS850_DRD_UTMI);
|
||||
reg &= ~(UTMI_FORCE_VBUSVALID | UTMI_FORCE_BVALID);
|
||||
writel(reg, regs_base + EXYNOS850_DRD_UTMI);
|
||||
|
||||
reg = readl(regs_base + EXYNOS850_DRD_HSP);
|
||||
reg |= HSP_VBUSVLDEXTSEL;
|
||||
reg &= ~HSP_VBUSVLDEXT;
|
||||
writel(reg, regs_base + EXYNOS850_DRD_HSP);
|
||||
} else {
|
||||
reg = readl(regs_base + EXYNOS850_DRD_UTMI);
|
||||
reg |= UTMI_FORCE_VBUSVALID | UTMI_FORCE_BVALID;
|
||||
writel(reg, regs_base + EXYNOS850_DRD_UTMI);
|
||||
|
||||
reg = readl(regs_base + EXYNOS850_DRD_HSP);
|
||||
reg |= HSP_VBUSVLDEXTSEL | HSP_VBUSVLDEXT;
|
||||
writel(reg, regs_base + EXYNOS850_DRD_HSP);
|
||||
}
|
||||
|
||||
phy_drd->orientation = orientation;
|
||||
}
|
||||
|
||||
clk_bulk_disable(phy_drd->drv_data->n_clks, phy_drd->clks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos5_usbdrd_orien_switch_unregister(void *data)
|
||||
{
|
||||
struct exynos5_usbdrd_phy *phy_drd = data;
|
||||
|
||||
typec_switch_unregister(phy_drd->sw);
|
||||
}
|
||||
|
||||
static int exynos5_usbdrd_setup_notifiers(struct exynos5_usbdrd_phy *phy_drd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_TYPEC))
|
||||
return 0;
|
||||
|
||||
if (device_property_present(phy_drd->dev, "orientation-switch")) {
|
||||
struct typec_switch_desc sw_desc = { };
|
||||
|
||||
sw_desc.drvdata = phy_drd;
|
||||
sw_desc.fwnode = dev_fwnode(phy_drd->dev);
|
||||
sw_desc.set = exynos5_usbdrd_orien_sw_set;
|
||||
|
||||
phy_drd->sw = typec_switch_register(phy_drd->dev, &sw_desc);
|
||||
if (IS_ERR(phy_drd->sw))
|
||||
return dev_err_probe(phy_drd->dev,
|
||||
PTR_ERR(phy_drd->sw),
|
||||
"Failed to register TypeC orientation switch\n");
|
||||
|
||||
ret = devm_add_action_or_reset(phy_drd->dev,
|
||||
exynos5_usbdrd_orien_switch_unregister,
|
||||
phy_drd);
|
||||
if (ret)
|
||||
return dev_err_probe(phy_drd->dev, ret,
|
||||
"Failed to register TypeC orientation devm action\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = {
|
||||
{
|
||||
.id = EXYNOS5_DRDPHY_UTMI,
|
||||
@@ -1513,8 +1625,11 @@ static const struct exynos5_usbdrd_phy_tuning gs101_tunes_pipe3_preinit[] = {
|
||||
PHY_TUNING_ENTRY_PMA(0x09e0, -1, 0x00),
|
||||
PHY_TUNING_ENTRY_PMA(0x09e4, -1, 0x36),
|
||||
PHY_TUNING_ENTRY_PMA(0x1e7c, -1, 0x06),
|
||||
PHY_TUNING_ENTRY_PMA(0x1e90, -1, 0x00),
|
||||
PHY_TUNING_ENTRY_PMA(0x1e94, -1, 0x36),
|
||||
PHY_TUNING_ENTRY_PMA(0x19e0, -1, 0x00),
|
||||
PHY_TUNING_ENTRY_PMA(0x19e4, -1, 0x36),
|
||||
/* fix bootloader bug */
|
||||
PHY_TUNING_ENTRY_PMA(0x1e90, -1, 0x02),
|
||||
PHY_TUNING_ENTRY_PMA(0x1e94, -1, 0x0b),
|
||||
/* improve LVCC */
|
||||
PHY_TUNING_ENTRY_PMA(0x08f0, -1, 0x30),
|
||||
PHY_TUNING_ENTRY_PMA(0x18f0, -1, 0x30),
|
||||
@@ -1698,6 +1813,10 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
phy_drd->drv_data = drv_data;
|
||||
|
||||
ret = devm_mutex_init(dev, &phy_drd->phy_mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (of_property_present(dev->of_node, "reg-names")) {
|
||||
void __iomem *reg;
|
||||
|
||||
@@ -1728,10 +1847,9 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
|
||||
|
||||
reg_pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"samsung,pmu-syscon");
|
||||
if (IS_ERR(reg_pmu)) {
|
||||
dev_err(dev, "Failed to lookup PMU regmap\n");
|
||||
return PTR_ERR(reg_pmu);
|
||||
}
|
||||
if (IS_ERR(reg_pmu))
|
||||
return dev_err_probe(dev, PTR_ERR(reg_pmu),
|
||||
"Failed to lookup PMU regmap\n");
|
||||
|
||||
/*
|
||||
* Exynos5420 SoC has multiple channels for USB 3.0 PHY, with
|
||||
@@ -1757,15 +1875,18 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to get regulators\n");
|
||||
|
||||
ret = exynos5_usbdrd_setup_notifiers(phy_drd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_vdbg(dev, "Creating usbdrd_phy phy\n");
|
||||
|
||||
for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) {
|
||||
struct phy *phy = devm_phy_create(dev, NULL, drv_data->phy_ops);
|
||||
|
||||
if (IS_ERR(phy)) {
|
||||
dev_err(dev, "Failed to create usbdrd_phy phy\n");
|
||||
return PTR_ERR(phy);
|
||||
}
|
||||
if (IS_ERR(phy))
|
||||
return dev_err_probe(dev, PTR_ERR(phy),
|
||||
"Failed to create usbdrd_phy phy\n");
|
||||
|
||||
phy_drd->phys[i].phy = phy;
|
||||
phy_drd->phys[i].index = i;
|
||||
@@ -1789,10 +1910,9 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev,
|
||||
exynos5_usbdrd_phy_xlate);
|
||||
if (IS_ERR(phy_provider)) {
|
||||
dev_err(phy_drd->dev, "Failed to register phy provider\n");
|
||||
return PTR_ERR(phy_provider);
|
||||
}
|
||||
if (IS_ERR(phy_provider))
|
||||
return dev_err_probe(phy_drd->dev, PTR_ERR(phy_provider),
|
||||
"Failed to register phy provider\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
168
drivers/phy/samsung/phy-exynosautov920-ufs.c
Normal file
168
drivers/phy/samsung/phy-exynosautov920-ufs.c
Normal file
@@ -0,0 +1,168 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* UFS PHY driver data for Samsung ExynosAuto v920 SoC
|
||||
*
|
||||
* Copyright (C) 2024 Samsung Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#include "phy-samsung-ufs.h"
|
||||
|
||||
#define EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CTRL 0x708
|
||||
#define EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CTRL_MASK 0x1
|
||||
#define EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CTRL_EN BIT(0)
|
||||
#define EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CDR_LOCK_STATUS 0x5e
|
||||
|
||||
#define EXYNOSAUTOV920_CDR_LOCK_OFFSET 0xce4
|
||||
|
||||
#define PHY_EXYNOSAUTOV920_LANE_OFFSET 0x200
|
||||
#define PHY_TRSV_REG_CFG_AUTOV920(o, v, d) \
|
||||
PHY_TRSV_REG_CFG_OFFSET(o, v, d, PHY_EXYNOSAUTOV920_LANE_OFFSET)
|
||||
|
||||
/* Calibration for phy initialization */
|
||||
static const struct samsung_ufs_phy_cfg exynosautov920_pre_init_cfg[] = {
|
||||
PHY_COMN_REG_CFG(0x29, 0x22, PWR_MODE_ANY),
|
||||
PHY_COMN_REG_CFG(0x43, 0x10, PWR_MODE_ANY),
|
||||
PHY_COMN_REG_CFG(0x3c, 0x14, PWR_MODE_ANY),
|
||||
PHY_COMN_REG_CFG(0x46, 0x48, PWR_MODE_ANY),
|
||||
PHY_COMN_REG_CFG(0x04, 0x95, PWR_MODE_ANY),
|
||||
PHY_COMN_REG_CFG(0x06, 0x30, PWR_MODE_ANY),
|
||||
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x200, 0x00, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x201, 0x06, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x202, 0x06, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x203, 0x0a, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x204, 0x00, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x205, 0x10, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x207, 0x0c, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x2e1, 0xc0, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x22d, 0xf8, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x234, 0x60, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x238, 0x13, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x239, 0x48, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x23a, 0x01, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x23b, 0x29, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x23c, 0x2a, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x23d, 0x01, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x23e, 0x14, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x23f, 0x13, PWR_MODE_ANY),
|
||||
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x240, 0x4a, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x243, 0x40, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x244, 0x02, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x25d, 0x00, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x25e, 0x3f, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x25f, 0xff, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x26f, 0xf0, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x273, 0x33, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x274, 0x50, PWR_MODE_ANY),
|
||||
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x284, 0x02, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x285, 0x02, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x2a2, 0x04, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x27d, 0x01, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x2fa, 0x01, PWR_MODE_ANY),
|
||||
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x286, 0x03, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x287, 0x03, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x288, 0x03, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x289, 0x03, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x2b3, 0x04, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x2b6, 0x0b, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x2b7, 0x0b, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x2b8, 0x0b, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x2b9, 0x0b, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x2ba, 0x0b, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x2bb, 0x06, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x2bc, 0x06, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x2bd, 0x06, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x2be, 0x06, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x34b, 0x01, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x34c, 0x24, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x34d, 0x23, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x34e, 0x45, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x34f, 0x00, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x350, 0x31, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x351, 0x00, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x352, 0x02, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x353, 0x00, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x354, 0x01, PWR_MODE_ANY),
|
||||
|
||||
PHY_COMN_REG_CFG(0x43, 0x18, PWR_MODE_ANY),
|
||||
PHY_COMN_REG_CFG(0x43, 0x00, PWR_MODE_ANY),
|
||||
|
||||
END_UFS_PHY_CFG,
|
||||
};
|
||||
|
||||
/* Calibration for HS mode series A/B */
|
||||
static const struct samsung_ufs_phy_cfg exynosautov920_pre_pwr_hs_cfg[] = {
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x369, 0x11, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x246, 0x03, PWR_MODE_ANY),
|
||||
|
||||
END_UFS_PHY_CFG,
|
||||
};
|
||||
|
||||
static const struct samsung_ufs_phy_cfg exynosautov920_post_pwr_hs_cfg[] = {
|
||||
END_UFS_PHY_CFG,
|
||||
};
|
||||
|
||||
#define DELAY_IN_US 40
|
||||
#define RETRY_CNT 100
|
||||
#define EXYNOSAUTOV920_CDR_LOCK_MASK 0x8
|
||||
|
||||
int exynosautov920_ufs_phy_wait_cdr_lock(struct phy *phy, u8 lane)
|
||||
{
|
||||
struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy);
|
||||
u32 reg, i;
|
||||
|
||||
struct samsung_ufs_phy_cfg cfg[4] = {
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x222, 0x10, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x222, 0x18, PWR_MODE_ANY),
|
||||
PHY_TRSV_REG_CFG_AUTOV920(0x246, 0x01, PWR_MODE_ANY),
|
||||
END_UFS_PHY_CFG,
|
||||
};
|
||||
|
||||
for (i = 0; i < RETRY_CNT; i++) {
|
||||
udelay(DELAY_IN_US);
|
||||
|
||||
reg = readl(ufs_phy->reg_pma + EXYNOSAUTOV920_CDR_LOCK_OFFSET +
|
||||
(PHY_APB_ADDR(PHY_EXYNOSAUTOV920_LANE_OFFSET) * lane));
|
||||
|
||||
if ((reg & EXYNOSAUTOV920_CDR_LOCK_MASK)
|
||||
== EXYNOSAUTOV920_CDR_LOCK_MASK) {
|
||||
samsung_ufs_phy_config(ufs_phy, &cfg[2], lane);
|
||||
return 0;
|
||||
}
|
||||
|
||||
udelay(DELAY_IN_US);
|
||||
|
||||
/* Disable and enable CDR */
|
||||
samsung_ufs_phy_config(ufs_phy, &cfg[0], lane);
|
||||
samsung_ufs_phy_config(ufs_phy, &cfg[1], lane);
|
||||
}
|
||||
|
||||
dev_err(ufs_phy->dev, "failed to get phy cdr lock\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static const struct samsung_ufs_phy_cfg *exynosautov920_ufs_phy_cfgs[CFG_TAG_MAX] = {
|
||||
[CFG_PRE_INIT] = exynosautov920_pre_init_cfg,
|
||||
[CFG_PRE_PWR_HS] = exynosautov920_pre_pwr_hs_cfg,
|
||||
[CFG_POST_PWR_HS] = exynosautov920_post_pwr_hs_cfg,
|
||||
};
|
||||
|
||||
static const char * const exynosautov920_ufs_phy_clks[] = {
|
||||
"ref_clk",
|
||||
};
|
||||
|
||||
const struct samsung_ufs_phy_drvdata exynosautov920_ufs_phy = {
|
||||
.cfgs = exynosautov920_ufs_phy_cfgs,
|
||||
.isol = {
|
||||
.offset = EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CTRL,
|
||||
.mask = EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CTRL_MASK,
|
||||
.en = EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CTRL_EN,
|
||||
},
|
||||
.clk_list = exynosautov920_ufs_phy_clks,
|
||||
.num_clks = ARRAY_SIZE(exynosautov920_ufs_phy_clks),
|
||||
.cdr_lock_status_offset = EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CDR_LOCK_STATUS,
|
||||
.wait_for_cdr = exynosautov920_ufs_phy_wait_cdr_lock,
|
||||
};
|
||||
@@ -28,9 +28,9 @@
|
||||
|
||||
#define PHY_DEF_LANE_CNT 1
|
||||
|
||||
static void samsung_ufs_phy_config(struct samsung_ufs_phy *phy,
|
||||
const struct samsung_ufs_phy_cfg *cfg,
|
||||
u8 lane)
|
||||
void samsung_ufs_phy_config(struct samsung_ufs_phy *phy,
|
||||
const struct samsung_ufs_phy_cfg *cfg,
|
||||
u8 lane)
|
||||
{
|
||||
enum {LANE_0, LANE_1}; /* lane index */
|
||||
|
||||
@@ -323,6 +323,9 @@ static const struct of_device_id samsung_ufs_phy_match[] = {
|
||||
}, {
|
||||
.compatible = "samsung,exynosautov9-ufs-phy",
|
||||
.data = &exynosautov9_ufs_phy,
|
||||
}, {
|
||||
.compatible = "samsung,exynosautov920-ufs-phy",
|
||||
.data = &exynosautov920_ufs_phy,
|
||||
}, {
|
||||
.compatible = "tesla,fsd-ufs-phy",
|
||||
.data = &fsd_ufs_phy,
|
||||
|
||||
@@ -143,9 +143,13 @@ static inline void samsung_ufs_phy_ctrl_isol(
|
||||
}
|
||||
|
||||
int samsung_ufs_phy_wait_for_lock_acq(struct phy *phy, u8 lane);
|
||||
int exynosautov920_ufs_phy_wait_cdr_lock(struct phy *phy, u8 lane);
|
||||
void samsung_ufs_phy_config(struct samsung_ufs_phy *phy,
|
||||
const struct samsung_ufs_phy_cfg *cfg, u8 lane);
|
||||
|
||||
extern const struct samsung_ufs_phy_drvdata exynos7_ufs_phy;
|
||||
extern const struct samsung_ufs_phy_drvdata exynosautov9_ufs_phy;
|
||||
extern const struct samsung_ufs_phy_drvdata exynosautov920_ufs_phy;
|
||||
extern const struct samsung_ufs_phy_drvdata fsd_ufs_phy;
|
||||
extern const struct samsung_ufs_phy_drvdata tensor_gs101_ufs_phy;
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/phy/phy.h>
|
||||
|
||||
#define PHYPARAM_REG 1
|
||||
#define PHYCTRL_REG 2
|
||||
#define PHYPARAM_REG 0
|
||||
#define PHYCTRL_REG 1
|
||||
|
||||
/* Default PHY_SEL and REFCLKSEL configuration */
|
||||
#define STIH407_USB_PICOPHY_CTRL_PORT_CONF 0x6
|
||||
@@ -91,8 +91,8 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct phy_provider *phy_provider;
|
||||
unsigned int syscon_args[2];
|
||||
struct phy *phy;
|
||||
int ret;
|
||||
|
||||
phy_dev = devm_kzalloc(dev, sizeof(*phy_dev), GFP_KERNEL);
|
||||
if (!phy_dev)
|
||||
@@ -116,25 +116,15 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev)
|
||||
/* Reset port by default: only deassert it in phy init */
|
||||
reset_control_assert(phy_dev->rstport);
|
||||
|
||||
phy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
|
||||
phy_dev->regmap = syscon_regmap_lookup_by_phandle_args(np, "st,syscfg",
|
||||
2, syscon_args);
|
||||
if (IS_ERR(phy_dev->regmap)) {
|
||||
dev_err(dev, "No syscfg phandle specified\n");
|
||||
return PTR_ERR(phy_dev->regmap);
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_index(np, "st,syscfg", PHYPARAM_REG,
|
||||
&phy_dev->param);
|
||||
if (ret) {
|
||||
dev_err(dev, "can't get phyparam offset (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_index(np, "st,syscfg", PHYCTRL_REG,
|
||||
&phy_dev->ctrl);
|
||||
if (ret) {
|
||||
dev_err(dev, "can't get phyctrl offset (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
phy_dev->param = syscon_args[PHYPARAM_REG];
|
||||
phy_dev->ctrl = syscon_args[PHYCTRL_REG];
|
||||
|
||||
phy = devm_phy_create(dev, NULL, &stih407_usb2_picophy_data);
|
||||
if (IS_ERR(phy)) {
|
||||
|
||||
@@ -227,8 +227,6 @@ int phy_pm_runtime_get(struct phy *phy);
|
||||
int phy_pm_runtime_get_sync(struct phy *phy);
|
||||
int phy_pm_runtime_put(struct phy *phy);
|
||||
int phy_pm_runtime_put_sync(struct phy *phy);
|
||||
void phy_pm_runtime_allow(struct phy *phy);
|
||||
void phy_pm_runtime_forbid(struct phy *phy);
|
||||
int phy_init(struct phy *phy);
|
||||
int phy_exit(struct phy *phy);
|
||||
int phy_power_on(struct phy *phy);
|
||||
@@ -321,16 +319,6 @@ static inline int phy_pm_runtime_put_sync(struct phy *phy)
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline void phy_pm_runtime_allow(struct phy *phy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void phy_pm_runtime_forbid(struct phy *phy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int phy_init(struct phy *phy)
|
||||
{
|
||||
if (!phy)
|
||||
|
||||
Reference in New Issue
Block a user