diff options
Diffstat (limited to 'drivers/phy/qualcomm')
-rw-r--r-- | drivers/phy/qualcomm/Kconfig | 20 | ||||
-rw-r--r-- | drivers/phy/qualcomm/Makefile | 2 | ||||
-rw-r--r-- | drivers/phy/qualcomm/phy-qcom-qmp.c | 425 | ||||
-rw-r--r-- | drivers/phy/qualcomm/phy-qcom-qmp.h | 114 | ||||
-rw-r--r-- | drivers/phy/qualcomm/phy-qcom-qusb2.c | 144 | ||||
-rw-r--r-- | drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c | 415 | ||||
-rw-r--r-- | drivers/phy/qualcomm/phy-qcom-usb-ss.c | 246 |
7 files changed, 1322 insertions, 44 deletions
diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig index e46824da29f6..98674ed094d9 100644 --- a/drivers/phy/qualcomm/Kconfig +++ b/drivers/phy/qualcomm/Kconfig @@ -91,3 +91,23 @@ config PHY_QCOM_USB_HSIC select GENERIC_PHY help Support for the USB HSIC ULPI compliant PHY on QCOM chipsets. + +config PHY_QCOM_USB_HS_28NM + tristate "Qualcomm 28nm High-Speed PHY" + depends on ARCH_QCOM || COMPILE_TEST + depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in + select GENERIC_PHY + help + Enable this to support the Qualcomm Synopsys DesignWare Core 28nm + High-Speed PHY driver. This driver supports the Hi-Speed PHY which + is usually paired with either the ChipIdea or Synopsys DWC3 USB + IPs on MSM SOCs. + +config PHY_QCOM_USB_SS + tristate "Qualcomm USB Super-Speed PHY driver" + depends on ARCH_QCOM || COMPILE_TEST + depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in + select GENERIC_PHY + help + Enable this to support the Super-Speed USB transceiver on various + Qualcomm chipsets. diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile index 283251d6a5d9..1f14aeacbd70 100644 --- a/drivers/phy/qualcomm/Makefile +++ b/drivers/phy/qualcomm/Makefile @@ -10,3 +10,5 @@ obj-$(CONFIG_PHY_QCOM_UFS_14NM) += phy-qcom-ufs-qmp-14nm.o obj-$(CONFIG_PHY_QCOM_UFS_20NM) += phy-qcom-ufs-qmp-20nm.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 +obj-$(CONFIG_PHY_QCOM_USB_SS) += phy-qcom-usb-ss.o diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 7db2a94f7a99..c190406246ab 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -121,6 +121,11 @@ enum qphy_reg_layout { QPHY_PCS_LFPS_RXTERM_IRQ_STATUS, }; +static const unsigned int msm8996_ufsphy_regs_layout[] = { + [QPHY_START_CTRL] = 0x00, + [QPHY_PCS_READY_STATUS] = 0x168, +}; + static const unsigned int pciephy_regs_layout[] = { [QPHY_COM_SW_RESET] = 0x400, [QPHY_COM_POWER_DOWN_CONTROL] = 0x404, @@ -160,6 +165,18 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[] = { [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170, }; +static const unsigned int sdm845_qmp_pciephy_regs_layout[] = { + [QPHY_SW_RESET] = 0x00, + [QPHY_START_CTRL] = 0x08, + [QPHY_PCS_STATUS] = 0x174, +}; + +static const unsigned int sdm845_qhp_pciephy_regs_layout[] = { + [QPHY_SW_RESET] = 0x00, + [QPHY_START_CTRL] = 0x08, + [QPHY_PCS_STATUS] = 0x2ac, +}; + static const unsigned int sdm845_ufsphy_regs_layout[] = { [QPHY_START_CTRL] = 0x00, [QPHY_PCS_READY_STATUS] = 0x160, @@ -331,6 +348,75 @@ static const struct qmp_phy_init_tbl msm8998_pcie_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_SIGDET_CNTRL, 0x03), }; +static const struct qmp_phy_init_tbl msm8996_ufs_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_POWER_DOWN_CONTROL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0xd7), + QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06), + QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x01), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x10), + QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x54), + QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xff), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE1, 0x98), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE1, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE1, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE1, 0x32), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE1, 0x00), +}; + +static const struct qmp_phy_init_tbl msm8996_ufs_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), + QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x02), +}; + +static const struct qmp_phy_init_tbl msm8996_ufs_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_INTERFACE_MODE, 0x00), + QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x18), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_TERM_BW, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xff), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xff), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0E), +}; + static const struct qmp_phy_init_tbl msm8996_usb3_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), @@ -481,6 +567,229 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_pcs_tbl[] = { QMP_PHY_INIT_CFG_L(QPHY_START_CTRL, 0x3), }; +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), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x007), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00), + 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_VCO_TUNE_TIMER1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_TIMER2, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_EP_DIV, 0x19), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_ENABLE1, 0x90), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x00), + 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_CMN_MODE, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x33), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_BUF_ENABLE, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x04), + 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_BG_TIMER, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x7e), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x15), +}; + +static const struct qmp_phy_init_tbl sdm845_qmp_pcie_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x06), +}; + +static const struct qmp_phy_init_tbl sdm845_qmp_pcie_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN_HALF, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x71), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x59), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_01, 0x59), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x71), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x40), +}; + +static const struct qmp_phy_init_tbl sdm845_qmp_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V3_PCS_ENDPOINT_REFCLK_DRIVE, 0x04), + + 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), + + QMP_PHY_INIT_CFG(QPHY_V3_PCS_OSC_DTCT_ACTIONS, 0x00), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x01), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB, 0x00), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB, 0x20), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK_MSB, 0x00), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK, 0x01), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_PLL_LOCK_CHK_DLY_TIME, 0x73), + + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0xbb), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_SIGDET_CNTRL, 0x03), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG1, 0x0d), + + QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG4, 0x00), +}; + +static const struct qmp_phy_init_tbl sdm845_qmp_pcie_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_OSC_DTCT_CONFIG2, 0x52), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG2, 0x10), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG4, 0x1a), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG5, 0x06), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_PCIE_INT_AUX_CLK_CONFIG1, 0x00), +}; + +static const struct qmp_phy_init_tbl sdm845_qhp_pcie_serdes_tbl[] = { + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SYSCLK_EN_SEL, 0x27), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_STEP_SIZE1, 0xde), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_STEP_SIZE2, 0x07), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_STEP_SIZE1_MODE1, 0x4c), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_STEP_SIZE2_MODE1, 0x06), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_BIAS_EN_CKBUFLR_EN, 0x18), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CLK_ENABLE1, 0xb0), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP1_MODE0, 0x8c), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP2_MODE0, 0x20), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP1_MODE1, 0x14), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP2_MODE1, 0x34), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_RESTRIM_CTRL2, 0x05), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP_EN, 0x42), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DEC_START_MODE1, 0x68), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START1_MODE0, 0x55), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START2_MODE0, 0x55), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START3_MODE0, 0x03), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START1_MODE1, 0xab), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START2_MODE1, 0xaa), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START3_MODE1, 0x02), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_INTEGLOOP_GAIN0_MODE1, 0x3f), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_VCO_TUNE_MAP, 0x10), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CLK_SELECT, 0x04), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_HSCLK_SEL1, 0x30), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CORECLK_DIV, 0x04), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CORE_CLK_EN, 0x73), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CMN_CONFIG, 0x0c), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SVS_MODE_CLK_SEL, 0x15), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CORECLK_DIV_MODE1, 0x04), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CMN_MODE, 0x01), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_VREGCLK_DIV1, 0x22), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_VREGCLK_DIV2, 0x00), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_BGV_TRIM, 0x20), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_BG_CTRL, 0x07), +}; + +static const struct qmp_phy_init_tbl sdm845_qhp_pcie_tx_tbl[] = { + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DRVR_CTRL0, 0x00), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DRVR_TAP_EN, 0x0d), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_TX_BAND_MODE, 0x01), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_LANE_MODE, 0x1a), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PARALLEL_RATE, 0x2f), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CML_CTRL_MODE0, 0x09), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CML_CTRL_MODE1, 0x09), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CML_CTRL_MODE2, 0x1b), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PREAMP_CTRL_MODE1, 0x01), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PREAMP_CTRL_MODE2, 0x07), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE0, 0x31), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE1, 0x31), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE2, 0x03), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CTLE_THRESH_DFE, 0x02), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CGA_THRESH_DFE, 0x00), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RXENGINE_EN0, 0x12), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CTLE_TRAIN_TIME, 0x25), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CTLE_DFE_OVRLP_TIME, 0x00), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DFE_REFRESH_TIME, 0x05), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DFE_ENABLE_TIME, 0x01), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_VGA_GAIN, 0x26), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DFE_GAIN, 0x12), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_EQ_GAIN, 0x04), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_OFFSET_GAIN, 0x04), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PRE_GAIN, 0x09), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_EQ_INTVAL, 0x15), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_EDAC_INITVAL, 0x28), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RXEQ_INITB0, 0x7f), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RXEQ_INITB1, 0x07), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RCVRDONE_THRESH1, 0x04), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RXEQ_CTRL, 0x70), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE0, 0x8b), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE1, 0x08), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE2, 0x0a), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE0, 0x03), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE1, 0x04), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE2, 0x04), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_SO_CONFIG, 0x0c), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_BAND, 0x02), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE0, 0x5c), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE1, 0x3e), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE2, 0x3f), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_SIGDET_ENABLES, 0x01), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_SIGDET_CNTRL, 0xa0), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_SIGDET_DEGLITCH_CNTRL, 0x08), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DCC_GAIN, 0x01), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_EN_SIGNAL, 0xc3), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PSM_RX_EN_CAL, 0x00), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_MISC_CNTRL0, 0xbc), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_TS0_TIMER, 0x7f), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DLL_HIGHDATARATE, 0x15), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DRVR_CTRL1, 0x0c), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DRVR_CTRL2, 0x0f), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_RESETCODE_OFFSET, 0x04), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_VGA_INITVAL, 0x20), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RSM_START, 0x01), +}; + +static const struct qmp_phy_init_tbl sdm845_qhp_pcie_rx_tbl[] = { +}; + +static const struct qmp_phy_init_tbl sdm845_qhp_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG, 0x3f), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_PCS_TX_RX_CONFIG, 0x50), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_TXMGN_MAIN_V0_M3P5DB, 0x19), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_TXMGN_POST_V0_M3P5DB, 0x07), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_TXMGN_MAIN_V0_M6DB, 0x17), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_TXMGN_POST_V0_M6DB, 0x09), + QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG5, 0x9f), +}; + static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14), @@ -988,6 +1297,8 @@ struct qmp_phy_cfg { int rx_tbl_num; const struct qmp_phy_init_tbl *pcs_tbl; int pcs_tbl_num; + const struct qmp_phy_init_tbl *pcs_misc_tbl; + int pcs_misc_tbl_num; /* clock ids to be requested */ const char * const *clk_list; @@ -1122,10 +1433,18 @@ static const char * const msm8996_phy_clk_l[] = { "aux", "cfg_ahb", "ref", }; +static const char * const msm8996_ufs_phy_clk_l[] = { + "ref", +}; + static const char * const qmp_v3_phy_clk_l[] = { "aux", "cfg_ahb", "ref", "com_aux", }; +static const char * const sdm845_pciephy_clk_l[] = { + "aux", "cfg_ahb", "ref", "refgen", +}; + static const char * const sdm845_ufs_phy_clk_l[] = { "ref", "ref_aux", }; @@ -1139,6 +1458,10 @@ static const char * const msm8996_usb3phy_reset_l[] = { "phy", "common", }; +static const char * const sdm845_pciephy_reset_l[] = { + "phy", +}; + /* list of regulators */ static const char * const qmp_phy_vreg_l[] = { "vdda-phy", "vdda-pll", @@ -1175,6 +1498,31 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = { .pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX, }; +static const struct qmp_phy_cfg msm8996_ufs_cfg = { + .type = PHY_TYPE_UFS, + .nlanes = 1, + + .serdes_tbl = msm8996_ufs_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(msm8996_ufs_serdes_tbl), + .tx_tbl = msm8996_ufs_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(msm8996_ufs_tx_tbl), + .rx_tbl = msm8996_ufs_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(msm8996_ufs_rx_tbl), + + .clk_list = msm8996_ufs_phy_clk_l, + .num_clks = ARRAY_SIZE(msm8996_ufs_phy_clk_l), + + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + + .regs = msm8996_ufsphy_regs_layout, + + .start_ctrl = SERDES_START, + .pwrdn_ctrl = SW_PWRDN, + + .no_pcs_sw_reset = true, +}; + static const struct qmp_phy_cfg msm8996_usb3phy_cfg = { .type = PHY_TYPE_USB3, .nlanes = 1, @@ -1234,6 +1582,64 @@ static const struct qmp_phy_cfg ipq8074_pciephy_cfg = { .pwrdn_delay_max = 1005, /* us */ }; +static const struct qmp_phy_cfg sdm845_qmp_pciephy_cfg = { + .type = PHY_TYPE_PCIE, + .nlanes = 1, + + .serdes_tbl = sdm845_qmp_pcie_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sdm845_qmp_pcie_serdes_tbl), + .tx_tbl = sdm845_qmp_pcie_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(sdm845_qmp_pcie_tx_tbl), + .rx_tbl = sdm845_qmp_pcie_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sdm845_qmp_pcie_rx_tbl), + .pcs_tbl = sdm845_qmp_pcie_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(sdm845_qmp_pcie_pcs_tbl), + .pcs_misc_tbl = sdm845_qmp_pcie_pcs_misc_tbl, + .pcs_misc_tbl_num = ARRAY_SIZE(sdm845_qmp_pcie_pcs_misc_tbl), + .clk_list = sdm845_pciephy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_pciephy_clk_l), + .reset_list = sdm845_pciephy_reset_l, + .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = sdm845_qmp_pciephy_regs_layout, + + .start_ctrl = PCS_START | SERDES_START, + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + + .has_pwrdn_delay = true, + .pwrdn_delay_min = 995, /* us */ + .pwrdn_delay_max = 1005, /* us */ +}; + +static const struct qmp_phy_cfg sdm845_qhp_pciephy_cfg = { + .type = PHY_TYPE_PCIE, + .nlanes = 1, + + .serdes_tbl = sdm845_qhp_pcie_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sdm845_qhp_pcie_serdes_tbl), + .tx_tbl = sdm845_qhp_pcie_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(sdm845_qhp_pcie_tx_tbl), + .rx_tbl = sdm845_qhp_pcie_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sdm845_qhp_pcie_rx_tbl), + .pcs_tbl = sdm845_qhp_pcie_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(sdm845_qhp_pcie_pcs_tbl), + .clk_list = sdm845_pciephy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_pciephy_clk_l), + .reset_list = sdm845_pciephy_reset_l, + .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = sdm845_qhp_pciephy_regs_layout, + + .start_ctrl = PCS_START | SERDES_START, + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + + .has_pwrdn_delay = true, + .pwrdn_delay_min = 995, /* us */ + .pwrdn_delay_max = 1005, /* us */ +}; + static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { .type = PHY_TYPE_USB3, .nlanes = 1, @@ -1563,6 +1969,7 @@ static int qcom_qmp_phy_enable(struct phy *phy) void __iomem *tx = qphy->tx; void __iomem *rx = qphy->rx; void __iomem *pcs = qphy->pcs; + void __iomem *pcs_misc = qphy->pcs_misc; void __iomem *dp_com = qmp->dp_com; void __iomem *status; unsigned int mask, val, ready; @@ -1633,6 +2040,9 @@ static int qcom_qmp_phy_enable(struct phy *phy) if (ret) goto err_lane_rst; + qcom_qmp_phy_configure(pcs_misc, cfg->regs, cfg->pcs_misc_tbl, + cfg->pcs_misc_tbl_num); + /* * Pull out PHY from POWER DOWN state. * This is active low enable signal to power-down PHY. @@ -1967,7 +2377,7 @@ static const struct phy_ops qcom_qmp_phy_gen_ops = { .owner = THIS_MODULE, }; -static const struct phy_ops qcom_qmp_ufs_ops = { +static const struct phy_ops qcom_qmp_pcie_ufs_ops = { .power_on = qcom_qmp_phy_enable, .power_off = qcom_qmp_phy_disable, .set_mode = qcom_qmp_phy_set_mode, @@ -2067,8 +2477,8 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id) } } - if (qmp->cfg->type == PHY_TYPE_UFS) - ops = &qcom_qmp_ufs_ops; + if (qmp->cfg->type == PHY_TYPE_UFS || qmp->cfg->type == PHY_TYPE_PCIE) + ops = &qcom_qmp_pcie_ufs_ops; generic_phy = devm_phy_create(dev, np, ops); if (IS_ERR(generic_phy)) { @@ -2091,6 +2501,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { .compatible = "qcom,msm8996-qmp-pcie-phy", .data = &msm8996_pciephy_cfg, }, { + .compatible = "qcom,msm8996-qmp-ufs-phy", + .data = &msm8996_ufs_cfg, + }, { .compatible = "qcom,msm8996-qmp-usb3-phy", .data = &msm8996_usb3phy_cfg, }, { @@ -2103,6 +2516,12 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { .compatible = "qcom,ipq8074-qmp-pcie-phy", .data = &ipq8074_pciephy_cfg, }, { + .compatible = "qcom,sdm845-qhp-pcie-phy", + .data = &sdm845_qhp_pciephy_cfg, + }, { + .compatible = "qcom,sdm845-qmp-pcie-phy", + .data = &sdm845_qmp_pciephy_cfg, + }, { .compatible = "qcom,sdm845-qmp-usb3-phy", .data = &qmp_v3_usb3phy_cfg, }, { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index 90f793c2293d..dece0e67704b 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -409,4 +409,118 @@ #define QPHY_V4_TX_MID_TERM_CTRL1 0x1d8 #define QPHY_V4_MULTI_LANE_CTRL1 0x1e0 +/* PCIE GEN3 COM registers */ +#define PCIE_GEN3_QHP_COM_SSC_EN_CENTER 0x14 +#define PCIE_GEN3_QHP_COM_SSC_PER1 0x20 +#define PCIE_GEN3_QHP_COM_SSC_PER2 0x24 +#define PCIE_GEN3_QHP_COM_SSC_STEP_SIZE1 0x28 +#define PCIE_GEN3_QHP_COM_SSC_STEP_SIZE2 0x2c +#define PCIE_GEN3_QHP_COM_SSC_STEP_SIZE1_MODE1 0x34 +#define PCIE_GEN3_QHP_COM_SSC_STEP_SIZE2_MODE1 0x38 +#define PCIE_GEN3_QHP_COM_BIAS_EN_CKBUFLR_EN 0x54 +#define PCIE_GEN3_QHP_COM_CLK_ENABLE1 0x58 +#define PCIE_GEN3_QHP_COM_LOCK_CMP1_MODE0 0x6c +#define PCIE_GEN3_QHP_COM_LOCK_CMP2_MODE0 0x70 +#define PCIE_GEN3_QHP_COM_LOCK_CMP1_MODE1 0x78 +#define PCIE_GEN3_QHP_COM_LOCK_CMP2_MODE1 0x7c +#define PCIE_GEN3_QHP_COM_BGV_TRIM 0x98 +#define PCIE_GEN3_QHP_COM_CP_CTRL_MODE0 0xb4 +#define PCIE_GEN3_QHP_COM_CP_CTRL_MODE1 0xb8 +#define PCIE_GEN3_QHP_COM_PLL_RCTRL_MODE0 0xc0 +#define PCIE_GEN3_QHP_COM_PLL_RCTRL_MODE1 0xc4 +#define PCIE_GEN3_QHP_COM_PLL_CCTRL_MODE0 0xcc +#define PCIE_GEN3_QHP_COM_PLL_CCTRL_MODE1 0xd0 +#define PCIE_GEN3_QHP_COM_SYSCLK_EN_SEL 0xdc +#define PCIE_GEN3_QHP_COM_RESTRIM_CTRL2 0xf0 +#define PCIE_GEN3_QHP_COM_LOCK_CMP_EN 0xf8 +#define PCIE_GEN3_QHP_COM_DEC_START_MODE0 0x100 +#define PCIE_GEN3_QHP_COM_DEC_START_MODE1 0x108 +#define PCIE_GEN3_QHP_COM_DIV_FRAC_START1_MODE0 0x11c +#define PCIE_GEN3_QHP_COM_DIV_FRAC_START2_MODE0 0x120 +#define PCIE_GEN3_QHP_COM_DIV_FRAC_START3_MODE0 0x124 +#define PCIE_GEN3_QHP_COM_DIV_FRAC_START1_MODE1 0x128 +#define PCIE_GEN3_QHP_COM_DIV_FRAC_START2_MODE1 0x12c +#define PCIE_GEN3_QHP_COM_DIV_FRAC_START3_MODE1 0x130 +#define PCIE_GEN3_QHP_COM_INTEGLOOP_GAIN0_MODE0 0x150 +#define PCIE_GEN3_QHP_COM_INTEGLOOP_GAIN0_MODE1 0x158 +#define PCIE_GEN3_QHP_COM_VCO_TUNE_MAP 0x178 +#define PCIE_GEN3_QHP_COM_BG_CTRL 0x1c8 +#define PCIE_GEN3_QHP_COM_CLK_SELECT 0x1cc +#define PCIE_GEN3_QHP_COM_HSCLK_SEL1 0x1d0 +#define PCIE_GEN3_QHP_COM_CORECLK_DIV 0x1e0 +#define PCIE_GEN3_QHP_COM_CORE_CLK_EN 0x1e8 +#define PCIE_GEN3_QHP_COM_CMN_CONFIG 0x1f0 +#define PCIE_GEN3_QHP_COM_SVS_MODE_CLK_SEL 0x1fc +#define PCIE_GEN3_QHP_COM_CORECLK_DIV_MODE1 0x21c +#define PCIE_GEN3_QHP_COM_CMN_MODE 0x224 +#define PCIE_GEN3_QHP_COM_VREGCLK_DIV1 0x228 +#define PCIE_GEN3_QHP_COM_VREGCLK_DIV2 0x22c + +/* PCIE GEN3 QHP Lane registers */ +#define PCIE_GEN3_QHP_L0_DRVR_CTRL0 0xc +#define PCIE_GEN3_QHP_L0_DRVR_CTRL1 0x10 +#define PCIE_GEN3_QHP_L0_DRVR_CTRL2 0x14 +#define PCIE_GEN3_QHP_L0_DRVR_TAP_EN 0x18 +#define PCIE_GEN3_QHP_L0_TX_BAND_MODE 0x60 +#define PCIE_GEN3_QHP_L0_LANE_MODE 0x64 +#define PCIE_GEN3_QHP_L0_PARALLEL_RATE 0x7c +#define PCIE_GEN3_QHP_L0_CML_CTRL_MODE0 0xc0 +#define PCIE_GEN3_QHP_L0_CML_CTRL_MODE1 0xc4 +#define PCIE_GEN3_QHP_L0_CML_CTRL_MODE2 0xc8 +#define PCIE_GEN3_QHP_L0_PREAMP_CTRL_MODE1 0xd0 +#define PCIE_GEN3_QHP_L0_PREAMP_CTRL_MODE2 0xd4 +#define PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE0 0xd8 +#define PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE1 0xdc +#define PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE2 0xe0 +#define PCIE_GEN3_QHP_L0_CTLE_THRESH_DFE 0xfc +#define PCIE_GEN3_QHP_L0_CGA_THRESH_DFE 0x100 +#define PCIE_GEN3_QHP_L0_RXENGINE_EN0 0x108 +#define PCIE_GEN3_QHP_L0_CTLE_TRAIN_TIME 0x114 +#define PCIE_GEN3_QHP_L0_CTLE_DFE_OVRLP_TIME 0x118 +#define PCIE_GEN3_QHP_L0_DFE_REFRESH_TIME 0x11c +#define PCIE_GEN3_QHP_L0_DFE_ENABLE_TIME 0x120 +#define PCIE_GEN3_QHP_L0_VGA_GAIN 0x124 +#define PCIE_GEN3_QHP_L0_DFE_GAIN 0x128 +#define PCIE_GEN3_QHP_L0_EQ_GAIN 0x130 +#define PCIE_GEN3_QHP_L0_OFFSET_GAIN 0x134 +#define PCIE_GEN3_QHP_L0_PRE_GAIN 0x138 +#define PCIE_GEN3_QHP_L0_VGA_INITVAL 0x13c +#define PCIE_GEN3_QHP_L0_EQ_INTVAL 0x154 +#define PCIE_GEN3_QHP_L0_EDAC_INITVAL 0x160 +#define PCIE_GEN3_QHP_L0_RXEQ_INITB0 0x168 +#define PCIE_GEN3_QHP_L0_RXEQ_INITB1 0x16c +#define PCIE_GEN3_QHP_L0_RCVRDONE_THRESH1 0x178 +#define PCIE_GEN3_QHP_L0_RXEQ_CTRL 0x180 +#define PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE0 0x184 +#define PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE1 0x188 +#define PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE2 0x18c +#define PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE0 0x190 +#define PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE1 0x194 +#define PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE2 0x198 +#define PCIE_GEN3_QHP_L0_UCDR_SO_CONFIG 0x19c +#define PCIE_GEN3_QHP_L0_RX_BAND 0x1a4 +#define PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE0 0x1c0 +#define PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE1 0x1c4 +#define PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE2 0x1c8 +#define PCIE_GEN3_QHP_L0_SIGDET_ENABLES 0x230 +#define PCIE_GEN3_QHP_L0_SIGDET_CNTRL 0x234 +#define PCIE_GEN3_QHP_L0_SIGDET_DEGLITCH_CNTRL 0x238 +#define PCIE_GEN3_QHP_L0_DCC_GAIN 0x2a4 +#define PCIE_GEN3_QHP_L0_RSM_START 0x2a8 +#define PCIE_GEN3_QHP_L0_RX_EN_SIGNAL 0x2ac +#define PCIE_GEN3_QHP_L0_PSM_RX_EN_CAL 0x2b0 +#define PCIE_GEN3_QHP_L0_RX_MISC_CNTRL0 0x2b8 +#define PCIE_GEN3_QHP_L0_TS0_TIMER 0x2c0 +#define PCIE_GEN3_QHP_L0_DLL_HIGHDATARATE 0x2c4 +#define PCIE_GEN3_QHP_L0_RX_RESETCODE_OFFSET 0x2cc + +/* PCIE GEN3 PCS registers */ +#define PCIE_GEN3_QHP_PHY_TXMGN_MAIN_V0_M3P5DB 0x2c +#define PCIE_GEN3_QHP_PHY_TXMGN_POST_V0_M3P5DB 0x40 +#define PCIE_GEN3_QHP_PHY_TXMGN_MAIN_V0_M6DB 0x54 +#define PCIE_GEN3_QHP_PHY_TXMGN_POST_V0_M6DB 0x68 +#define PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG 0x15c +#define PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG5 0x16c +#define PCIE_GEN3_QHP_PHY_PCS_TX_RX_CONFIG 0x174 + #endif diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c index bf94a52d3087..3708d43b7508 100644 --- a/drivers/phy/qualcomm/phy-qcom-qusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017, 2019, The Linux Foundation. All rights reserved. */ #include <linux/clk.h> @@ -66,6 +66,14 @@ #define IMP_RES_OFFSET_MASK GENMASK(5, 0) #define IMP_RES_OFFSET_SHIFT 0x0 +/* QUSB2PHY_PLL_BIAS_CONTROL_2 register bits */ +#define BIAS_CTRL2_RES_OFFSET_MASK GENMASK(5, 0) +#define BIAS_CTRL2_RES_OFFSET_SHIFT 0x0 + +/* QUSB2PHY_CHG_CONTROL_2 register bits */ +#define CHG_CTRL2_OFFSET_MASK GENMASK(5, 4) +#define CHG_CTRL2_OFFSET_SHIFT 0x4 + /* QUSB2PHY_PORT_TUNE1 register bits */ #define HSTX_TRIM_MASK GENMASK(7, 4) #define HSTX_TRIM_SHIFT 0x4 @@ -73,6 +81,10 @@ #define PREEMPHASIS_EN_MASK GENMASK(1, 0) #define PREEMPHASIS_EN_SHIFT 0x0 +/* QUSB2PHY_PORT_TUNE2 register bits */ +#define HSDISC_TRIM_MASK GENMASK(1, 0) +#define HSDISC_TRIM_SHIFT 0x0 + #define QUSB2PHY_PLL_ANALOG_CONTROLS_TWO 0x04 #define QUSB2PHY_PLL_CLOCK_INVERTERS 0x18c #define QUSB2PHY_PLL_CMODE 0x2c @@ -177,7 +189,7 @@ static const struct qusb2_phy_init_tbl msm8998_init_tbl[] = { QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19), }; -static const unsigned int sdm845_regs_layout[] = { +static const unsigned int qusb2_v2_regs_layout[] = { [QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8, [QUSB2PHY_PLL_STATUS] = 0x1a0, [QUSB2PHY_PORT_TUNE1] = 0x240, @@ -191,7 +203,7 @@ static const unsigned int sdm845_regs_layout[] = { [QUSB2PHY_INTR_CTRL] = 0x230, }; -static const struct qusb2_phy_init_tbl sdm845_init_tbl[] = { +static const struct qusb2_phy_init_tbl qusb2_v2_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), @@ -258,10 +270,10 @@ static const struct qusb2_phy_cfg msm8998_phy_cfg = { .update_tune1_with_efuse = true, }; -static const struct qusb2_phy_cfg sdm845_phy_cfg = { - .tbl = sdm845_init_tbl, - .tbl_num = ARRAY_SIZE(sdm845_init_tbl), - .regs = sdm845_regs_layout, +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, .disable_ctrl = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN | POWER_DOWN), @@ -277,6 +289,34 @@ static const char * const qusb2_phy_vreg_names[] = { #define QUSB2_NUM_VREGS ARRAY_SIZE(qusb2_phy_vreg_names) +/* struct override_param - structure holding qusb2 v2 phy overriding param + * set override true if the device tree property exists and read and assign + * to value + */ +struct override_param { + bool override; + u8 value; +}; + +/*struct override_params - structure holding qusb2 v2 phy overriding params + * @imp_res_offset: rescode offset to be updated in IMP_CTRL1 register + * @hstx_trim: HSTX_TRIM to be updated in TUNE1 register + * @preemphasis: Amplitude Pre-Emphasis to be updated in TUNE1 register + * @preemphasis_width: half/full-width Pre-Emphasis updated via TUNE1 + * @bias_ctrl: bias ctrl to be updated in BIAS_CONTROL_2 register + * @charge_ctrl: charge ctrl to be updated in CHG_CTRL2 register + * @hsdisc_trim: disconnect threshold to be updated in TUNE2 register + */ +struct override_params { + struct override_param imp_res_offset; + struct override_param hstx_trim; + struct override_param preemphasis; + struct override_param preemphasis_width; + struct override_param bias_ctrl; + struct override_param charge_ctrl; + struct override_param hsdisc_trim; +}; + /** * struct qusb2_phy - structure holding qusb2 phy attributes * @@ -292,14 +332,7 @@ 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 + * @overrides: pointer to structure for all overriding tuning params * * @cfg: phy config data * @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme @@ -319,14 +352,7 @@ 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; + struct override_params overrides; const struct qusb2_phy_cfg *cfg; bool has_se_clk_scheme; @@ -394,24 +420,35 @@ void qcom_qusb2_phy_configure(void __iomem *base, static void qusb2_phy_override_phy_params(struct qusb2_phy *qphy) { const struct qusb2_phy_cfg *cfg = qphy->cfg; + struct override_params *or = &qphy->overrides; - if (qphy->override_imp_res_offset) + if (or->imp_res_offset.override) qusb2_write_mask(qphy->base, QUSB2PHY_IMP_CTRL1, - qphy->imp_res_offset_value << IMP_RES_OFFSET_SHIFT, + or->imp_res_offset.value << IMP_RES_OFFSET_SHIFT, IMP_RES_OFFSET_MASK); - if (qphy->override_hstx_trim) + if (or->bias_ctrl.override) + qusb2_write_mask(qphy->base, QUSB2PHY_PLL_BIAS_CONTROL_2, + or->bias_ctrl.value << BIAS_CTRL2_RES_OFFSET_SHIFT, + BIAS_CTRL2_RES_OFFSET_MASK); + + if (or->charge_ctrl.override) + qusb2_write_mask(qphy->base, QUSB2PHY_CHG_CTRL2, + or->charge_ctrl.value << CHG_CTRL2_OFFSET_SHIFT, + CHG_CTRL2_OFFSET_MASK); + + if (or->hstx_trim.override) qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1], - qphy->hstx_trim_value << HSTX_TRIM_SHIFT, + or->hstx_trim.value << HSTX_TRIM_SHIFT, HSTX_TRIM_MASK); - if (qphy->override_preemphasis) + if (or->preemphasis.override) qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1], - qphy->preemphasis_level << PREEMPHASIS_EN_SHIFT, + or->preemphasis.value << PREEMPHASIS_EN_SHIFT, PREEMPHASIS_EN_MASK); - if (qphy->override_preemphasis_width) { - if (qphy->preemphasis_width == + if (or->preemphasis_width.override) { + if (or->preemphasis_width.value == QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT) qusb2_setbits(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1], @@ -421,6 +458,11 @@ static void qusb2_phy_override_phy_params(struct qusb2_phy *qphy) cfg->regs[QUSB2PHY_PORT_TUNE1], PREEMPH_WIDTH_HALF_BIT); } + + if (or->hsdisc_trim.override) + qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE2], + or->hsdisc_trim.value << HSDISC_TRIM_SHIFT, + HSDISC_TRIM_MASK); } /* @@ -774,8 +816,8 @@ static const struct of_device_id qusb2_phy_of_match_table[] = { .compatible = "qcom,msm8998-qusb2-phy", .data = &msm8998_phy_cfg, }, { - .compatible = "qcom,sdm845-qusb2-phy", - .data = &sdm845_phy_cfg, + .compatible = "qcom,qusb2-v2-phy", + .data = &qusb2_v2_phy_cfg, }, { }, }; @@ -796,10 +838,12 @@ static int qusb2_phy_probe(struct platform_device *pdev) int ret, i; int num; u32 value; + struct override_params *or; qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL); if (!qphy) return -ENOMEM; + or = &qphy->overrides; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); qphy->base = devm_ioremap_resource(dev, res); @@ -864,26 +908,44 @@ static int qusb2_phy_probe(struct platform_device *pdev) 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; + or->imp_res_offset.value = (u8)value; + or->imp_res_offset.override = true; + } + + if (!of_property_read_u32(dev->of_node, "qcom,bias-ctrl-value", + &value)) { + or->bias_ctrl.value = (u8)value; + or->bias_ctrl.override = true; + } + + if (!of_property_read_u32(dev->of_node, "qcom,charge-ctrl-value", + &value)) { + or->charge_ctrl.value = (u8)value; + or->charge_ctrl.override = 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; + or->hstx_trim.value = (u8)value; + or->hstx_trim.override = true; } if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-level", &value)) { - qphy->preemphasis_level = (u8)value; - qphy->override_preemphasis = true; + or->preemphasis.value = (u8)value; + or->preemphasis.override = true; } if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-width", &value)) { - qphy->preemphasis_width = (u8)value; - qphy->override_preemphasis_width = true; + or->preemphasis_width.value = (u8)value; + or->preemphasis_width.override = true; + } + + if (!of_property_read_u32(dev->of_node, "qcom,hsdisc-trim-value", + &value)) { + or->hsdisc_trim.value = (u8)value; + or->hsdisc_trim.override = true; } pm_runtime_set_active(dev); diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c b/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c new file mode 100644 index 000000000000..d998e65c89c8 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2009-2018, Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, Linaro Limited + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_graph.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/reset.h> +#include <linux/slab.h> + +/* PHY register and bit definitions */ +#define PHY_CTRL_COMMON0 0x078 +#define SIDDQ BIT(2) +#define PHY_IRQ_CMD 0x0d0 +#define PHY_INTR_MASK0 0x0d4 +#define PHY_INTR_CLEAR0 0x0dc +#define DPDM_MASK 0x1e +#define DP_1_0 BIT(4) +#define DP_0_1 BIT(3) +#define DM_1_0 BIT(2) +#define DM_0_1 BIT(1) + +enum hsphy_voltage { + VOL_NONE, + VOL_MIN, + VOL_MAX, + VOL_NUM, +}; + +enum hsphy_vreg { + VDD, + VDDA_1P8, + VDDA_3P3, + VREG_NUM, +}; + +struct hsphy_init_seq { + int offset; + int val; + int delay; +}; + +struct hsphy_data { + const struct hsphy_init_seq *init_seq; + unsigned int init_seq_num; +}; + +struct hsphy_priv { + void __iomem *base; + struct clk_bulk_data *clks; + int num_clks; + struct reset_control *phy_reset; + struct reset_control *por_reset; + struct regulator_bulk_data vregs[VREG_NUM]; + const struct hsphy_data *data; + enum phy_mode mode; +}; + +static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode, + int submode) +{ + struct hsphy_priv *priv = phy_get_drvdata(phy); + + priv->mode = PHY_MODE_INVALID; + + if (mode > 0) + priv->mode = mode; + + return 0; +} + +static void qcom_snps_hsphy_enable_hv_interrupts(struct hsphy_priv *priv) +{ + u32 val; + + /* Clear any existing interrupts before enabling the interrupts */ + val = readb(priv->base + PHY_INTR_CLEAR0); + val |= DPDM_MASK; + writeb(val, priv->base + PHY_INTR_CLEAR0); + + writeb(0x0, priv->base + PHY_IRQ_CMD); + usleep_range(200, 220); + writeb(0x1, priv->base + PHY_IRQ_CMD); + + /* Make sure the interrupts are cleared */ + usleep_range(200, 220); + + val = readb(priv->base + PHY_INTR_MASK0); + switch (priv->mode) { + case PHY_MODE_USB_HOST_HS: + case PHY_MODE_USB_HOST_FS: + case PHY_MODE_USB_DEVICE_HS: + case PHY_MODE_USB_DEVICE_FS: + val |= DP_1_0 | DM_0_1; + break; + case PHY_MODE_USB_HOST_LS: + case PHY_MODE_USB_DEVICE_LS: + val |= DP_0_1 | DM_1_0; + break; + default: + /* No device connected */ + val |= DP_0_1 | DM_0_1; + break; + } + writeb(val, priv->base + PHY_INTR_MASK0); +} + +static void qcom_snps_hsphy_disable_hv_interrupts(struct hsphy_priv *priv) +{ + u32 val; + + val = readb(priv->base + PHY_INTR_MASK0); + val &= ~DPDM_MASK; + writeb(val, priv->base + PHY_INTR_MASK0); + + /* Clear any pending interrupts */ + val = readb(priv->base + PHY_INTR_CLEAR0); + val |= DPDM_MASK; + writeb(val, priv->base + PHY_INTR_CLEAR0); + + writeb(0x0, priv->base + PHY_IRQ_CMD); + usleep_range(200, 220); + + writeb(0x1, priv->base + PHY_IRQ_CMD); + usleep_range(200, 220); +} + +static void qcom_snps_hsphy_enter_retention(struct hsphy_priv *priv) +{ + u32 val; + + val = readb(priv->base + PHY_CTRL_COMMON0); + val |= SIDDQ; + writeb(val, priv->base + PHY_CTRL_COMMON0); +} + +static void qcom_snps_hsphy_exit_retention(struct hsphy_priv *priv) +{ + u32 val; + + val = readb(priv->base + PHY_CTRL_COMMON0); + val &= ~SIDDQ; + writeb(val, priv->base + PHY_CTRL_COMMON0); +} + +static int qcom_snps_hsphy_power_on(struct phy *phy) +{ + struct hsphy_priv *priv = phy_get_drvdata(phy); + int ret; + + ret = regulator_bulk_enable(VREG_NUM, priv->vregs); + if (ret) + return ret; + ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); + if (ret) + goto err_disable_regulator; + qcom_snps_hsphy_disable_hv_interrupts(priv); + qcom_snps_hsphy_exit_retention(priv); + + return 0; + +err_disable_regulator: + regulator_bulk_disable(VREG_NUM, priv->vregs); + + return ret; +} + +static int qcom_snps_hsphy_power_off(struct phy *phy) +{ + struct hsphy_priv *priv = phy_get_drvdata(phy); + + qcom_snps_hsphy_enter_retention(priv); + qcom_snps_hsphy_enable_hv_interrupts(priv); + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); + regulator_bulk_disable(VREG_NUM, priv->vregs); + + return 0; +} + +static int qcom_snps_hsphy_reset(struct hsphy_priv *priv) +{ + int ret; + + ret = reset_control_assert(priv->phy_reset); + if (ret) + return ret; + + usleep_range(10, 15); + + ret = reset_control_deassert(priv->phy_reset); + if (ret) + return ret; + + usleep_range(80, 100); + + return 0; +} + +static void qcom_snps_hsphy_init_sequence(struct hsphy_priv *priv) +{ + const struct hsphy_data *data = priv->data; + const struct hsphy_init_seq *seq; + int i; + + /* Device match data is optional. */ + if (!data) + return; + + seq = data->init_seq; + + for (i = 0; i < data->init_seq_num; i++, seq++) { + writeb(seq->val, priv->base + seq->offset); + if (seq->delay) + usleep_range(seq->delay, seq->delay + 10); + } +} + +static int qcom_snps_hsphy_por_reset(struct hsphy_priv *priv) +{ + int ret; + + ret = reset_control_assert(priv->por_reset); + if (ret) + return ret; + + /* + * The Femto PHY is POR reset in the following scenarios. + * + * 1. After overriding the parameter registers. + * 2. Low power mode exit from PHY retention. + * + * Ensure that SIDDQ is cleared before bringing the PHY + * out of reset. + */ + qcom_snps_hsphy_exit_retention(priv); + + /* + * As per databook, 10 usec delay is required between + * PHY POR assert and de-assert. + */ + usleep_range(10, 20); + ret = reset_control_deassert(priv->por_reset); + if (ret) + return ret; + + /* + * As per databook, it takes 75 usec for PHY to stabilize + * after the reset. + */ + usleep_range(80, 100); + + return 0; +} + +static int qcom_snps_hsphy_init(struct phy *phy) +{ + struct hsphy_priv *priv = phy_get_drvdata(phy); + int ret; + + ret = qcom_snps_hsphy_reset(priv); + if (ret) + return ret; + + qcom_snps_hsphy_init_sequence(priv); + + ret = qcom_snps_hsphy_por_reset(priv); + if (ret) + return ret; + + return 0; +} + +static const struct phy_ops qcom_snps_hsphy_ops = { + .init = qcom_snps_hsphy_init, + .power_on = qcom_snps_hsphy_power_on, + .power_off = qcom_snps_hsphy_power_off, + .set_mode = qcom_snps_hsphy_set_mode, + .owner = THIS_MODULE, +}; + +static const char * const qcom_snps_hsphy_clks[] = { + "ref", + "ahb", + "sleep", +}; + +static int qcom_snps_hsphy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy_provider *provider; + struct hsphy_priv *priv; + struct phy *phy; + int ret; + int i; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->num_clks = ARRAY_SIZE(qcom_snps_hsphy_clks); + priv->clks = devm_kcalloc(dev, priv->num_clks, sizeof(*priv->clks), + GFP_KERNEL); + if (!priv->clks) + return -ENOMEM; + + for (i = 0; i < priv->num_clks; i++) + priv->clks[i].id = qcom_snps_hsphy_clks[i]; + + ret = devm_clk_bulk_get(dev, priv->num_clks, priv->clks); + if (ret) + return ret; + + priv->phy_reset = devm_reset_control_get_exclusive(dev, "phy"); + if (IS_ERR(priv->phy_reset)) + return PTR_ERR(priv->phy_reset); + + priv->por_reset = devm_reset_control_get_exclusive(dev, "por"); + if (IS_ERR(priv->por_reset)) + return PTR_ERR(priv->por_reset); + + priv->vregs[VDD].supply = "vdd"; + priv->vregs[VDDA_1P8].supply = "vdda1p8"; + priv->vregs[VDDA_3P3].supply = "vdda3p3"; + + ret = devm_regulator_bulk_get(dev, VREG_NUM, priv->vregs); + if (ret) + return ret; + + /* Get device match data */ + priv->data = device_get_match_data(dev); + + phy = devm_phy_create(dev, dev->of_node, &qcom_snps_hsphy_ops); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + phy_set_drvdata(phy, priv); + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(provider)) + return PTR_ERR(provider); + + ret = regulator_set_load(priv->vregs[VDDA_1P8].consumer, 19000); + if (ret < 0) + return ret; + + ret = regulator_set_load(priv->vregs[VDDA_3P3].consumer, 16000); + if (ret < 0) + goto unset_1p8_load; + + return 0; + +unset_1p8_load: + regulator_set_load(priv->vregs[VDDA_1P8].consumer, 0); + + return ret; +} + +/* + * The macro is used to define an initialization sequence. Each tuple + * is meant to program 'value' into phy register at 'offset' with 'delay' + * in us followed. + */ +#define HSPHY_INIT_CFG(o, v, d) { .offset = o, .val = v, .delay = d, } + +static const struct hsphy_init_seq init_seq_femtophy[] = { + HSPHY_INIT_CFG(0xc0, 0x01, 0), + HSPHY_INIT_CFG(0xe8, 0x0d, 0), + HSPHY_INIT_CFG(0x74, 0x12, 0), + HSPHY_INIT_CFG(0x98, 0x63, 0), + HSPHY_INIT_CFG(0x9c, 0x03, 0), + HSPHY_INIT_CFG(0xa0, 0x1d, 0), + HSPHY_INIT_CFG(0xa4, 0x03, 0), + HSPHY_INIT_CFG(0x8c, 0x23, 0), + HSPHY_INIT_CFG(0x78, 0x08, 0), + HSPHY_INIT_CFG(0x7c, 0xdc, 0), + HSPHY_INIT_CFG(0x90, 0xe0, 20), + HSPHY_INIT_CFG(0x74, 0x10, 0), + HSPHY_INIT_CFG(0x90, 0x60, 0), +}; + +static const struct hsphy_data hsphy_data_femtophy = { + .init_seq = init_seq_femtophy, + .init_seq_num = ARRAY_SIZE(init_seq_femtophy), +}; + +static const struct of_device_id qcom_snps_hsphy_match[] = { + { .compatible = "qcom,usb-hs-28nm-femtophy", .data = &hsphy_data_femtophy, }, + { }, +}; +MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_match); + +static struct platform_driver qcom_snps_hsphy_driver = { + .probe = qcom_snps_hsphy_probe, + .driver = { + .name = "qcom,usb-hs-28nm-phy", + .of_match_table = qcom_snps_hsphy_match, + }, +}; +module_platform_driver(qcom_snps_hsphy_driver); + +MODULE_DESCRIPTION("Qualcomm 28nm Hi-Speed USB PHY driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/qualcomm/phy-qcom-usb-ss.c b/drivers/phy/qualcomm/phy-qcom-usb-ss.c new file mode 100644 index 000000000000..a3a6d3ce7ea1 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-usb-ss.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2012-2014,2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, Linaro Limited + */ + +#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/regulator/consumer.h> +#include <linux/reset.h> +#include <linux/slab.h> + +#define PHY_CTRL0 0x6C +#define PHY_CTRL1 0x70 +#define PHY_CTRL2 0x74 +#define PHY_CTRL4 0x7C + +/* PHY_CTRL bits */ +#define REF_PHY_EN BIT(0) +#define LANE0_PWR_ON BIT(2) +#define SWI_PCS_CLK_SEL BIT(4) +#define TST_PWR_DOWN BIT(4) +#define PHY_RESET BIT(7) + +#define NUM_BULK_CLKS 3 +#define NUM_BULK_REGS 2 + +struct ssphy_priv { + void __iomem *base; + struct device *dev; + struct reset_control *reset_com; + struct reset_control *reset_phy; + struct regulator_bulk_data regs[NUM_BULK_REGS]; + struct clk_bulk_data clks[NUM_BULK_CLKS]; + enum phy_mode mode; +}; + +static inline void qcom_ssphy_updatel(void __iomem *addr, u32 mask, u32 val) +{ + writel((readl(addr) & ~mask) | val, addr); +} + +static int qcom_ssphy_do_reset(struct ssphy_priv *priv) +{ + int ret; + + if (!priv->reset_com) { + qcom_ssphy_updatel(priv->base + PHY_CTRL1, PHY_RESET, + PHY_RESET); + usleep_range(10, 20); + qcom_ssphy_updatel(priv->base + PHY_CTRL1, PHY_RESET, 0); + } else { + ret = reset_control_assert(priv->reset_com); + if (ret) { + dev_err(priv->dev, "Failed to assert reset com\n"); + return ret; + } + + ret = reset_control_assert(priv->reset_phy); + if (ret) { + dev_err(priv->dev, "Failed to assert reset phy\n"); + return ret; + } + + usleep_range(10, 20); + + ret = reset_control_deassert(priv->reset_com); + if (ret) { + dev_err(priv->dev, "Failed to deassert reset com\n"); + return ret; + } + + ret = reset_control_deassert(priv->reset_phy); + if (ret) { + dev_err(priv->dev, "Failed to deassert reset phy\n"); + return ret; + } + } + + return 0; +} + +static int qcom_ssphy_power_on(struct phy *phy) +{ + struct ssphy_priv *priv = phy_get_drvdata(phy); + int ret; + + ret = regulator_bulk_enable(NUM_BULK_REGS, priv->regs); + if (ret) + return ret; + + ret = clk_bulk_prepare_enable(NUM_BULK_CLKS, priv->clks); + if (ret) + goto err_disable_regulator; + + ret = qcom_ssphy_do_reset(priv); + if (ret) + goto err_disable_clock; + + writeb(SWI_PCS_CLK_SEL, priv->base + PHY_CTRL0); + qcom_ssphy_updatel(priv->base + PHY_CTRL4, LANE0_PWR_ON, LANE0_PWR_ON); + qcom_ssphy_updatel(priv->base + PHY_CTRL2, REF_PHY_EN, REF_PHY_EN); + qcom_ssphy_updatel(priv->base + PHY_CTRL4, TST_PWR_DOWN, 0); + + return 0; +err_disable_clock: + clk_bulk_disable_unprepare(NUM_BULK_CLKS, priv->clks); +err_disable_regulator: + regulator_bulk_disable(NUM_BULK_REGS, priv->regs); + + return ret; +} + +static int qcom_ssphy_power_off(struct phy *phy) +{ + struct ssphy_priv *priv = phy_get_drvdata(phy); + + qcom_ssphy_updatel(priv->base + PHY_CTRL4, LANE0_PWR_ON, 0); + qcom_ssphy_updatel(priv->base + PHY_CTRL2, REF_PHY_EN, 0); + qcom_ssphy_updatel(priv->base + PHY_CTRL4, TST_PWR_DOWN, TST_PWR_DOWN); + + clk_bulk_disable_unprepare(NUM_BULK_CLKS, priv->clks); + regulator_bulk_disable(NUM_BULK_REGS, priv->regs); + + return 0; +} + +static int qcom_ssphy_init_clock(struct ssphy_priv *priv) +{ + priv->clks[0].id = "ref"; + priv->clks[1].id = "ahb"; + priv->clks[2].id = "pipe"; + + return devm_clk_bulk_get(priv->dev, NUM_BULK_CLKS, priv->clks); +} + +static int qcom_ssphy_init_regulator(struct ssphy_priv *priv) +{ + int ret; + + priv->regs[0].supply = "vdd"; + priv->regs[1].supply = "vdda1p8"; + ret = devm_regulator_bulk_get(priv->dev, NUM_BULK_REGS, priv->regs); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(priv->dev, "Failed to get regulators\n"); + return ret; + } + + return ret; +} + +static int qcom_ssphy_init_reset(struct ssphy_priv *priv) +{ + priv->reset_com = devm_reset_control_get_optional_exclusive(priv->dev, "com"); + if (IS_ERR(priv->reset_com)) { + dev_err(priv->dev, "Failed to get reset control com\n"); + return PTR_ERR(priv->reset_com); + } + + if (priv->reset_com) { + /* if reset_com is present, reset_phy is no longer optional */ + priv->reset_phy = devm_reset_control_get_exclusive(priv->dev, "phy"); + if (IS_ERR(priv->reset_phy)) { + dev_err(priv->dev, "Failed to get reset control phy\n"); + return PTR_ERR(priv->reset_phy); + } + } + + return 0; +} + +static const struct phy_ops qcom_ssphy_ops = { + .power_off = qcom_ssphy_power_off, + .power_on = qcom_ssphy_power_on, + .owner = THIS_MODULE, +}; + +static int qcom_ssphy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy_provider *provider; + struct ssphy_priv *priv; + struct phy *phy; + int ret; + + priv = devm_kzalloc(dev, sizeof(struct ssphy_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->mode = PHY_MODE_INVALID; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + ret = qcom_ssphy_init_clock(priv); + if (ret) + return ret; + + ret = qcom_ssphy_init_reset(priv); + if (ret) + return ret; + + ret = qcom_ssphy_init_regulator(priv); + if (ret) + return ret; + + phy = devm_phy_create(dev, dev->of_node, &qcom_ssphy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "Failed to create the SS phy\n"); + return PTR_ERR(phy); + } + + phy_set_drvdata(phy, priv); + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static const struct of_device_id qcom_ssphy_match[] = { + { .compatible = "qcom,usb-ss-28nm-phy", }, + { }, +}; +MODULE_DEVICE_TABLE(of, qcom_ssphy_match); + +static struct platform_driver qcom_ssphy_driver = { + .probe = qcom_ssphy_probe, + .driver = { + .name = "qcom-usb-ssphy", + .of_match_table = qcom_ssphy_match, + }, +}; +module_platform_driver(qcom_ssphy_driver); + +MODULE_DESCRIPTION("Qualcomm SuperSpeed USB PHY driver"); +MODULE_LICENSE("GPL v2"); |