diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-06 02:14:12 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-06 02:14:12 +0300 |
commit | 07c4dd3435aa387d3b58f4e941dc516513f14507 (patch) | |
tree | 26ebc60562ba573ec499f850c53ffd48f2bfdf72 /drivers/phy/qualcomm | |
parent | f60342fac9fae20ada2cd5faadbc2a1337cae03f (diff) | |
parent | c2ef60fea2dc7f903450926aee1f9c282ea529ca (diff) | |
download | linux-07c4dd3435aa387d3b58f4e941dc516513f14507.tar.xz |
Merge tag 'usb-4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB and PHY updates from Greg KH:
"Here is the big USB pull request for 4.18-rc1.
Lots of stuff here, the highlights are:
- phy driver updates and new additions
- usual set of xhci driver updates
- normal set of musb updates
- gadget driver updates and new controllers
- typec work, it's getting closer to getting fully out of the staging
portion of the tree.
- lots of minor cleanups and bugfixes.
All of these have been in linux-next for a while with no reported
issues"
* tag 'usb-4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (263 commits)
Revert "xhci: Reset Renesas uPD72020x USB controller for 32-bit DMA issue"
xhci: Add quirk to zero 64bit registers on Renesas PCIe controllers
xhci: Allow more than 32 quirks
usb: xhci: force all memory allocations to node
selftests: add test for USB over IP driver
USB: typec: fsusb302: no need to check return value of debugfs_create_dir()
USB: gadget: udc: s3c2410_udc: no need to check return value of debugfs_create functions
USB: gadget: udc: renesas_usb3: no need to check return value of debugfs_create functions
USB: gadget: udc: pxa27x_udc: no need to check return value of debugfs_create functions
USB: gadget: udc: gr_udc: no need to check return value of debugfs_create functions
USB: gadget: udc: bcm63xx_udc: no need to check return value of debugfs_create functions
USB: udc: atmel_usba_udc: no need to check return value of debugfs_create functions
USB: dwc3: no need to check return value of debugfs_create functions
USB: dwc2: no need to check return value of debugfs_create functions
USB: core: no need to check return value of debugfs_create functions
USB: chipidea: no need to check return value of debugfs_create functions
USB: ehci-hcd: no need to check return value of debugfs_create functions
USB: fhci-hcd: no need to check return value of debugfs_create functions
USB: fotg210-hcd: no need to check return value of debugfs_create functions
USB: imx21-hcd: no need to check return value of debugfs_create functions
...
Diffstat (limited to 'drivers/phy/qualcomm')
-rw-r--r-- | drivers/phy/qualcomm/Kconfig | 11 | ||||
-rw-r--r-- | drivers/phy/qualcomm/Makefile | 1 | ||||
-rw-r--r-- | drivers/phy/qualcomm/phy-ath79-usb.c | 108 | ||||
-rw-r--r-- | drivers/phy/qualcomm/phy-qcom-qmp.c | 169 | ||||
-rw-r--r-- | drivers/phy/qualcomm/phy-qcom-qmp.h | 5 | ||||
-rw-r--r-- | drivers/phy/qualcomm/phy-qcom-qusb2.c | 130 |
6 files changed, 400 insertions, 24 deletions
diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig index 7bfa64baf837..632a0e73ee10 100644 --- a/drivers/phy/qualcomm/Kconfig +++ b/drivers/phy/qualcomm/Kconfig @@ -1,6 +1,15 @@ # -# Phy drivers for Qualcomm platforms +# Phy drivers for Qualcomm and Atheros platforms # +config PHY_ATH79_USB + tristate "Atheros AR71XX/9XXX USB PHY driver" + depends on OF && (ATH79 || COMPILE_TEST) + default y if USB_EHCI_HCD_PLATFORM || USB_OHCI_HCD_PLATFORM + select RESET_CONTROLLER + select GENERIC_PHY + help + Enable this to support the USB PHY on Atheros AR71XX/9XXX SoCs. + config PHY_QCOM_APQ8064_SATA tristate "Qualcomm APQ8064 SATA SerDes/PHY driver" depends on ARCH_QCOM diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile index 9abb7899762a..deb831f453ae 100644 --- a/drivers/phy/qualcomm/Makefile +++ b/drivers/phy/qualcomm/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PHY_ATH79_USB) += phy-ath79-usb.o obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o diff --git a/drivers/phy/qualcomm/phy-ath79-usb.c b/drivers/phy/qualcomm/phy-ath79-usb.c new file mode 100644 index 000000000000..6fd6e07ab345 --- /dev/null +++ b/drivers/phy/qualcomm/phy-ath79-usb.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Atheros AR71XX/9XXX USB PHY driver + * + * Copyright (C) 2015-2018 Alban Bedel <albeu@free.fr> + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/phy/phy.h> +#include <linux/reset.h> + +struct ath79_usb_phy { + struct reset_control *reset; + /* The suspend override logic is inverted, hence the no prefix + * to make the code a bit easier to understand. + */ + struct reset_control *no_suspend_override; +}; + +static int ath79_usb_phy_power_on(struct phy *phy) +{ + struct ath79_usb_phy *priv = phy_get_drvdata(phy); + int err = 0; + + if (priv->no_suspend_override) { + err = reset_control_assert(priv->no_suspend_override); + if (err) + return err; + } + + err = reset_control_deassert(priv->reset); + if (err && priv->no_suspend_override) + reset_control_assert(priv->no_suspend_override); + + return err; +} + +static int ath79_usb_phy_power_off(struct phy *phy) +{ + struct ath79_usb_phy *priv = phy_get_drvdata(phy); + int err = 0; + + err = reset_control_assert(priv->reset); + if (err) + return err; + + if (priv->no_suspend_override) { + err = reset_control_deassert(priv->no_suspend_override); + if (err) + reset_control_deassert(priv->reset); + } + + return err; +} + +static const struct phy_ops ath79_usb_phy_ops = { + .power_on = ath79_usb_phy_power_on, + .power_off = ath79_usb_phy_power_off, + .owner = THIS_MODULE, +}; + +static int ath79_usb_phy_probe(struct platform_device *pdev) +{ + struct ath79_usb_phy *priv; + struct phy *phy; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->reset = devm_reset_control_get(&pdev->dev, "usb-phy"); + if (IS_ERR(priv->reset)) + return PTR_ERR(priv->reset); + + priv->no_suspend_override = devm_reset_control_get_optional( + &pdev->dev, "usb-suspend-override"); + if (IS_ERR(priv->no_suspend_override)) + return PTR_ERR(priv->no_suspend_override); + + phy = devm_phy_create(&pdev->dev, NULL, &ath79_usb_phy_ops); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + phy_set_drvdata(phy, priv); + + return PTR_ERR_OR_ZERO(devm_of_phy_provider_register( + &pdev->dev, of_phy_simple_xlate)); +} + +static const struct of_device_id ath79_usb_phy_of_match[] = { + { .compatible = "qca,ar7100-usb-phy" }, + {} +}; +MODULE_DEVICE_TABLE(of, ath79_usb_phy_of_match); + +static struct platform_driver ath79_usb_phy_driver = { + .probe = ath79_usb_phy_probe, + .driver = { + .of_match_table = ath79_usb_phy_of_match, + .name = "ath79-usb-phy", + } +}; +module_platform_driver(ath79_usb_phy_driver); + +MODULE_DESCRIPTION("ATH79 USB PHY driver"); +MODULE_AUTHOR("Alban Bedel <albeu@free.fr>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 6470c5d61d1c..4c470104a0d6 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -490,6 +490,118 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), }; +static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_BUF_ENABLE, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07), +}; + +static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0xc6), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x06), +}; + +static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x50), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), +}; + +static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_pcs_tbl[] = { + /* FLL settings */ + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02), + + /* Lock Det settings */ + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b), + + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0xba), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V1, 0x9f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V2, 0xb5), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V3, 0x4c), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V4, 0x64), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_LS, 0x6a), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V1, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V2, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V3, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3, 0x1d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V4, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_LS, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS, 0x0d), + + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RATE_SLEW_CNTRL, 0x02), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), + + QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG1, 0x21), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60), +}; + + /* struct qmp_phy_cfg - per-PHY initialization config */ struct qmp_phy_cfg { /* phy-type - PCIE/UFS/USB */ @@ -766,6 +878,7 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { .pwrdn_ctrl = SW_PWRDN, .mask_pcs_ready = PHYSTATUS, + .has_pwrdn_delay = true, .pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN, .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, @@ -774,6 +887,35 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { .rx_b_lane_offset = 0x400, }; +static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = { + .type = PHY_TYPE_USB3, + .nlanes = 1, + + .serdes_tbl = qmp_v3_usb3_uniphy_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_uniphy_serdes_tbl), + .tx_tbl = qmp_v3_usb3_uniphy_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_uniphy_tx_tbl), + .rx_tbl = qmp_v3_usb3_uniphy_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(qmp_v3_usb3_uniphy_rx_tbl), + .pcs_tbl = qmp_v3_usb3_uniphy_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(qmp_v3_usb3_uniphy_pcs_tbl), + .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 = msm8996_phy_vreg_l, + .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l), + .regs = qmp_v3_usb3phy_regs_layout, + + .start_ctrl = SERDES_START | PCS_START, + .pwrdn_ctrl = SW_PWRDN, + .mask_pcs_ready = PHYSTATUS, + + .has_pwrdn_delay = true, + .pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN, + .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, +}; + static void qcom_qmp_phy_configure(void __iomem *base, const unsigned int *regs, const struct qmp_phy_init_tbl tbl[], @@ -793,19 +935,6 @@ static void qcom_qmp_phy_configure(void __iomem *base, } } -static int qcom_qmp_phy_poweron(struct phy *phy) -{ - struct qmp_phy *qphy = phy_get_drvdata(phy); - struct qcom_qmp *qmp = qphy->qmp; - int ret; - - ret = clk_prepare_enable(qphy->pipe_clk); - if (ret) - dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret); - - return ret; -} - static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp) { const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -974,6 +1103,12 @@ static int qcom_qmp_phy_init(struct phy *phy) } } + ret = clk_prepare_enable(qphy->pipe_clk); + if (ret) { + dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret); + goto err_clk_enable; + } + /* Tx, Rx, and PCS configurations */ qcom_qmp_phy_configure(tx, cfg->regs, cfg->tx_tbl, cfg->tx_tbl_num); /* Configuration for other LANE for USB-DP combo PHY */ @@ -1019,6 +1154,8 @@ static int qcom_qmp_phy_init(struct phy *phy) return ret; err_pcs_ready: + clk_disable_unprepare(qphy->pipe_clk); +err_clk_enable: if (cfg->has_lane_rst) reset_control_assert(qphy->lane_rst); err_lane_rst: @@ -1283,7 +1420,6 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np) static const struct phy_ops qcom_qmp_phy_gen_ops = { .init = qcom_qmp_phy_init, .exit = qcom_qmp_phy_exit, - .power_on = qcom_qmp_phy_poweron, .set_mode = qcom_qmp_phy_set_mode, .owner = THIS_MODULE, }; @@ -1381,8 +1517,11 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { .compatible = "qcom,ipq8074-qmp-pcie-phy", .data = &ipq8074_pciephy_cfg, }, { - .compatible = "qcom,qmp-v3-usb3-phy", + .compatible = "qcom,sdm845-qmp-usb3-phy", .data = &qmp_v3_usb3phy_cfg, + }, { + .compatible = "qcom,sdm845-qmp-usb3-uni-phy", + .data = &qmp_v3_usb3_uniphy_cfg, }, { }, }; diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index d1c6905d0439..5d78d43ba9fc 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -214,6 +214,8 @@ #define QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN 0x030 #define QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034 #define QSERDES_V3_RX_RX_TERM_BW 0x07c +#define QSERDES_V3_RX_VGA_CAL_CNTRL1 0x0bc +#define QSERDES_V3_RX_VGA_CAL_CNTRL2 0x0c0 #define QSERDES_V3_RX_RX_EQ_GAIN2_LSB 0x0c8 #define QSERDES_V3_RX_RX_EQ_GAIN2_MSB 0x0cc #define QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2 0x0d4 @@ -227,6 +229,7 @@ #define QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL 0x10c #define QSERDES_V3_RX_RX_BAND 0x110 #define QSERDES_V3_RX_RX_INTERFACE_MODE 0x11c +#define QSERDES_V3_RX_RX_MODE_00 0x164 /* Only for QMP V3 PHY - PCS registers */ #define QPHY_V3_PCS_POWER_DOWN_CONTROL 0x004 @@ -273,6 +276,8 @@ #define QPHY_V3_PCS_FLL_CNT_VAL_H_TOL 0x0d0 #define QPHY_V3_PCS_FLL_MAN_CODE 0x0d4 #define QPHY_V3_PCS_RX_SIGDET_LVL 0x1d8 +#define QPHY_V3_PCS_REFGEN_REQ_CONFIG1 0x20c +#define QPHY_V3_PCS_REFGEN_REQ_CONFIG2 0x210 /* Only for QMP V3 PHY - PCS_MISC registers */ #define QPHY_V3_PCS_MISC_CLAMP_ENABLE 0x0c diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c index 94afeac1a19e..e70e425f26f5 100644 --- a/drivers/phy/qualcomm/phy-qcom-qusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c @@ -20,6 +20,8 @@ #include <linux/reset.h> #include <linux/slab.h> +#include <dt-bindings/phy/phy-qcom-qusb2.h> + #define QUSB2PHY_PLL_TEST 0x04 #define CLK_REF_SEL BIT(7) @@ -60,6 +62,17 @@ #define CORE_RESET BIT(5) #define CORE_RESET_MUX BIT(6) +/* QUSB2PHY_IMP_CTRL1 register bits */ +#define IMP_RES_OFFSET_MASK GENMASK(5, 0) +#define IMP_RES_OFFSET_SHIFT 0x0 + +/* QUSB2PHY_PORT_TUNE1 register bits */ +#define HSTX_TRIM_MASK GENMASK(7, 4) +#define HSTX_TRIM_SHIFT 0x4 +#define PREEMPH_WIDTH_HALF_BIT BIT(2) +#define PREEMPHASIS_EN_MASK GENMASK(1, 0) +#define PREEMPHASIS_EN_SHIFT 0x0 + #define QUSB2PHY_PLL_ANALOG_CONTROLS_TWO 0x04 #define QUSB2PHY_PLL_CLOCK_INVERTERS 0x18c #define QUSB2PHY_PLL_CMODE 0x2c @@ -139,7 +152,7 @@ static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = { QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00), }; -static const unsigned int qusb2_v2_regs_layout[] = { +static const unsigned int sdm845_regs_layout[] = { [QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8, [QUSB2PHY_PLL_STATUS] = 0x1a0, [QUSB2PHY_PORT_TUNE1] = 0x240, @@ -153,7 +166,7 @@ static const unsigned int qusb2_v2_regs_layout[] = { [QUSB2PHY_INTR_CTRL] = 0x230, }; -static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = { +static const struct qusb2_phy_init_tbl sdm845_init_tbl[] = { QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x03), QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c), QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80), @@ -208,10 +221,10 @@ static const struct qusb2_phy_cfg msm8996_phy_cfg = { .autoresume_en = BIT(3), }; -static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = { - .tbl = qusb2_v2_init_tbl, - .tbl_num = ARRAY_SIZE(qusb2_v2_init_tbl), - .regs = qusb2_v2_regs_layout, +static const struct qusb2_phy_cfg sdm845_phy_cfg = { + .tbl = sdm845_init_tbl, + .tbl_num = ARRAY_SIZE(sdm845_init_tbl), + .regs = sdm845_regs_layout, .disable_ctrl = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN | POWER_DOWN), @@ -241,6 +254,15 @@ static const char * const qusb2_phy_vreg_names[] = { * @tcsr: TCSR syscon register map * @cell: nvmem cell containing phy tuning value * + * @override_imp_res_offset: PHY should use different rescode offset + * @imp_res_offset_value: rescode offset to be updated in IMP_CTRL1 register + * @override_hstx_trim: PHY should use different HSTX o/p current value + * @hstx_trim_value: HSTX_TRIM value to be updated in TUNE1 register + * @override_preemphasis: PHY should use different pre-amphasis amplitude + * @preemphasis_level: Amplitude Pre-Emphasis to be updated in TUNE1 register + * @override_preemphasis_width: PHY should use different pre-emphasis duration + * @preemphasis_width: half/full-width Pre-Emphasis updated via TUNE1 + * * @cfg: phy config data * @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme * @phy_initialized: indicate if PHY has been initialized @@ -259,12 +281,35 @@ struct qusb2_phy { struct regmap *tcsr; struct nvmem_cell *cell; + bool override_imp_res_offset; + u8 imp_res_offset_value; + bool override_hstx_trim; + u8 hstx_trim_value; + bool override_preemphasis; + u8 preemphasis_level; + bool override_preemphasis_width; + u8 preemphasis_width; + const struct qusb2_phy_cfg *cfg; bool has_se_clk_scheme; bool phy_initialized; enum phy_mode mode; }; +static inline void qusb2_write_mask(void __iomem *base, u32 offset, + u32 val, u32 mask) +{ + u32 reg; + + reg = readl(base + offset); + reg &= ~mask; + reg |= val & mask; + writel(reg, base + offset); + + /* Ensure above write is completed */ + readl(base + offset); +} + static inline void qusb2_setbits(void __iomem *base, u32 offset, u32 val) { u32 reg; @@ -305,6 +350,42 @@ void qcom_qusb2_phy_configure(void __iomem *base, } /* + * Update board specific PHY tuning override values if specified from + * device tree. + */ +static void qusb2_phy_override_phy_params(struct qusb2_phy *qphy) +{ + const struct qusb2_phy_cfg *cfg = qphy->cfg; + + if (qphy->override_imp_res_offset) + qusb2_write_mask(qphy->base, QUSB2PHY_IMP_CTRL1, + qphy->imp_res_offset_value << IMP_RES_OFFSET_SHIFT, + IMP_RES_OFFSET_MASK); + + if (qphy->override_hstx_trim) + qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1], + qphy->hstx_trim_value << HSTX_TRIM_SHIFT, + HSTX_TRIM_MASK); + + if (qphy->override_preemphasis) + qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1], + qphy->preemphasis_level << PREEMPHASIS_EN_SHIFT, + PREEMPHASIS_EN_MASK); + + if (qphy->override_preemphasis_width) { + if (qphy->preemphasis_width == + QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT) + qusb2_setbits(qphy->base, + cfg->regs[QUSB2PHY_PORT_TUNE1], + PREEMPH_WIDTH_HALF_BIT); + else + qusb2_clrbits(qphy->base, + cfg->regs[QUSB2PHY_PORT_TUNE1], + PREEMPH_WIDTH_HALF_BIT); + } +} + +/* * Fetches HS Tx tuning value from nvmem and sets the * QUSB2PHY_PORT_TUNE1/2 register. * For error case, skip setting the value and use the default value. @@ -315,6 +396,10 @@ static void qusb2_phy_set_tune2_param(struct qusb2_phy *qphy) const struct qusb2_phy_cfg *cfg = qphy->cfg; u8 *val; + /* efuse register is optional */ + if (!qphy->cell) + return; + /* * Read efuse register having TUNE2/1 parameter's high nibble. * If efuse register shows value as 0x0, or if we fail to find @@ -521,6 +606,9 @@ static int qusb2_phy_init(struct phy *phy) qcom_qusb2_phy_configure(qphy->base, cfg->regs, cfg->tbl, cfg->tbl_num); + /* Override board specific PHY tuning values */ + qusb2_phy_override_phy_params(qphy); + /* Set efuse value for tuning the PHY */ qusb2_phy_set_tune2_param(qphy); @@ -643,8 +731,8 @@ static const struct of_device_id qusb2_phy_of_match_table[] = { .compatible = "qcom,msm8996-qusb2-phy", .data = &msm8996_phy_cfg, }, { - .compatible = "qcom,qusb2-v2-phy", - .data = &qusb2_v2_phy_cfg, + .compatible = "qcom,sdm845-qusb2-phy", + .data = &sdm845_phy_cfg, }, { }, }; @@ -664,6 +752,7 @@ static int qusb2_phy_probe(struct platform_device *pdev) struct resource *res; int ret, i; int num; + u32 value; qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL); if (!qphy) @@ -732,6 +821,31 @@ static int qusb2_phy_probe(struct platform_device *pdev) qphy->cell = NULL; dev_dbg(dev, "failed to lookup tune2 hstx trim value\n"); } + + if (!of_property_read_u32(dev->of_node, "qcom,imp-res-offset-value", + &value)) { + qphy->imp_res_offset_value = (u8)value; + qphy->override_imp_res_offset = true; + } + + if (!of_property_read_u32(dev->of_node, "qcom,hstx-trim-value", + &value)) { + qphy->hstx_trim_value = (u8)value; + qphy->override_hstx_trim = true; + } + + if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-level", + &value)) { + qphy->preemphasis_level = (u8)value; + qphy->override_preemphasis = true; + } + + if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-width", + &value)) { + qphy->preemphasis_width = (u8)value; + qphy->override_preemphasis_width = true; + } + pm_runtime_set_active(dev); pm_runtime_enable(dev); /* |