From 998ec9c188bf78f2ffd1c9e7bbf65c525e225db2 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Thu, 10 Nov 2016 15:55:24 +0530 Subject: [PATCH 1/2] phy: ufs: add UFS PHY support for msmfalcon Add support for new UFS PHY that is used in falcon msm. This PHY is identical to the final 8996 PHY except it has been moved to VDDMX and level shifters have been added between the controller/chip and the PHY. Change-Id: I50681c877917a58c3d70262597300b0d66b1e3a8 Signed-off-by: Asutosh Das --- .../devicetree/bindings/ufs/ufs-qcom.txt | 4 +- drivers/phy/Makefile | 1 + drivers/phy/phy-qcom-ufs-qmp-v3-falcon.c | 260 ++++++++++++++++ drivers/phy/phy-qcom-ufs-qmp-v3-falcon.h | 283 ++++++++++++++++++ 4 files changed, 547 insertions(+), 1 deletion(-) create mode 100644 drivers/phy/phy-qcom-ufs-qmp-v3-falcon.c create mode 100644 drivers/phy/phy-qcom-ufs-qmp-v3-falcon.h diff --git a/Documentation/devicetree/bindings/ufs/ufs-qcom.txt b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt index 80488c802df2..66142b4cd880 100644 --- a/Documentation/devicetree/bindings/ufs/ufs-qcom.txt +++ b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt @@ -9,7 +9,9 @@ contain a phandle reference to UFS PHY node. Required properties: - compatible : compatible list, contains "qcom,ufs-phy-qmp-20nm" or "qcom,ufs-phy-qmp-14nm" or "qcom,ufs-phy-qmp-v3" - or "qcom,ufs-phy-qrbtc-v2" according to the relevant phy in use. + or "qcom,ufs-phy-qrbtc-v2" or + "qcom,ufs-phy-qmp-v3-falcon" + according to the relevant phy in use. - reg : should contain PHY register address space (mandatory), - reg-names : indicates various resources passed to driver (via reg proptery) by name. Required "reg-names" is "phy_mem". diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 70cabc7080b3..223339ff119d 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-v3.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qrbtc-v2.o +obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-v3-falcon.o obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3-falcon.c b/drivers/phy/phy-qcom-ufs-qmp-v3-falcon.c new file mode 100644 index 000000000000..e88c00e01e0b --- /dev/null +++ b/drivers/phy/phy-qcom-ufs-qmp-v3-falcon.c @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "phy-qcom-ufs-qmp-v3-falcon.h" + +#define UFS_PHY_NAME "ufs_phy_qmp_v3_falcon" + +static +int ufs_qcom_phy_qmp_v3_falcon_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, + bool is_rate_B) +{ + int err; + int tbl_size_A, tbl_size_B; + struct ufs_qcom_phy_calibration *tbl_A, *tbl_B; + u8 major = ufs_qcom_phy->host_ctrl_rev_major; + u16 minor = ufs_qcom_phy->host_ctrl_rev_minor; + u16 step = ufs_qcom_phy->host_ctrl_rev_step; + + tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B); + tbl_B = phy_cal_table_rate_B; + + if ((major == 0x3) && (minor == 0x001) && (step == 0x001)) { + tbl_A = phy_cal_table_rate_A_3_1_1; + tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_3_1_1); + } else { + dev_err(ufs_qcom_phy->dev, + "%s: Unknown UFS-PHY version (major 0x%x minor 0x%x step 0x%x), no calibration values\n", + __func__, major, minor, step); + err = -ENODEV; + goto out; + } + + err = ufs_qcom_phy_calibrate(ufs_qcom_phy, + tbl_A, tbl_size_A, + tbl_B, tbl_size_B, + is_rate_B); + + if (err) + dev_err(ufs_qcom_phy->dev, + "%s: ufs_qcom_phy_calibrate() failed %d\n", + __func__, err); + +out: + return err; +} + +static int ufs_qcom_phy_qmp_v3_falcon_init(struct phy *generic_phy) +{ + struct ufs_qcom_phy_qmp_v3_falcon *phy = phy_get_drvdata(generic_phy); + struct ufs_qcom_phy *phy_common = &phy->common_cfg; + int err; + + err = ufs_qcom_phy_init_clks(generic_phy, phy_common); + if (err) { + dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n", + __func__, err); + goto out; + } + + err = ufs_qcom_phy_init_vregulators(generic_phy, phy_common); + if (err) { + dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n", + __func__, err); + goto out; + } + +out: + return err; +} + +static +void ufs_qcom_phy_qmp_v3_falcon_power_control(struct ufs_qcom_phy *phy, + bool power_ctrl) +{ + if (!power_ctrl) { + /* apply analog power collapse */ + writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL); + /* + * Make sure that PHY knows its analog rail is going to be + * powered OFF. + */ + mb(); + } else { + /* bring PHY out of analog power collapse */ + writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL); + + /* + * Before any transactions involving PHY, ensure PHY knows + * that it's analog rail is powered ON. + */ + mb(); + } +} + +static inline +void ufs_qcom_phy_qmp_v3_falcon_set_tx_lane_enable(struct ufs_qcom_phy *phy, + u32 val) +{ + /* + * v3 PHY does not have TX_LANE_ENABLE register. + * Implement this function so as not to propagate error to caller. + */ +} + +static +void ufs_qcom_phy_qmp_v3_falcon_ctrl_rx_linecfg(struct ufs_qcom_phy *phy, + bool ctrl) +{ + u32 temp; + + temp = readl_relaxed(phy->mmio + UFS_PHY_LINECFG_DISABLE); + + if (ctrl) /* enable RX LineCfg */ + temp &= ~UFS_PHY_RX_LINECFG_DISABLE_BIT; + else /* disable RX LineCfg */ + temp |= UFS_PHY_RX_LINECFG_DISABLE_BIT; + + writel_relaxed(temp, phy->mmio + UFS_PHY_LINECFG_DISABLE); + /* Make sure that RX LineCfg config applied before we return */ + mb(); +} + +static inline void ufs_qcom_phy_qmp_v3_falcon_start_serdes( + struct ufs_qcom_phy *phy) +{ + u32 tmp; + + tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START); + tmp &= ~MASK_SERDES_START; + tmp |= (1 << OFFSET_SERDES_START); + writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START); + /* Ensure register value is committed */ + mb(); +} + +static int ufs_qcom_phy_qmp_v3_falcon_is_pcs_ready( + struct ufs_qcom_phy *phy_common) +{ + int err = 0; + u32 val; + + err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS, + val, (val & MASK_PCS_READY), 10, 1000000); + if (err) + dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n", + __func__, err); + return err; +} + +static void ufs_qcom_phy_qmp_v3_falcon_dbg_register_dump( + struct ufs_qcom_phy *phy) +{ + ufs_qcom_phy_dump_regs(phy, COM_BASE, COM_SIZE, + "PHY QSERDES COM Registers "); + ufs_qcom_phy_dump_regs(phy, PHY_BASE, PHY_SIZE, + "PHY Registers "); + ufs_qcom_phy_dump_regs(phy, RX_BASE, RX_SIZE, + "PHY RX0 Registers "); + ufs_qcom_phy_dump_regs(phy, TX_BASE, TX_SIZE, + "PHY TX0 Registers "); +} + +struct phy_ops ufs_qcom_phy_qmp_v3_falcon_phy_ops = { + .init = ufs_qcom_phy_qmp_v3_falcon_init, + .exit = ufs_qcom_phy_exit, + .power_on = ufs_qcom_phy_power_on, + .power_off = ufs_qcom_phy_power_off, + .owner = THIS_MODULE, +}; + +struct ufs_qcom_phy_specific_ops phy_v3_falcon_ops = { + .calibrate_phy = ufs_qcom_phy_qmp_v3_falcon_phy_calibrate, + .start_serdes = ufs_qcom_phy_qmp_v3_falcon_start_serdes, + .is_physical_coding_sublayer_ready = + ufs_qcom_phy_qmp_v3_falcon_is_pcs_ready, + .set_tx_lane_enable = ufs_qcom_phy_qmp_v3_falcon_set_tx_lane_enable, + .ctrl_rx_linecfg = ufs_qcom_phy_qmp_v3_falcon_ctrl_rx_linecfg, + .power_control = ufs_qcom_phy_qmp_v3_falcon_power_control, + .dbg_register_dump = ufs_qcom_phy_qmp_v3_falcon_dbg_register_dump, +}; + +static int ufs_qcom_phy_qmp_v3_falcon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy *generic_phy; + struct ufs_qcom_phy_qmp_v3_falcon *phy; + int err = 0; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) { + err = -ENOMEM; + goto out; + } + + generic_phy = ufs_qcom_phy_generic_probe(pdev, &phy->common_cfg, + &ufs_qcom_phy_qmp_v3_falcon_phy_ops, + &phy_v3_falcon_ops); + + if (!generic_phy) { + dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n", + __func__); + err = -EIO; + goto out; + } + + phy_set_drvdata(generic_phy, phy); + + strlcpy(phy->common_cfg.name, UFS_PHY_NAME, + sizeof(phy->common_cfg.name)); + +out: + return err; +} + +static int ufs_qcom_phy_qmp_v3_falcon_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy *generic_phy = to_phy(dev); + struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy); + int err = 0; + + err = ufs_qcom_phy_remove(generic_phy, ufs_qcom_phy); + if (err) + dev_err(dev, "%s: ufs_qcom_phy_remove failed = %d\n", + __func__, err); + + return err; +} + +static const struct of_device_id ufs_qcom_phy_qmp_v3_falcon_of_match[] = { + {.compatible = "qcom,ufs-phy-qmp-v3-falcon"}, + {}, +}; +MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qmp_v3_falcon_of_match); + +static struct platform_driver ufs_qcom_phy_qmp_v3_falcon_driver = { + .probe = ufs_qcom_phy_qmp_v3_falcon_probe, + .remove = ufs_qcom_phy_qmp_v3_falcon_remove, + .driver = { + .of_match_table = ufs_qcom_phy_qmp_v3_falcon_of_match, + .name = "ufs_qcom_phy_qmp_v3_falcon", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(ufs_qcom_phy_qmp_v3_falcon_driver); + +MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QMP v3 falcon"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3-falcon.h b/drivers/phy/phy-qcom-ufs-qmp-v3-falcon.h new file mode 100644 index 000000000000..e64601cc6b22 --- /dev/null +++ b/drivers/phy/phy-qcom-ufs-qmp-v3-falcon.h @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef UFS_QCOM_PHY_QMP_V3_FALCON_H_ +#define UFS_QCOM_PHY_QMP_V3_FALCON_H_ + +#include "phy-qcom-ufs-i.h" + +/* QCOM UFS PHY control registers */ +#define COM_BASE 0x000 +#define COM_OFF(x) (COM_BASE + x) +#define COM_SIZE 0x1C0 + +#define TX_BASE 0x400 +#define TX_OFF(x) (TX_BASE + x) +#define TX_SIZE 0x128 + +#define RX_BASE 0x600 +#define RX_OFF(x) (RX_BASE + x) +#define RX_SIZE 0x1FC + +#define PHY_BASE 0xC00 +#define PHY_OFF(x) (PHY_BASE + x) +#define PHY_SIZE 0x1B4 + +/* UFS PHY QSERDES COM registers */ +#define QSERDES_COM_ATB_SEL1 COM_OFF(0x00) +#define QSERDES_COM_ATB_SEL2 COM_OFF(0x04) +#define QSERDES_COM_FREQ_UPDATE COM_OFF(0x08) +#define QSERDES_COM_BG_TIMER COM_OFF(0x0C) +#define QSERDES_COM_SSC_EN_CENTER COM_OFF(0x10) +#define QSERDES_COM_SSC_ADJ_PER1 COM_OFF(0x14) +#define QSERDES_COM_SSC_ADJ_PER2 COM_OFF(0x18) +#define QSERDES_COM_SSC_PER1 COM_OFF(0x1C) +#define QSERDES_COM_SSC_PER2 COM_OFF(0x20) +#define QSERDES_COM_SSC_STEP_SIZE1 COM_OFF(0x24) +#define QSERDES_COM_SSC_STEP_SIZE2 COM_OFF(0x28) +#define QSERDES_COM_POST_DIV COM_OFF(0x2C) +#define QSERDES_COM_POST_DIV_MUX COM_OFF(0x30) +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN COM_OFF(0x34) +#define QSERDES_COM_CLK_ENABLE1 COM_OFF(0x38) +#define QSERDES_COM_SYS_CLK_CTRL COM_OFF(0x3C) +#define QSERDES_COM_SYSCLK_BUF_ENABLE COM_OFF(0x40) +#define QSERDES_COM_PLL_EN COM_OFF(0x44) +#define QSERDES_COM_PLL_IVCO COM_OFF(0x48) +#define QSERDES_COM_LOCK_CMP1_MODE0 COM_OFF(0X4C) +#define QSERDES_COM_LOCK_CMP2_MODE0 COM_OFF(0X50) +#define QSERDES_COM_LOCK_CMP3_MODE0 COM_OFF(0X54) +#define QSERDES_COM_LOCK_CMP1_MODE1 COM_OFF(0X58) +#define QSERDES_COM_LOCK_CMP2_MODE1 COM_OFF(0X5C) +#define QSERDES_COM_LOCK_CMP3_MODE1 COM_OFF(0X60) +#define QSERDES_COM_CMD_RSVD0 COM_OFF(0x64) +#define QSERDES_COM_EP_CLOCK_DETECT_CTRL COM_OFF(0x68) +#define QSERDES_COM_SYSCLK_DET_COMP_STATUS COM_OFF(0x6C) +#define QSERDES_COM_BG_TRIM COM_OFF(0x70) +#define QSERDES_COM_CLK_EP_DIV COM_OFF(0x74) +#define QSERDES_COM_CP_CTRL_MODE0 COM_OFF(0x78) +#define QSERDES_COM_CP_CTRL_MODE1 COM_OFF(0x7C) +#define QSERDES_COM_CMN_RSVD1 COM_OFF(0x80) +#define QSERDES_COM_PLL_RCTRL_MODE0 COM_OFF(0x84) +#define QSERDES_COM_PLL_RCTRL_MODE1 COM_OFF(0x88) +#define QSERDES_COM_CMN_RSVD2 COM_OFF(0x8C) +#define QSERDES_COM_PLL_CCTRL_MODE0 COM_OFF(0x90) +#define QSERDES_COM_PLL_CCTRL_MODE1 COM_OFF(0x94) +#define QSERDES_COM_CMN_RSVD3 COM_OFF(0x98) +#define QSERDES_COM_PLL_CNTRL COM_OFF(0x9C) +#define QSERDES_COM_PHASE_SEL_CTRL COM_OFF(0xA0) +#define QSERDES_COM_PHASE_SEL_DC COM_OFF(0xA4) +#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM COM_OFF(0xA8) +#define QSERDES_COM_SYSCLK_EN_SEL COM_OFF(0xAC) +#define QSERDES_COM_CML_SYSCLK_SEL COM_OFF(0xB0) +#define QSERDES_COM_RESETSM_CNTRL COM_OFF(0xB4) +#define QSERDES_COM_RESETSM_CNTRL2 COM_OFF(0xB8) +#define QSERDES_COM_RESTRIM_CTRL COM_OFF(0xBC) +#define QSERDES_COM_RESTRIM_CTRL2 COM_OFF(0xC0) +#define QSERDES_COM_LOCK_CMP_EN COM_OFF(0xC8) +#define QSERDES_COM_LOCK_CMP_CFG COM_OFF(0xCC) +#define QSERDES_COM_DEC_START_MODE0 COM_OFF(0xD0) +#define QSERDES_COM_DEC_START_MODE1 COM_OFF(0xD4) +#define QSERDES_COM_VCOCAL_DEADMAN_CTRL COM_OFF(0xD8) +#define QSERDES_COM_DIV_FRAC_START1_MODE0 COM_OFF(0xDC) +#define QSERDES_COM_DIV_FRAC_START2_MODE0 COM_OFF(0xE0) +#define QSERDES_COM_DIV_FRAC_START3_MODE0 COM_OFF(0xE4) +#define QSERDES_COM_DIV_FRAC_START1_MODE1 COM_OFF(0xE8) +#define QSERDES_COM_DIV_FRAC_START2_MODE1 COM_OFF(0xEC) +#define QSERDES_COM_DIV_FRAC_START3_MODE1 COM_OFF(0xF0) +#define QSERDES_COM_VCO_TUNE_MINVAL1 COM_OFF(0xF4) +#define QSERDES_COM_VCO_TUNE_MINVAL2 COM_OFF(0xF8) +#define QSERDES_COM_CMN_RSVD4 COM_OFF(0xFC) +#define QSERDES_COM_INTEGLOOP_INITVAL COM_OFF(0x100) +#define QSERDES_COM_INTEGLOOP_EN COM_OFF(0x104) +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 COM_OFF(0x108) +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 COM_OFF(0x10C) +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 COM_OFF(0x110) +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 COM_OFF(0x114) +#define QSERDES_COM_VCO_TUNE_MAXVAL1 COM_OFF(0x118) +#define QSERDES_COM_VCO_TUNE_MAXVAL2 COM_OFF(0x11C) +#define QSERDES_COM_RES_TRIM_CONTROL2 COM_OFF(0x120) +#define QSERDES_COM_VCO_TUNE_CTRL COM_OFF(0x124) +#define QSERDES_COM_VCO_TUNE_MAP COM_OFF(0x128) +#define QSERDES_COM_VCO_TUNE1_MODE0 COM_OFF(0x12C) +#define QSERDES_COM_VCO_TUNE2_MODE0 COM_OFF(0x130) +#define QSERDES_COM_VCO_TUNE1_MODE1 COM_OFF(0x134) +#define QSERDES_COM_VCO_TUNE2_MODE1 COM_OFF(0x138) +#define QSERDES_COM_VCO_TUNE_INITVAL1 COM_OFF(0x13C) +#define QSERDES_COM_VCO_TUNE_INITVAL2 COM_OFF(0x140) +#define QSERDES_COM_VCO_TUNE_TIMER1 COM_OFF(0x144) +#define QSERDES_COM_VCO_TUNE_TIMER2 COM_OFF(0x148) +#define QSERDES_COM_SAR COM_OFF(0x14C) +#define QSERDES_COM_SAR_CLK COM_OFF(0x150) +#define QSERDES_COM_SAR_CODE_OUT_STATUS COM_OFF(0x154) +#define QSERDES_COM_SAR_CODE_READY_STATUS COM_OFF(0x158) +#define QSERDES_COM_CMN_STATUS COM_OFF(0x15C) +#define QSERDES_COM_RESET_SM_STATUS COM_OFF(0x160) +#define QSERDES_COM_RESTRIM_CODE_STATUS COM_OFF(0x164) +#define QSERDES_COM_PLLCAL_CODE1_STATUS COM_OFF(0x168) +#define QSERDES_COM_PLLCAL_CODE2_STATUS COM_OFF(0x16C) +#define QSERDES_COM_BG_CTRL COM_OFF(0x170) +#define QSERDES_COM_CLK_SELECT COM_OFF(0x174) +#define QSERDES_COM_HSCLK_SEL COM_OFF(0x178) +#define QSERDES_COM_INTEGLOOP_BINCODE_STATUS COM_OFF(0x17C) +#define QSERDES_COM_PLL_ANALOG COM_OFF(0x180) +#define QSERDES_COM_CORECLK_DIV COM_OFF(0x184) +#define QSERDES_COM_SW_RESET COM_OFF(0x188) +#define QSERDES_COM_CORE_CLK_EN COM_OFF(0x18C) +#define QSERDES_COM_C_READY_STATUS COM_OFF(0x190) +#define QSERDES_COM_CMN_CONFIG COM_OFF(0x194) +#define QSERDES_COM_CMN_RATE_OVERRIDE COM_OFF(0x198) +#define QSERDES_COM_SVS_MODE_CLK_SEL COM_OFF(0x19C) +#define QSERDES_COM_DEBUG_BUS0 COM_OFF(0x1A0) +#define QSERDES_COM_DEBUG_BUS1 COM_OFF(0x1A4) +#define QSERDES_COM_DEBUG_BUS2 COM_OFF(0x1A8) +#define QSERDES_COM_DEBUG_BUS3 COM_OFF(0x1AC) +#define QSERDES_COM_DEBUG_BUS_SEL COM_OFF(0x1B0) +#define QSERDES_COM_CMN_MISC1 COM_OFF(0x1B4) +#define QSERDES_COM_CORECLK_DIV_MODE1 COM_OFF(0x1BC) +#define QSERDES_COM_CMN_RSVD5 COM_OFF(0x1C0) + +/* UFS PHY registers */ +#define UFS_PHY_PHY_START PHY_OFF(0x00) +#define UFS_PHY_POWER_DOWN_CONTROL PHY_OFF(0x04) +#define UFS_PHY_TX_LARGE_AMP_DRV_LVL PHY_OFF(0x34) +#define UFS_PHY_TX_SMALL_AMP_DRV_LVL PHY_OFF(0x3C) +#define UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAP PHY_OFF(0xCC) +#define UFS_PHY_LINECFG_DISABLE PHY_OFF(0x138) +#define UFS_PHY_RX_SYM_RESYNC_CTRL PHY_OFF(0x13C) +#define UFS_PHY_RX_SIGDET_CTRL2 PHY_OFF(0x148) +#define UFS_PHY_RX_PWM_GEAR_BAND PHY_OFF(0x154) +#define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x168) + +/* UFS PHY TX registers */ +#define QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN TX_OFF(0x68) +#define QSERDES_TX_LANE_MODE TX_OFF(0x94) + +/* UFS PHY RX registers */ +#define QSERDES_RX_UCDR_SVS_SO_GAIN_HALF RX_OFF(0x30) +#define QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER RX_OFF(0x34) +#define QSERDES_RX_UCDR_SVS_SO_GAIN_EIGHTH RX_OFF(0x38) +#define QSERDES_RX_UCDR_SVS_SO_GAIN RX_OFF(0x3C) +#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN RX_OFF(0x40) +#define QSERDES_RX_UCDR_SO_SATURATION_ENABLE RX_OFF(0x48) +#define QSERDES_RX_RX_TERM_BW RX_OFF(0x90) +#define QSERDES_RX_RX_EQ_GAIN1_LSB RX_OFF(0xC4) +#define QSERDES_RX_RX_EQ_GAIN1_MSB RX_OFF(0xC8) +#define QSERDES_RX_RX_EQ_GAIN2_LSB RX_OFF(0xCC) +#define QSERDES_RX_RX_EQ_GAIN2_MSB RX_OFF(0xD0) +#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 RX_OFF(0xD8) +#define QSERDES_RX_SIGDET_CNTRL RX_OFF(0x114) +#define QSERDES_RX_SIGDET_LVL RX_OFF(0x118) +#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL RX_OFF(0x11C) +#define QSERDES_RX_RX_INTERFACE_MODE RX_OFF(0x12C) + + +#define UFS_PHY_RX_LINECFG_DISABLE_BIT BIT(1) + +/* + * This structure represents the v3 falcon specific phy. + * common_cfg MUST remain the first field in this structure + * in case extra fields are added. This way, when calling + * get_ufs_qcom_phy() of generic phy, we can extract the + * common phy structure (struct ufs_qcom_phy) out of it + * regardless of the relevant specific phy. + */ +struct ufs_qcom_phy_qmp_v3_falcon { + struct ufs_qcom_phy common_cfg; +}; + +static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_3_1_1[] = { + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_CONFIG, 0x0e), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0x14), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CLK_SELECT, 0x30), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYS_CLK_CTRL, 0x02), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BG_TIMER, 0x0a), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_HSCLK_SEL, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV, 0x0a), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_EN, 0x01), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_CTRL, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x20), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORE_CLK_EN, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_CFG, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER1, 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x04), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE0, 0x82), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x0b), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0x28), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE0, 0x02), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0xff), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE1, 0x98), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x0b), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE1, 0x16), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x28), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE1, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE1, 0x00), + + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN, 0x45), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE, 0x06), + + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_LVL, 0x24), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL, 0x0F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_INTERFACE_MODE, 0x40), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1E), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_TERM_BW, 0x5B), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xFF), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xFF), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x3F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0D), + + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IVCO, 0x0F), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BG_TRIM, 0x0F), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_PWM_GEAR_BAND, 0x15), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SVS_SO_GAIN_HALF, 0x04), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SVS_SO_GAIN, 0x04), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SO_SATURATION_ENABLE, 0x4B), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL1, 0xFF), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6c), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0A), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAP, 0x28), + UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SYM_RESYNC_CTRL, 0x03), +}; + +static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = { + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x44), +}; + +#endif From 8fb5f8480348d27fef0037b97065494f39596544 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Wed, 5 Oct 2016 17:22:24 +0530 Subject: [PATCH 2/2] ARM: dts: msm: add ufs support to msmfalcon Add ufs and ufs-phy device nodes for msmfalcon. Change-Id: I42e796ca7e1883f5c2077660dbcde87cd4b30038 Signed-off-by: Asutosh Das --- arch/arm/boot/dts/qcom/msmfalcon-cdp.dtsi | 21 ++++++ arch/arm/boot/dts/qcom/msmfalcon-mtp.dtsi | 21 ++++++ arch/arm/boot/dts/qcom/msmfalcon-rumi.dts | 20 ++++++ arch/arm/boot/dts/qcom/msmfalcon-sim.dts | 21 ++++++ arch/arm/boot/dts/qcom/msmfalcon.dtsi | 79 +++++++++++++++++++++++ 5 files changed, 162 insertions(+) diff --git a/arch/arm/boot/dts/qcom/msmfalcon-cdp.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-cdp.dtsi index 3ec991b82bba..ff14003877d1 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon-cdp.dtsi @@ -20,5 +20,26 @@ pinctrl-0 = <&uart_console_active>; }; +&ufsphy1 { + vdda-phy-supply = <&pm2falcon_l1>; + vdda-pll-supply = <&pmfalcon_l10>; + vddp-ref-clk-supply = <&pmfalcon_l1>; + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14200>; + vddp-ref-clk-max-microamp = <100>; + vddp-ref-clk-always-on; + status = "ok"; +}; + +&ufs1 { + vdd-hba-supply = <&gdsc_ufs>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm2falcon_l4>; + vccq2-supply = <&pmfalcon_l8>; + vcc-max-microamp = <500000>; + vccq2-max-microamp = <600000>; + status = "ok"; +}; + &soc { }; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-mtp.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-mtp.dtsi index 3ec991b82bba..ff14003877d1 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon-mtp.dtsi @@ -20,5 +20,26 @@ pinctrl-0 = <&uart_console_active>; }; +&ufsphy1 { + vdda-phy-supply = <&pm2falcon_l1>; + vdda-pll-supply = <&pmfalcon_l10>; + vddp-ref-clk-supply = <&pmfalcon_l1>; + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14200>; + vddp-ref-clk-max-microamp = <100>; + vddp-ref-clk-always-on; + status = "ok"; +}; + +&ufs1 { + vdd-hba-supply = <&gdsc_ufs>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm2falcon_l4>; + vccq2-supply = <&pmfalcon_l8>; + vcc-max-microamp = <500000>; + vccq2-max-microamp = <600000>; + status = "ok"; +}; + &soc { }; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts index d952c3b5e299..ab61ee115782 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts +++ b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts @@ -117,3 +117,23 @@ compatible = "qcom,dummycc"; clock-output-names = "mmss_clocks"; }; + +&ufsphy1 { + vdda-phy-supply = <&pm2falcon_l1>; + vdda-pll-supply = <&pmfalcon_l10>; + vddp-ref-clk-supply = <&pmfalcon_l1>; + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14200>; + vddp-ref-clk-max-microamp = <100>; + vddp-ref-clk-always-on; +}; + +&ufs1 { + vdd-hba-supply = <&gdsc_ufs>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm2falcon_l4>; + vccq2-supply = <&pmfalcon_l8>; + vcc-max-microamp = <500000>; + vccq2-max-microamp = <600000>; + qcom,disable-lpm; +}; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts index fe92f40d786f..80772bab86e4 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts +++ b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts @@ -86,3 +86,24 @@ &pmfalcon_pdphy { status = "disabled"; }; + +&ufsphy1 { + vdda-phy-supply = <&pm2falcon_l1>; + vdda-pll-supply = <&pmfalcon_l10>; + vddp-ref-clk-supply = <&pmfalcon_l1>; + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14200>; + vddp-ref-clk-max-microamp = <100>; + vddp-ref-clk-always-on; + status = "ok"; +}; + +&ufs1 { + vdd-hba-supply = <&gdsc_ufs>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm2falcon_l4>; + vccq2-supply = <&pmfalcon_l8>; + vcc-max-microamp = <500000>; + vccq2-max-microamp = <600000>; + status = "ok"; +}; diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index 572a896ad795..c76cdcdbb9ee 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi @@ -1565,6 +1565,85 @@ qcom,config-arr = <0x178880b8 0x178980b8 0x178a80b8 0x178b80b8>; }; + + ufsphy1: ufsphy@1da7000 { + compatible = "qcom,ufs-phy-qmp-v3-falcon"; + reg = <0x1da7000 0xdb8>; + reg-names = "phy_mem"; + #phy-cells = <0>; + clock-names = "ref_clk_src", + "ref_clk", + "ref_aux_clk"; + clocks = <&clock_rpmcc RPM_LN_BB_CLK1>, + <&clock_gcc GCC_UFS_CLKREF_CLK>, + <&clock_gcc GCC_UFS_PHY_AUX_CLK>; + status = "disabled"; + }; + + ufs1: ufshc@1da4000 { + compatible = "qcom,ufshc"; + reg = <0x1da4000 0x3000>; + interrupts = <0 265 0>; + phys = <&ufsphy1>; + phy-names = "ufsphy"; + + clock-names = + "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "core_clk_ice", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk"; + clocks = + <&clock_gcc GCC_UFS_AXI_CLK>, + <&clock_gcc GCC_AGGRE2_UFS_AXI_CLK>, + <&clock_gcc GCC_UFS_AHB_CLK>, + <&clock_gcc GCC_UFS_UNIPRO_CORE_CLK>, + <&clock_gcc GCC_UFS_ICE_CORE_CLK>, + <&clock_rpmcc RPM_LN_BB_CLK1>, + <&clock_gcc GCC_UFS_TX_SYMBOL_0_CLK>, + <&clock_gcc GCC_UFS_RX_SYMBOL_0_CLK>; + freq-table-hz = + <50000000 200000000>, + <0 0>, + <0 0>, + <37500000 150000000>, + <75000000 300000000>, + <0 0>, + <0 0>, + <0 0>; + + lanes-per-direction = <1>; + + qcom,msm-bus,name = "ufs1"; + qcom,msm-bus,num-cases = <12>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <95 512 0 0>, <1 650 0 0>, /* No vote */ + <95 512 922 0>, <1 650 1000 0>, /* PWM G1 */ + <95 512 1844 0>, <1 650 1000 0>, /* PWM G2 */ + <95 512 3688 0>, <1 650 1000 0>, /* PWM G3 */ + <95 512 7376 0>, <1 650 1000 0>, /* PWM G4 */ + <95 512 127796 0>, <1 650 1000 0>, /* HS G1 RA */ + <95 512 255591 0>, <1 650 1000 0>, /* HS G2 RA */ + <95 512 2097152 0>, <1 650 102400 0>, /* HS G3 RA */ + <95 512 149422 0>, <1 650 1000 0>, /* HS G1 RB */ + <95 512 298189 0>, <1 650 1000 0>, /* HS G2 RB */ + <95 512 2097152 0>, <1 650 102400 0>, /* HS G3 RB */ + <95 512 7643136 0>, <1 650 307200 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1", + "HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1", + "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1", + "MAX"; + + resets = <&clock_gcc GCC_UFS_BCR>; + reset-names = "core_reset"; + + status = "disabled"; + }; }; #include "msmfalcon-ion.dtsi"