diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 06b5648111a3..77880f6491d1 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -59,10 +59,13 @@ #define PCIE_GEN3_EQ_FMDC_T_MIN_PHASE23_MASK (0x1f) #define PCIE_GEN3_MISC_CONTROL (0x08bc) +#define DBI_RO_WR_EN (BIT(0)) #define PCIE_PL_16GT_CAP (0x168) #define PCIE20_PARF_SYS_CTRL (0x00) +#define CORE_CLK_2AUX_CLK_MUX_DIS (BIT(3)) + #define PCIE20_PARF_PM_CTRL (0x20) #define PCIE20_PARF_PM_STTS (0x24) #define PCIE20_PARF_PHY_CTRL (0x40) @@ -103,6 +106,10 @@ #define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10) #define PCIE_CAP_DLL_ACTIVE BIT(29) +#define PCIE20_CAP_LINKCAP (PCIE20_CAP + 0xc) +#define PCIE_CAP_ASPM_L0S (BIT(10)) +#define PCIE_CAP_ASPM_L1 (BIT(11)) + #define PCIE20_COMMAND_STATUS (0x04) #define PCIE20_HEADER_TYPE (0x0c) #define PCIE20_BRIDGE_CTRL (0x3c) @@ -793,6 +800,8 @@ struct msm_pcie_dev_t { bool l1_2_aspm_supported; uint32_t l1_2_th_scale; uint32_t l1_2_th_value; + uint32_t t_pwr_on_val; + uint32_t t_pwr_on_scale; bool common_clk_en; bool clk_power_manage_en; bool aux_clk_sync; @@ -1287,7 +1296,7 @@ static void msm_pcie_config_l1ss_enable_all(struct msm_pcie_dev_t *dev); static void msm_pcie_check_l1ss_support_all(struct msm_pcie_dev_t *dev); -static void msm_pcie_config_link_pm(struct msm_pcie_dev_t *dev, bool enable); +static void msm_pcie_config_aspm(struct msm_pcie_dev_t *dev); static u32 msm_pcie_reg_copy(struct msm_pcie_dev_t *pcie_dev, u8 *buf, u32 size, void __iomem *base, @@ -1665,6 +1674,8 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev) dev->l1_2_th_scale); PCIE_DBG_FS(dev, "l1_2_th_value is %d\n", dev->l1_2_th_value); + PCIE_DBG_FS(dev, "t_pwr_on_scale is %u\n", dev->t_pwr_on_scale); + PCIE_DBG_FS(dev, "t_pwr_on_val is %u\n", dev->t_pwr_on_val); PCIE_DBG_FS(dev, "common_clk_en is %d\n", dev->common_clk_en); PCIE_DBG_FS(dev, "clk_power_manage_en is %d\n", @@ -3653,6 +3664,126 @@ static void msm_pcie_config_controller_phy(struct msm_pcie_dev_t *pcie_dev) } } +static u32 msm_pcie_find_ext_capability(struct msm_pcie_dev_t *pcie_dev, + u32 cap_id) +{ + int total; + u32 header; + int pos = PCI_CFG_SPACE_SIZE; + + total = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; + + header = readl_relaxed(pcie_dev->dm_core + PCIE_EXT_CAP_OFFSET); + if (!header) + return 0; + + while (total-- > 0) { + if (PCI_EXT_CAP_ID(header) == cap_id && pos != 0) + return pos; + + pos = PCI_EXT_CAP_NEXT(header); + if (pos < PCI_CFG_SPACE_SIZE) + break; + + header = readl_relaxed(pcie_dev->dm_core + pos); + } + + return 0; +} + +static void msm_pcie_config_aspm(struct msm_pcie_dev_t *pcie_dev) +{ + u32 reg; + u32 l1ss_cap_id_offset, l1ss_cap_offset; + + /* enable write access to RO register */ + msm_pcie_write_mask(pcie_dev->dm_core + PCIE_GEN3_MISC_CONTROL, 0, + DBI_RO_WR_EN); + + reg = readl_relaxed(pcie_dev->dm_core + PCIE20_CAP_LINKCAP); + reg >>= 10; + + if (pcie_dev->l0s_supported) { + if (!(reg & PCI_EXP_LNKCTL_ASPM_L0S)) { + PCIE_ERR(pcie_dev, "PCIe: RC%d: L0s not supported\n", + pcie_dev->rc_idx); + pcie_dev->l0s_supported = false; + } + } else { + if (reg & PCI_EXP_LNKCTL_ASPM_L0S) + msm_pcie_write_mask(pcie_dev->dm_core + PCIE20_CAP_LINKCAP, + PCIE_CAP_ASPM_L0S, 0); + } + + if (pcie_dev->l1_supported) { + if (!(reg & PCI_EXP_LNKCTL_ASPM_L1)) { + PCIE_ERR(pcie_dev, "PCIe: RC%d: L1 not supported\n", + pcie_dev->rc_idx); + pcie_dev->l1_supported = false; + goto done; + } + } else { + if (reg & PCI_EXP_LNKCTL_ASPM_L1) + msm_pcie_write_mask( + pcie_dev->dm_core + PCIE20_CAP_LINKCAP, + PCIE_CAP_ASPM_L1, 0); + } + + l1ss_cap_id_offset = msm_pcie_find_ext_capability(pcie_dev, + PCI_EXT_CAP_ID_L1SS); + if (!l1ss_cap_id_offset) { + PCIE_DBG(pcie_dev, + "PCIe: RC%d: L1ss capability register not found\n", + pcie_dev->rc_idx); + pcie_dev->l1ss_supported = false; + goto done; + } + + l1ss_cap_offset = l1ss_cap_id_offset + PCI_L1SS_CAP; + + reg = readl_relaxed(pcie_dev->dm_core + l1ss_cap_offset); + if (pcie_dev->l1ss_supported) { + if (!(reg & PCI_L1SS_CAP_PCIPM_L1_2) && + !(reg & PCI_L1SS_CAP_PCIPM_L1_1) && + !(reg & PCI_L1SS_CAP_ASPM_L1_2) && + !(reg & PCI_L1SS_CAP_ASPM_L1_1)) { + PCIE_ERR(pcie_dev, "PCIe: RC%d: L1ss not supported\n", + pcie_dev->rc_idx); + pcie_dev->l1ss_supported = false; + goto done; + } + + if (pcie_dev->t_pwr_on_scale <= 0x3 && + pcie_dev->t_pwr_on_val <= 0x1f) { + reg |= (pcie_dev->t_pwr_on_scale << 16) | + pcie_dev->t_pwr_on_val << 19; + writel_relaxed(reg, + pcie_dev->dm_core + l1ss_cap_offset); + } + + /* Enable AUX clk and Core clk async for L1SS */ + if (!pcie_dev->aux_clk_sync) + msm_pcie_write_mask(pcie_dev->parf + PCIE20_PARF_SYS_CTRL, + CORE_CLK_2AUX_CLK_MUX_DIS, 0); + } else { + msm_pcie_write_mask(pcie_dev->dm_core + l1ss_cap_offset, + PCI_L1SS_CTL1_PCIPM_L1_1 | + PCI_L1SS_CTL1_PCIPM_L1_2 | + PCI_L1SS_CTL1_ASPM_L1_1 | + PCI_L1SS_CTL1_ASPM_L1_2, 0); + + /* Disable AUX clk and Core Clock async - L1SS disabled */ + if (!pcie_dev->aux_clk_sync) + msm_pcie_write_mask(pcie_dev->parf + PCIE20_PARF_SYS_CTRL, 0, + CORE_CLK_2AUX_CLK_MUX_DIS); + } + +done: + /* disable write access to RO register */ + msm_pcie_write_mask(pcie_dev->dm_core + PCIE_GEN3_MISC_CONTROL, + DBI_RO_WR_EN, 0); +} + static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev) { PCIE_DBG(dev, "RC%d\n", dev->rc_idx); @@ -3705,6 +3836,8 @@ static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev) PCIE_DBG(dev, "RC's PCIE20_CAP_DEVCTRLSTATUS:0x%x\n", readl_relaxed(dev->dm_core + PCIE20_CAP_DEVCTRLSTATUS)); } + + msm_pcie_config_aspm(dev); } static int msm_pcie_get_clk(struct msm_pcie_dev_t *pcie_dev) @@ -4611,6 +4744,9 @@ static int msm_pcie_enable(struct msm_pcie_dev_t *dev) ep_up_timeout = jiffies + usecs_to_jiffies(EP_UP_TIMEOUT_US); + msm_pcie_config_sid(dev); + msm_pcie_config_controller(dev); + ret = msm_pcie_link_train(dev); if (ret) goto link_fail; @@ -4630,9 +4766,6 @@ static int msm_pcie_enable(struct msm_pcie_dev_t *dev) msleep(dev->switch_latency); } - msm_pcie_config_sid(dev); - msm_pcie_config_controller(dev); - /* check endpoint configuration space is accessible */ while (time_before(jiffies, ep_up_timeout)) { if (readl_relaxed(dev->conf) != PCIE_LINK_DOWN) @@ -4655,10 +4788,8 @@ static int msm_pcie_enable(struct msm_pcie_dev_t *dev) goto link_fail; } - if (dev->enumerated) { + if (dev->enumerated) msm_msi_config(dev_get_msi_domain(&dev->dev->dev)); - msm_pcie_config_link_pm(dev, true); - } /* bring eps out of reset */ if (dev->i2c_ctrl.client && dev->i2c_ctrl.client_i2c_reset) @@ -4981,8 +5112,6 @@ int msm_pcie_enumerate(u32 rc_idx) pci_walk_bus(dev->dev->bus, msm_pcie_config_device_table, dev); - msm_pcie_check_l1ss_support_all(dev); - msm_pcie_config_link_pm(dev, true); out: mutex_unlock(&dev->enumerate_lock); @@ -5546,64 +5675,6 @@ static int msm_pcie_check_l1ss_support(struct pci_dev *pdev, void *dev) return 0; } -static int msm_pcie_config_common_clock_enable(struct pci_dev *pdev, - void *dev) -{ - struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; - - PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x\n", - pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn)); - - msm_pcie_config_clear_set_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCTL, - 0, PCI_EXP_LNKCTL_CCC); - - return 0; -} - -static void msm_pcie_config_common_clock_enable_all(struct msm_pcie_dev_t *dev) -{ - if (dev->common_clk_en) - pci_walk_bus(dev->dev->bus, - msm_pcie_config_common_clock_enable, dev); -} - -static int msm_pcie_config_clock_power_management_enable(struct pci_dev *pdev, - void *dev) -{ - struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev; - u32 val; - - /* enable only for upstream ports */ - if (pci_is_root_bus(pdev->bus)) - return 0; - - PCIE_DBG(pcie_dev, "PCIe: RC%d: PCI device %02x:%02x.%01x\n", - pcie_dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn)); - - pci_read_config_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCAP, &val); - if (val & PCI_EXP_LNKCAP_CLKPM) - msm_pcie_config_clear_set_dword(pdev, - pdev->pcie_cap + PCI_EXP_LNKCTL, 0, - PCI_EXP_LNKCTL_CLKREQ_EN); - else - PCIE_DBG(pcie_dev, - "PCIe: RC%d: PCI device %02x:%02x.%01x does not support clock power management\n", - pcie_dev->rc_idx, pdev->bus->number, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); - - return 0; -} - -static void msm_pcie_config_clock_power_management_enable_all( - struct msm_pcie_dev_t *dev) -{ - if (dev->clk_power_manage_en) - pci_walk_bus(dev->dev->bus, - msm_pcie_config_clock_power_management_enable, dev); -} - static void msm_pcie_config_l0s(struct msm_pcie_dev_t *dev, struct pci_dev *pdev, bool enable) { @@ -5854,23 +5925,6 @@ static void msm_pcie_config_l1ss_enable_all(struct msm_pcie_dev_t *dev) } } -static void msm_pcie_config_link_pm(struct msm_pcie_dev_t *dev, bool enable) -{ - struct pci_bus *bus = dev->dev->bus; - - if (enable) { - msm_pcie_config_common_clock_enable_all(dev); - msm_pcie_config_clock_power_management_enable_all(dev); - msm_pcie_config_l1ss_enable_all(dev); - msm_pcie_config_l1_enable_all(dev); - msm_pcie_config_l0s_enable_all(dev); - } else { - msm_pcie_config_l0s_disable_all(dev, bus); - msm_pcie_config_l1_disable_all(dev, bus); - msm_pcie_config_l1ss_disable_all(dev, bus); - } -} - 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); @@ -6055,6 +6109,14 @@ static int msm_pcie_probe(struct platform_device *pdev) pcie_dev->rc_idx, pcie_dev->l1_2_th_scale, pcie_dev->l1_2_th_value); + of_property_read_u32(of_node, "qcom,tpwr-on-scale", + &pcie_dev->t_pwr_on_scale); + of_property_read_u32(of_node, "qcom,tpwr-on-value", + &pcie_dev->t_pwr_on_val); + PCIE_DBG(pcie_dev, "PCIe: RC%d: t_power on scale: %u value: %u.\n", + pcie_dev->rc_idx, pcie_dev->t_pwr_on_scale, + pcie_dev->t_pwr_on_val); + pcie_dev->common_clk_en = of_property_read_bool(of_node, "qcom,common-clk-en"); PCIE_DBG(pcie_dev, "Common clock is %s enabled.\n",