diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 422348f8c395..a2e8d88de1d8 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -160,6 +160,8 @@ #define IPC_TIMEOUT_MS (250) +#define PHY_C_READY (BIT(0)) + #define PHY_READY_TIMEOUT_COUNT (10) #define XMLH_LINK_UP (0x400) #define MAX_PROP_SIZE (32) @@ -608,20 +610,6 @@ struct __packed msm_pcie_drv_msg { struct msm_pcie_drv_tre pkt; }; -struct msm_pcie_drv_info { - bool ep_connected; /* drv supports only one endpoint (no switch) */ - struct msm_pcie_drv_msg drv_enable; /* hand off payload */ - struct msm_pcie_drv_msg drv_disable; /* payload to request back */ - struct msm_pcie_drv_msg drv_enable_l1ss_sleep; /* enable l1ss sleep */ - struct msm_pcie_drv_msg drv_disable_l1ss_sleep; /* disable l1ss sleep */ - int dev_id; - u16 seq; - u16 reply_seq; - u32 timeout_ms; /* IPC command timeout */ - u32 l1ss_timeout_us; - struct completion completion; -}; - /* msm pcie device structure */ struct msm_pcie_dev_t { struct platform_device *pdev; @@ -766,6 +754,27 @@ struct msm_root_dev_t { struct pci_dev *pci_dev; }; +struct msm_pcie_drv_info { + bool ep_connected; /* drv supports only one endpoint (no switch) */ + struct msm_pcie_drv_msg drv_enable; /* hand off payload */ + struct msm_pcie_drv_msg drv_disable; /* payload to request back */ + struct msm_pcie_drv_msg drv_enable_l1ss_sleep; /* enable l1ss sleep */ + struct msm_pcie_drv_msg drv_disable_l1ss_sleep; /* disable l1ss sleep */ + int dev_id; + u16 seq; + u16 reply_seq; + u32 timeout_ms; /* IPC command timeout */ + u32 l1ss_timeout_us; + struct completion completion; + + /* for DRV SSR */ + void (*manage_pll_power_on)(struct msm_pcie_dev_t *pcie_dev, + struct msm_pcie_drv_info *drv_info); + u32 phy_resetsm_cntrl2; + u32 phy_core_pll_en_mux; + u32 phy_c_ready_status; +}; + static u32 msm_pcie_keep_resources_on; /* debugfs values */ @@ -5552,6 +5561,74 @@ static void msm_pcie_check_l1ss_support_all(struct msm_pcie_dev_t *dev) pci_walk_bus(dev->dev->bus, msm_pcie_check_l1ss_support, dev); } +static void msm_pcie_drv_manage_pll_power_on(struct msm_pcie_dev_t *pcie_dev, + struct msm_pcie_drv_info *drv_info) +{ + u32 cnt = 0; + u32 cnt_max = 20; /* 1ms */ + + PCIE_DBG(pcie_dev, "PCIe: RC%d: manually power on PHY PLL\n", + pcie_dev->rc_idx); + + msm_pcie_write_mask(pcie_dev->phy + drv_info->phy_resetsm_cntrl2, + BIT(drv_info->phy_core_pll_en_mux), 0); + + while (!(readl_relaxed(pcie_dev->phy + drv_info->phy_c_ready_status) & + PHY_C_READY)) { + if (unlikely(cnt++ >= cnt_max)) { + PCIE_ERR(pcie_dev, + "PCIe: RC%d: failed to manually power on PHY PLL\n", + pcie_dev->rc_idx); + return; + } + + usleep_range(50, 55); + } + + PCIE_DBG(pcie_dev, "PCIe: RC%d: successfully powered on PHY PLL\n", + pcie_dev->rc_idx); +} + +static int msm_pcie_setup_drv_manage_pll(struct msm_pcie_dev_t *pcie_dev, + struct device_node *of_node, + struct msm_pcie_drv_info *drv_info) +{ + int ret; + + PCIE_DBG(pcie_dev, "PCIe: RC%d: enter\n", pcie_dev->rc_idx); + + ret = of_property_read_u32(of_node, "qcom,phy-resetsm-cntrl2", + &drv_info->phy_resetsm_cntrl2); + if (ret) { + PCIE_ERR(pcie_dev, + "PCIe: RC%d failed to get qcom,phy-resetsm-cntrl2\n", + pcie_dev->rc_idx); + return ret; + } + + ret = of_property_read_u32(of_node, "qcom,phy-core-pll-en-mux", + &drv_info->phy_core_pll_en_mux); + if (ret) { + PCIE_ERR(pcie_dev, + "PCIe: RC%d failed to get qcom,phy-core-pll-en-mux\n", + pcie_dev->rc_idx); + return ret; + } + + ret = of_property_read_u32(of_node, "qcom,phy-c-ready-status", + &drv_info->phy_c_ready_status); + if (ret) { + PCIE_ERR(pcie_dev, + "PCIe: RC%d failed to get qcom,phy-c-ready-status\n", + pcie_dev->rc_idx); + return ret; + } + + drv_info->manage_pll_power_on = msm_pcie_drv_manage_pll_power_on; + + return 0; +} + static void msm_pcie_setup_drv_msg(struct msm_pcie_drv_msg *msg, u32 dev_id, enum msm_pcie_drv_cmds cmd) { @@ -5573,6 +5650,7 @@ static int msm_pcie_setup_drv(struct msm_pcie_dev_t *pcie_dev, { struct msm_pcie_drv_info *drv_info; int ret; + u32 phy_manage_pll = 0; drv_info = devm_kzalloc(&pcie_dev->pdev->dev, sizeof(*drv_info), GFP_KERNEL); @@ -5589,6 +5667,15 @@ static int msm_pcie_setup_drv(struct msm_pcie_dev_t *pcie_dev, drv_info->dev_id = pcie_dev->rc_idx; + ret = of_property_read_u32(of_node, "qcom,phy-manage-pll", + &phy_manage_pll); + if (!ret && phy_manage_pll) { + ret = msm_pcie_setup_drv_manage_pll(pcie_dev, of_node, + drv_info); + if (ret) + return ret; + } + msm_pcie_setup_drv_msg(&drv_info->drv_enable, drv_info->dev_id, MSM_PCIE_DRV_CMD_ENABLE); @@ -6954,6 +7041,9 @@ static int msm_pcie_drv_resume(struct msm_pcie_dev_t *pcie_dev) clk_prepare_enable(clk_info->hdl); if (clkreq_override_en) { + if (drv_info->manage_pll_power_on) + drv_info->manage_pll_power_on(pcie_dev, drv_info); + /* remove CLKREQ override */ msm_pcie_write_reg_field(pcie_dev->parf, PCIE20_PARF_CLKREQ_OVERRIDE,