diff options
Diffstat (limited to 'drivers/phy/qualcomm')
22 files changed, 2376 insertions, 918 deletions
diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig index 97ca5952e34e..d891058b7c39 100644 --- a/drivers/phy/qualcomm/Kconfig +++ b/drivers/phy/qualcomm/Kconfig @@ -102,6 +102,16 @@ config PHY_QCOM_QMP_USB Enable this to support the QMP USB PHY transceiver that is used with USB3 controllers on Qualcomm chips. +config PHY_QCOM_QMP_USB_LEGACY + tristate "Qualcomm QMP legacy USB PHY Driver" + select GENERIC_PHY + default n + help + Enable this legacy driver to support the QMP USB+DisplayPort Combo + PHY transceivers working only in USB3 mode on Qualcomm chips. This + driver exists only for compatibility with older device trees, + existing users have been migrated to PHY_QCOM_QMP_COMBO driver. + endif # PHY_QCOM_QMP config PHY_QCOM_QUSB2 @@ -133,6 +143,17 @@ config PHY_QCOM_EUSB2_REPEATER PMICs. The repeater is paired with a Synopsys eUSB2 Phy on Qualcomm SOCs. +config PHY_QCOM_M31_USB + tristate "Qualcomm M31 HS PHY driver support" + depends on USB && (ARCH_QCOM || COMPILE_TEST) + select GENERIC_PHY + help + Enable this to support M31 HS PHY transceivers on Qualcomm chips + with DWC3 USB core. It handles PHY initialization, clock + management required after resetting the hardware and power + management. This driver is required even for peripheral only or + host only mode configurations. + config PHY_QCOM_USB_HS tristate "Qualcomm USB HS PHY module" depends on USB_ULPI_BUS diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile index b030858e0f8d..ffd609ac6233 100644 --- a/drivers/phy/qualcomm/Makefile +++ b/drivers/phy/qualcomm/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o obj-$(CONFIG_PHY_QCOM_EDP) += phy-qcom-edp.o obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o +obj-$(CONFIG_PHY_QCOM_M31_USB) += phy-qcom-m31.o obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o @@ -11,6 +12,7 @@ obj-$(CONFIG_PHY_QCOM_QMP_PCIE) += phy-qcom-qmp-pcie.o obj-$(CONFIG_PHY_QCOM_QMP_PCIE_8996) += phy-qcom-qmp-pcie-msm8996.o obj-$(CONFIG_PHY_QCOM_QMP_UFS) += phy-qcom-qmp-ufs.o obj-$(CONFIG_PHY_QCOM_QMP_USB) += phy-qcom-qmp-usb.o +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 diff --git a/drivers/phy/qualcomm/phy-ath79-usb.c b/drivers/phy/qualcomm/phy-ath79-usb.c index 09a77e556ece..f8d0199c6e78 100644 --- a/drivers/phy/qualcomm/phy-ath79-usb.c +++ b/drivers/phy/qualcomm/phy-ath79-usb.c @@ -5,6 +5,7 @@ * Copyright (C) 2015-2018 Alban Bedel <albeu@free.fr> */ +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/phy/phy.h> diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c index 5c4305df7d53..8e5078304646 100644 --- a/drivers/phy/qualcomm/phy-qcom-edp.c +++ b/drivers/phy/qualcomm/phy-qcom-edp.c @@ -13,8 +13,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_address.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c index 90f8543ba265..52c275fbb2a1 100644 --- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c +++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c @@ -8,7 +8,6 @@ #include <linux/regulator/consumer.h> #include <linux/regmap.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/phy/phy.h> /* eUSB2 status registers */ diff --git a/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c b/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c index d3e7d5e1d1b6..da6f290af722 100644 --- a/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-ipq4019-usb.c @@ -13,8 +13,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h> -#include <linux/of_platform.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/reset.h> diff --git a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c index 7bacc527fbad..06392ed7c91b 100644 --- a/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-usb.c @@ -4,7 +4,7 @@ #include <linux/err.h> #include <linux/io.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/delay.h> diff --git a/drivers/phy/qualcomm/phy-qcom-m31.c b/drivers/phy/qualcomm/phy-qcom-m31.c new file mode 100644 index 000000000000..ed08072ca032 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-m31.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2014-2023, The Linux Foundation. All rights reserved. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/reset.h> +#include <linux/slab.h> + +#define USB2PHY_PORT_UTMI_CTRL1 0x40 + +#define USB2PHY_PORT_UTMI_CTRL2 0x44 + #define UTMI_ULPI_SEL BIT(7) + #define UTMI_TEST_MUX_SEL BIT(6) + +#define HS_PHY_CTRL_REG 0x10 + #define UTMI_OTG_VBUS_VALID BIT(20) + #define SW_SESSVLD_SEL BIT(28) + +#define USB_PHY_UTMI_CTRL0 0x3c + +#define USB_PHY_UTMI_CTRL5 0x50 + #define POR_EN BIT(1) + +#define USB_PHY_HS_PHY_CTRL_COMMON0 0x54 + #define COMMONONN BIT(7) + #define FSEL BIT(4) + #define RETENABLEN BIT(3) + #define FREQ_24MHZ (BIT(6) | BIT(4)) + +#define USB_PHY_HS_PHY_CTRL2 0x64 + #define USB2_SUSPEND_N_SEL BIT(3) + #define USB2_SUSPEND_N BIT(2) + #define USB2_UTMI_CLK_EN BIT(1) + +#define USB_PHY_CFG0 0x94 + #define UTMI_PHY_OVERRIDE_EN BIT(1) + +#define USB_PHY_REFCLK_CTRL 0xa0 + #define CLKCORE BIT(1) + +#define USB2PHY_PORT_POWERDOWN 0xa4 + #define POWER_UP BIT(0) + #define POWER_DOWN 0 + +#define USB_PHY_FSEL_SEL 0xb8 + #define FREQ_SEL BIT(0) + +#define USB2PHY_USB_PHY_M31_XCFGI_1 0xbc + #define USB2_0_TX_ENABLE BIT(2) + +#define USB2PHY_USB_PHY_M31_XCFGI_4 0xc8 + #define HSTX_SLEW_RATE_565PS GENMASK(1, 0) + #define PLL_CHARGING_PUMP_CURRENT_35UA GENMASK(4, 3) + #define ODT_VALUE_38_02_OHM GENMASK(7, 6) + +#define USB2PHY_USB_PHY_M31_XCFGI_5 0xcc + #define ODT_VALUE_45_02_OHM BIT(2) + #define HSTX_PRE_EMPHASIS_LEVEL_0_55MA BIT(0) + +#define USB2PHY_USB_PHY_M31_XCFGI_11 0xe4 + #define XCFG_COARSE_TUNE_NUM BIT(1) + #define XCFG_FINE_TUNE_NUM BIT(3) + +struct m31_phy_regs { + u32 off; + u32 val; + u32 delay; +}; + +struct m31_priv_data { + bool ulpi_mode; + const struct m31_phy_regs *regs; + unsigned int nregs; +}; + +struct m31_phy_regs m31_ipq5332_regs[] = { + { + USB_PHY_CFG0, + UTMI_PHY_OVERRIDE_EN, + 0 + }, + { + USB_PHY_UTMI_CTRL5, + POR_EN, + 15 + }, + { + USB_PHY_FSEL_SEL, + FREQ_SEL, + 0 + }, + { + USB_PHY_HS_PHY_CTRL_COMMON0, + COMMONONN | FREQ_24MHZ | RETENABLEN, + 0 + }, + { + USB_PHY_UTMI_CTRL5, + POR_EN, + 0 + }, + { + USB_PHY_HS_PHY_CTRL2, + USB2_SUSPEND_N_SEL | USB2_SUSPEND_N | USB2_UTMI_CLK_EN, + 0 + }, + { + USB2PHY_USB_PHY_M31_XCFGI_11, + XCFG_COARSE_TUNE_NUM | XCFG_FINE_TUNE_NUM, + 0 + }, + { + USB2PHY_USB_PHY_M31_XCFGI_4, + HSTX_SLEW_RATE_565PS | PLL_CHARGING_PUMP_CURRENT_35UA | ODT_VALUE_38_02_OHM, + 0 + }, + { + USB2PHY_USB_PHY_M31_XCFGI_1, + USB2_0_TX_ENABLE, + 0 + }, + { + USB2PHY_USB_PHY_M31_XCFGI_5, + ODT_VALUE_45_02_OHM | HSTX_PRE_EMPHASIS_LEVEL_0_55MA, + 4 + }, + { + USB_PHY_UTMI_CTRL5, + 0x0, + 0 + }, + { + USB_PHY_HS_PHY_CTRL2, + USB2_SUSPEND_N | USB2_UTMI_CLK_EN, + 0 + }, +}; + +struct m31usb_phy { + struct phy *phy; + void __iomem *base; + const struct m31_phy_regs *regs; + int nregs; + + struct regulator *vreg; + struct clk *clk; + struct reset_control *reset; + + bool ulpi_mode; +}; + +static int m31usb_phy_init(struct phy *phy) +{ + struct m31usb_phy *qphy = phy_get_drvdata(phy); + const struct m31_phy_regs *regs = qphy->regs; + int i, ret; + + ret = regulator_enable(qphy->vreg); + if (ret) { + dev_err(&phy->dev, "failed to enable regulator, %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(qphy->clk); + if (ret) { + if (qphy->vreg) + regulator_disable(qphy->vreg); + dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret); + return ret; + } + + /* Perform phy reset */ + reset_control_assert(qphy->reset); + udelay(5); + reset_control_deassert(qphy->reset); + + /* configure for ULPI mode if requested */ + if (qphy->ulpi_mode) + writel(0x0, qphy->base + USB2PHY_PORT_UTMI_CTRL2); + + /* Enable the PHY */ + writel(POWER_UP, qphy->base + USB2PHY_PORT_POWERDOWN); + + /* Turn on phy ref clock */ + for (i = 0; i < qphy->nregs; i++) { + writel(regs[i].val, qphy->base + regs[i].off); + if (regs[i].delay) + udelay(regs[i].delay); + } + + return 0; +} + +static int m31usb_phy_shutdown(struct phy *phy) +{ + struct m31usb_phy *qphy = phy_get_drvdata(phy); + + /* Disable the PHY */ + writel_relaxed(POWER_DOWN, qphy->base + USB2PHY_PORT_POWERDOWN); + + clk_disable_unprepare(qphy->clk); + + regulator_disable(qphy->vreg); + + return 0; +} + +static const struct phy_ops m31usb_phy_gen_ops = { + .power_on = m31usb_phy_init, + .power_off = m31usb_phy_shutdown, + .owner = THIS_MODULE, +}; + +static int m31usb_phy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + const struct m31_priv_data *data; + struct device *dev = &pdev->dev; + struct m31usb_phy *qphy; + + qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL); + if (!qphy) + return -ENOMEM; + + qphy->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(qphy->base)) + return PTR_ERR(qphy->base); + + qphy->reset = devm_reset_control_get_exclusive_by_index(dev, 0); + if (IS_ERR(qphy->reset)) + return PTR_ERR(qphy->reset); + + qphy->clk = devm_clk_get(dev, NULL); + if (IS_ERR(qphy->clk)) + return dev_err_probe(dev, PTR_ERR(qphy->clk), + "failed to get clk\n"); + + data = of_device_get_match_data(dev); + qphy->regs = data->regs; + qphy->nregs = data->nregs; + qphy->ulpi_mode = data->ulpi_mode; + + qphy->phy = devm_phy_create(dev, NULL, &m31usb_phy_gen_ops); + if (IS_ERR(qphy->phy)) + return dev_err_probe(dev, PTR_ERR(qphy->phy), + "failed to create phy\n"); + + qphy->vreg = devm_regulator_get(dev, "vdda-phy"); + if (IS_ERR(qphy->vreg)) + return dev_err_probe(dev, PTR_ERR(qphy->phy), + "failed to get vreg\n"); + + phy_set_drvdata(qphy->phy, qphy); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (!IS_ERR(phy_provider)) + dev_info(dev, "Registered M31 USB phy\n"); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct m31_priv_data m31_ipq5332_data = { + .ulpi_mode = false, + .regs = m31_ipq5332_regs, + .nregs = ARRAY_SIZE(m31_ipq5332_regs), +}; + +static const struct of_device_id m31usb_phy_id_table[] = { + { .compatible = "qcom,ipq5332-usb-hsphy", .data = &m31_ipq5332_data }, + { }, +}; +MODULE_DEVICE_TABLE(of, m31usb_phy_id_table); + +static struct platform_driver m31usb_phy_driver = { + .probe = m31usb_phy_probe, + .driver = { + .name = "qcom-m31usb-phy", + .of_match_table = m31usb_phy_id_table, + }, +}; + +module_platform_driver(m31usb_phy_driver); + +MODULE_DESCRIPTION("USB2 Qualcomm M31 HSPHY driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index bebce8c591a3..cbb28afce135 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -12,7 +12,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/of_address.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> @@ -106,6 +105,20 @@ enum qphy_reg_layout { QPHY_PCS_AUTONOMOUS_MODE_CTRL, QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR, QPHY_PCS_POWER_DOWN_CONTROL, + + QPHY_COM_RESETSM_CNTRL, + QPHY_COM_C_READY_STATUS, + QPHY_COM_CMN_STATUS, + QPHY_COM_BIAS_EN_CLKBUFLR_EN, + + QPHY_DP_PHY_STATUS, + + QPHY_TX_TX_POL_INV, + QPHY_TX_TX_DRV_LVL, + QPHY_TX_TX_EMP_POST1_LVL, + QPHY_TX_HIGHZ_DRVR_EN, + QPHY_TX_TRANSCEIVER_BIAS_EN, + /* Keep last to ensure regs_layout arrays are properly initialized */ QPHY_LAYOUT_SIZE }; @@ -117,9 +130,22 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_POWER_DOWN_CONTROL, [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL, [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR, + + [QPHY_COM_RESETSM_CNTRL] = QSERDES_V3_COM_RESETSM_CNTRL, + [QPHY_COM_C_READY_STATUS] = QSERDES_V3_COM_C_READY_STATUS, + [QPHY_COM_CMN_STATUS] = QSERDES_V3_COM_CMN_STATUS, + [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, + + [QPHY_DP_PHY_STATUS] = QSERDES_V3_DP_PHY_STATUS, + + [QPHY_TX_TX_POL_INV] = QSERDES_V3_TX_TX_POL_INV, + [QPHY_TX_TX_DRV_LVL] = QSERDES_V3_TX_TX_DRV_LVL, + [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V3_TX_TX_EMP_POST1_LVL, + [QPHY_TX_HIGHZ_DRVR_EN] = QSERDES_V3_TX_HIGHZ_DRVR_EN, + [QPHY_TX_TRANSCEIVER_BIAS_EN] = QSERDES_V3_TX_TRANSCEIVER_BIAS_EN, }; -static const unsigned int qmp_v4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { +static const unsigned int qmp_v45_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_SW_RESET] = QPHY_V4_PCS_SW_RESET, [QPHY_START_CTRL] = QPHY_V4_PCS_START_CONTROL, [QPHY_PCS_STATUS] = QPHY_V4_PCS_PCS_STATUS1, @@ -128,6 +154,67 @@ static const unsigned int qmp_v4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { /* In PCS_USB */ [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_CTRL, [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V4_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR, + + [QPHY_COM_RESETSM_CNTRL] = QSERDES_V4_COM_RESETSM_CNTRL, + [QPHY_COM_C_READY_STATUS] = QSERDES_V4_COM_C_READY_STATUS, + [QPHY_COM_CMN_STATUS] = QSERDES_V4_COM_CMN_STATUS, + [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN, + + [QPHY_DP_PHY_STATUS] = QSERDES_V4_DP_PHY_STATUS, + + [QPHY_TX_TX_POL_INV] = QSERDES_V4_TX_TX_POL_INV, + [QPHY_TX_TX_DRV_LVL] = QSERDES_V4_TX_TX_DRV_LVL, + [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V4_TX_TX_EMP_POST1_LVL, + [QPHY_TX_HIGHZ_DRVR_EN] = QSERDES_V4_TX_HIGHZ_DRVR_EN, + [QPHY_TX_TRANSCEIVER_BIAS_EN] = QSERDES_V4_TX_TRANSCEIVER_BIAS_EN, +}; + +static const unsigned int qmp_v5_5nm_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V5_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V5_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V5_PCS_PCS_STATUS1, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V5_PCS_POWER_DOWN_CONTROL, + + /* In PCS_USB */ + [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V5_PCS_USB3_AUTONOMOUS_MODE_CTRL, + [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V5_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR, + + [QPHY_COM_RESETSM_CNTRL] = QSERDES_V5_COM_RESETSM_CNTRL, + [QPHY_COM_C_READY_STATUS] = QSERDES_V5_COM_C_READY_STATUS, + [QPHY_COM_CMN_STATUS] = QSERDES_V5_COM_CMN_STATUS, + [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, + + [QPHY_DP_PHY_STATUS] = QSERDES_V5_DP_PHY_STATUS, + + [QPHY_TX_TX_POL_INV] = QSERDES_V5_5NM_TX_TX_POL_INV, + [QPHY_TX_TX_DRV_LVL] = QSERDES_V5_5NM_TX_TX_DRV_LVL, + [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V5_5NM_TX_TX_EMP_POST1_LVL, + [QPHY_TX_HIGHZ_DRVR_EN] = QSERDES_V5_5NM_TX_HIGHZ_DRVR_EN, + [QPHY_TX_TRANSCEIVER_BIAS_EN] = QSERDES_V5_5NM_TX_TRANSCEIVER_BIAS_EN, +}; + +static const unsigned int qmp_v6_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V5_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V5_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V5_PCS_PCS_STATUS1, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V5_PCS_POWER_DOWN_CONTROL, + + /* In PCS_USB */ + [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V5_PCS_USB3_AUTONOMOUS_MODE_CTRL, + [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V5_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR, + + [QPHY_COM_RESETSM_CNTRL] = QSERDES_V6_COM_RESETSM_CNTRL, + [QPHY_COM_C_READY_STATUS] = QSERDES_V6_COM_C_READY_STATUS, + [QPHY_COM_CMN_STATUS] = QSERDES_V6_COM_CMN_STATUS, + [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN, + + [QPHY_DP_PHY_STATUS] = QSERDES_V6_DP_PHY_STATUS, + + [QPHY_TX_TX_POL_INV] = QSERDES_V6_TX_TX_POL_INV, + [QPHY_TX_TX_DRV_LVL] = QSERDES_V6_TX_TX_DRV_LVL, + [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V6_TX_TX_EMP_POST1_LVL, + [QPHY_TX_HIGHZ_DRVR_EN] = QSERDES_V6_TX_HIGHZ_DRVR_EN, + [QPHY_TX_TRANSCEIVER_BIAS_EN] = QSERDES_V6_TX_TRANSCEIVER_BIAS_EN, }; static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = { @@ -1271,9 +1358,6 @@ struct qmp_phy_cfg { int (*calibrate_dp_phy)(struct qmp_combo *qmp); void (*dp_aux_init)(struct qmp_combo *qmp); - /* clock ids to be requested */ - const char * const *clk_list; - int num_clks; /* resets to be requested */ const char * const *reset_list; int num_resets; @@ -1315,6 +1399,7 @@ struct qmp_combo { struct clk *pipe_clk; struct clk_bulk_data *clks; + int num_clks; struct reset_control_bulk_data *resets; struct regulator_bulk_data *vregs; @@ -1350,11 +1435,6 @@ static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp); static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp); static int qmp_v4_calibrate_dp_phy(struct qmp_combo *qmp); -static int qmp_v5_configure_dp_phy(struct qmp_combo *qmp); - -static void qmp_v6_dp_aux_init(struct qmp_combo *qmp); -static int qmp_v6_configure_dp_phy(struct qmp_combo *qmp); - static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) { u32 reg; @@ -1380,19 +1460,10 @@ static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val) } /* list of clocks required by phy */ -static const char * const qmp_v3_phy_clk_l[] = { +static const char * const qmp_combo_phy_clk_l[] = { "aux", "cfg_ahb", "ref", "com_aux", }; -static const char * const qmp_v4_phy_clk_l[] = { - "aux", "ref", "com_aux", -}; - -/* the primary usb3 phy on sm8250 doesn't have a ref clock */ -static const char * const qmp_v4_sm8250_usbphy_clk_l[] = { - "aux", "ref_clk_src", "com_aux" -}; - /* list of resets */ static const char * const msm8996_usb3phy_reset_l[] = { "phy", "common", @@ -1433,6 +1504,8 @@ static const struct qmp_combo_offsets qmp_combo_offsets_v5 = { }; static const struct qmp_phy_cfg sc7180_usb3dpphy_cfg = { + .offsets = &qmp_combo_offsets_v3, + .serdes_tbl = qmp_v3_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), .tx_tbl = qmp_v3_usb3_tx_tbl, @@ -1466,8 +1539,6 @@ static const struct qmp_phy_cfg sc7180_usb3dpphy_cfg = { .configure_dp_phy = qmp_v3_configure_dp_phy, .calibrate_dp_phy = qmp_v3_calibrate_dp_phy, - .clk_list = qmp_v3_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), .reset_list = sc7180_usb3phy_reset_l, .num_resets = ARRAY_SIZE(sc7180_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, @@ -1478,6 +1549,8 @@ static const struct qmp_phy_cfg sc7180_usb3dpphy_cfg = { }; static const struct qmp_phy_cfg sdm845_usb3dpphy_cfg = { + .offsets = &qmp_combo_offsets_v3, + .serdes_tbl = qmp_v3_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), .tx_tbl = qmp_v3_usb3_tx_tbl, @@ -1511,8 +1584,6 @@ static const struct qmp_phy_cfg sdm845_usb3dpphy_cfg = { .configure_dp_phy = qmp_v3_configure_dp_phy, .calibrate_dp_phy = qmp_v3_calibrate_dp_phy, - .clk_list = qmp_v3_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, @@ -1523,6 +1594,8 @@ static const struct qmp_phy_cfg sdm845_usb3dpphy_cfg = { }; static const struct qmp_phy_cfg sc8180x_usb3dpphy_cfg = { + .offsets = &qmp_combo_offsets_v3, + .serdes_tbl = sm8150_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), .tx_tbl = sm8150_usb3_tx_tbl, @@ -1558,13 +1631,11 @@ static const struct qmp_phy_cfg sc8180x_usb3dpphy_cfg = { .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, - .clk_list = qmp_v4_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v4_usb3phy_regs_layout, + .regs = qmp_v45_usb3phy_regs_layout, .pcs_usb_offset = 0x300, .has_pwrdn_delay = true, @@ -1603,16 +1674,14 @@ static const struct qmp_phy_cfg sc8280xp_usb43dpphy_cfg = { .dp_aux_init = qmp_v4_dp_aux_init, .configure_dp_tx = qmp_v4_configure_dp_tx, - .configure_dp_phy = qmp_v5_configure_dp_phy, + .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, - .clk_list = qmp_v4_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v4_usb3phy_regs_layout, + .regs = qmp_v5_5nm_usb3phy_regs_layout, }; static const struct qmp_phy_cfg sm6350_usb3dpphy_cfg = { @@ -1651,8 +1720,6 @@ static const struct qmp_phy_cfg sm6350_usb3dpphy_cfg = { .configure_dp_phy = qmp_v3_configure_dp_phy, .calibrate_dp_phy = qmp_v3_calibrate_dp_phy, - .clk_list = qmp_v4_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, @@ -1661,6 +1728,8 @@ static const struct qmp_phy_cfg sm6350_usb3dpphy_cfg = { }; static const struct qmp_phy_cfg sm8250_usb3dpphy_cfg = { + .offsets = &qmp_combo_offsets_v3, + .serdes_tbl = sm8150_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), .tx_tbl = sm8250_usb3_tx_tbl, @@ -1696,13 +1765,11 @@ static const struct qmp_phy_cfg sm8250_usb3dpphy_cfg = { .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, - .clk_list = qmp_v4_sm8250_usbphy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_sm8250_usbphy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v4_usb3phy_regs_layout, + .regs = qmp_v45_usb3phy_regs_layout, .pcs_usb_offset = 0x300, .has_pwrdn_delay = true, @@ -1746,13 +1813,11 @@ static const struct qmp_phy_cfg sm8350_usb3dpphy_cfg = { .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, - .clk_list = qmp_v4_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v4_usb3phy_regs_layout, + .regs = qmp_v45_usb3phy_regs_layout, .has_pwrdn_delay = true, }; @@ -1790,14 +1855,12 @@ static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = { .swing_hbr3_hbr2 = &qmp_dp_v5_voltage_swing_hbr3_hbr2, .pre_emphasis_hbr3_hbr2 = &qmp_dp_v5_pre_emphasis_hbr3_hbr2, - .dp_aux_init = qmp_v6_dp_aux_init, + .dp_aux_init = qmp_v4_dp_aux_init, .configure_dp_tx = qmp_v4_configure_dp_tx, - .configure_dp_phy = qmp_v6_configure_dp_phy, + .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, - .regs = qmp_v4_usb3phy_regs_layout, - .clk_list = qmp_v4_phy_clk_l, - .num_clks = ARRAY_SIZE(qmp_v4_phy_clk_l), + .regs = qmp_v6_usb3phy_regs_layout, .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, @@ -1865,6 +1928,8 @@ static int qmp_combo_dp_serdes_init(struct qmp_combo *qmp) static void qmp_v3_dp_aux_init(struct qmp_combo *qmp) { + const struct qmp_phy_cfg *cfg = qmp->cfg; + writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); @@ -1872,7 +1937,7 @@ static void qmp_v3_dp_aux_init(struct qmp_combo *qmp) /* Turn on BIAS current for PHY/PLL */ writel(QSERDES_V3_COM_BIAS_EN | QSERDES_V3_COM_BIAS_EN_MUX | QSERDES_V3_COM_CLKBUF_L_EN | QSERDES_V3_COM_EN_SYSCLK_TX_SEL, - qmp->dp_serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN); + qmp->dp_serdes + cfg->regs[QPHY_COM_BIAS_EN_CLKBUFLR_EN]); writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); @@ -1886,7 +1951,7 @@ static void qmp_v3_dp_aux_init(struct qmp_combo *qmp) QSERDES_V3_COM_BIAS_EN_MUX | QSERDES_V3_COM_CLKBUF_R_EN | QSERDES_V3_COM_CLKBUF_L_EN | QSERDES_V3_COM_EN_SYSCLK_TX_SEL | QSERDES_V3_COM_CLKBUF_RX_DRIVE_L, - qmp->dp_serdes + QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN); + qmp->dp_serdes + cfg->regs[QPHY_COM_BIAS_EN_CLKBUFLR_EN]); writel(0x00, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG0); writel(0x13, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG1); @@ -1906,8 +1971,7 @@ static void qmp_v3_dp_aux_init(struct qmp_combo *qmp) qmp->dp_dp_phy + QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK); } -static int qmp_combo_configure_dp_swing(struct qmp_combo *qmp, - unsigned int drv_lvl_reg, unsigned int emp_post_reg) +static int qmp_combo_configure_dp_swing(struct qmp_combo *qmp) { const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -1936,10 +2000,10 @@ static int qmp_combo_configure_dp_swing(struct qmp_combo *qmp, voltage_swing_cfg |= DP_PHY_TXn_TX_DRV_LVL_MUX_EN; pre_emphasis_cfg |= DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN; - writel(voltage_swing_cfg, qmp->dp_tx + drv_lvl_reg); - writel(pre_emphasis_cfg, qmp->dp_tx + emp_post_reg); - writel(voltage_swing_cfg, qmp->dp_tx2 + drv_lvl_reg); - writel(pre_emphasis_cfg, qmp->dp_tx2 + emp_post_reg); + writel(voltage_swing_cfg, qmp->dp_tx + cfg->regs[QPHY_TX_TX_DRV_LVL]); + writel(pre_emphasis_cfg, qmp->dp_tx + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); + writel(voltage_swing_cfg, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_DRV_LVL]); + writel(pre_emphasis_cfg, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); return 0; } @@ -1949,8 +2013,7 @@ static void qmp_v3_configure_dp_tx(struct qmp_combo *qmp) const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; u32 bias_en, drvr_en; - if (qmp_combo_configure_dp_swing(qmp, QSERDES_V3_TX_TX_DRV_LVL, - QSERDES_V3_TX_TX_EMP_POST1_LVL) < 0) + if (qmp_combo_configure_dp_swing(qmp) < 0) return; if (dp_opts->lanes == 1) { @@ -1991,17 +2054,12 @@ static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp) return reverse; } -static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp) +static int qmp_combo_configure_dp_clocks(struct qmp_combo *qmp) { const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; - u32 phy_vco_div, status; + u32 phy_vco_div; unsigned long pixel_freq; - qmp_combo_configure_dp_mode(qmp); - - writel(0x05, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL); - writel(0x05, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL); - switch (dp_opts->link_rate) { case 1620: phy_vco_div = 0x1; @@ -2023,20 +2081,38 @@ static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp) /* Other link rates aren't supported */ return -EINVAL; } - writel(phy_vco_div, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_VCO_DIV); + writel(phy_vco_div, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_VCO_DIV); clk_set_rate(qmp->dp_link_hw.clk, dp_opts->link_rate * 100000); clk_set_rate(qmp->dp_pixel_hw.clk, pixel_freq); + return 0; +} + +static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + u32 status; + int ret; + + qmp_combo_configure_dp_mode(qmp); + + writel(0x05, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL); + writel(0x05, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL); + + ret = qmp_combo_configure_dp_clocks(qmp); + if (ret) + return ret; + writel(0x04, qmp->dp_dp_phy + QSERDES_DP_PHY_AUX_CFG2); writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); writel(0x05, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); writel(0x01, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); writel(0x09, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG); - writel(0x20, qmp->dp_serdes + QSERDES_V3_COM_RESETSM_CNTRL); + writel(0x20, qmp->dp_serdes + cfg->regs[QPHY_COM_RESETSM_CNTRL]); |