Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c637ad32 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: pcie: correct the enable/disable order for PCIe link ASPM"

parents cd2e8b7e a6f0f083
Loading
Loading
Loading
Loading
+347 −266
Original line number Diff line number Diff line
@@ -579,6 +579,10 @@ struct msm_pcie_dev_t {
	bool				l0s_supported;
	bool				l1_supported;
	bool				 l1ss_supported;
	bool				l1_1_pcipm_supported;
	bool				l1_2_pcipm_supported;
	bool				l1_1_aspm_supported;
	bool				l1_2_aspm_supported;
	bool				common_clk_en;
	bool				clk_power_manage_en;
	bool				 aux_clk_sync;
@@ -881,15 +885,19 @@ static const struct msm_pcie_irq_info_t msm_pcie_msi_info[MSM_PCIE_MAX_MSI] = {
};

static void msm_pcie_config_sid(struct msm_pcie_dev_t *dev);
static int msm_pcie_config_device(struct pci_dev *dev, void *pdev);
static int msm_pcie_config_l0s_disable(struct pci_dev *dev, void *pdev);
static int msm_pcie_config_l0s_enable(struct pci_dev *dev, void *pdev);
static int msm_pcie_config_l1_disable(struct pci_dev *dev, void *pdev);
static int msm_pcie_config_l1_enable(struct pci_dev *dev, void *pdev);
static int msm_pcie_config_l1ss_disable(struct pci_dev *dev, void *pdev);
static int msm_pcie_config_l1ss_enable(struct pci_dev *dev, void *pdev);
static void msm_pcie_config_link_pm_rc(struct msm_pcie_dev_t *dev,
				struct pci_dev *pdev, bool enable);
static void msm_pcie_config_l0s_disable_all(struct msm_pcie_dev_t *dev,
				struct pci_bus *bus);
static void msm_pcie_config_l1_disable_all(struct msm_pcie_dev_t *dev,
				struct pci_bus *bus);
static void msm_pcie_config_l1ss_disable_all(struct msm_pcie_dev_t *dev,
				struct pci_bus *bus);
static void msm_pcie_config_l0s_enable_all(struct msm_pcie_dev_t *dev);
static void msm_pcie_config_l1_enable_all(struct msm_pcie_dev_t *dev);
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);

#ifdef CONFIG_ARM
static inline void msm_pcie_fixup_irqs(struct msm_pcie_dev_t *dev)
@@ -1199,6 +1207,14 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev)
		dev->l1_supported ? "" : "not");
	PCIE_DBG_FS(dev, "l1ss_supported is %s supported\n",
		dev->l1ss_supported ? "" : "not");
	PCIE_DBG_FS(dev, "l1_1_pcipm_supported is %s supported\n",
		dev->l1_1_pcipm_supported ? "" : "not");
	PCIE_DBG_FS(dev, "l1_2_pcipm_supported is %s supported\n",
		dev->l1_2_pcipm_supported ? "" : "not");
	PCIE_DBG_FS(dev, "l1_1_aspm_supported is %s supported\n",
		dev->l1_1_aspm_supported ? "" : "not");
	PCIE_DBG_FS(dev, "l1_2_aspm_supported is %s supported\n",
		dev->l1_2_aspm_supported ? "" : "not");
	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",
@@ -1397,46 +1413,22 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev,
	case MSM_PCIE_DISABLE_L0S:
		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L0s\n\n",
			dev->rc_idx);
		if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
			struct pci_bus *bus, *c_bus;
			struct list_head *children = &dev->dev->bus->children;

			msm_pcie_config_l0s_disable(dev->dev, dev);

			list_for_each_entry_safe(bus, c_bus, children, node)
				pci_walk_bus(bus,
					&msm_pcie_config_l0s_disable, dev);
		}
		if (dev->link_status == MSM_PCIE_LINK_ENABLED)
			msm_pcie_config_l0s_disable_all(dev, dev->dev->bus);
		dev->l0s_supported = false;
		break;
	case MSM_PCIE_ENABLE_L0S:
		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L0s\n\n",
			dev->rc_idx);
		dev->l0s_supported = true;
		if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
			struct pci_bus *bus, *c_bus;
			struct list_head *children = &dev->dev->bus->children;

			list_for_each_entry_safe(bus, c_bus, children, node)
				pci_walk_bus(bus,
					&msm_pcie_config_l0s_enable, dev);

			msm_pcie_config_l0s_enable(dev->dev, dev);
		}
		if (dev->link_status == MSM_PCIE_LINK_ENABLED)
			msm_pcie_config_l0s_enable_all(dev);
		break;
	case MSM_PCIE_DISABLE_L1:
		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L1\n\n",
			dev->rc_idx);
		if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
			struct pci_bus *bus, *c_bus;
			struct list_head *children = &dev->dev->bus->children;

			msm_pcie_config_l1_disable(dev->dev, dev);

			list_for_each_entry_safe(bus, c_bus, children, node)
				pci_walk_bus(bus,
					&msm_pcie_config_l1_disable, dev);
		}
		if (dev->link_status == MSM_PCIE_LINK_ENABLED)
			msm_pcie_config_l1_disable_all(dev, dev->dev->bus);
		dev->l1_supported = false;
		break;
	case MSM_PCIE_ENABLE_L1:
@@ -1444,48 +1436,35 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev,
			dev->rc_idx);
		dev->l1_supported = true;
		if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
			struct pci_bus *bus, *c_bus;
			struct list_head *children = &dev->dev->bus->children;

			list_for_each_entry_safe(bus, c_bus, children, node)
				pci_walk_bus(bus,
					&msm_pcie_config_l1_enable, dev);

			/* enable l1 mode, clear bit 5 (REQ_NOT_ENTR_L1) */
			msm_pcie_write_mask(dev->parf +
				PCIE20_PARF_PM_CTRL, BIT(5), 0);

			msm_pcie_config_l1_enable(dev->dev, dev);
			msm_pcie_config_l1_enable_all(dev);
		}
		break;
	case MSM_PCIE_DISABLE_L1SS:
		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: disable L1ss\n\n",
			dev->rc_idx);
		if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
			struct pci_bus *bus, *c_bus;
			struct list_head *children = &dev->dev->bus->children;

			msm_pcie_config_l1ss_disable(dev->dev, dev);

			list_for_each_entry_safe(bus, c_bus, children, node)
				pci_walk_bus(bus,
					&msm_pcie_config_l1ss_disable, dev);
		}
		if (dev->link_status == MSM_PCIE_LINK_ENABLED)
			msm_pcie_config_l1ss_disable_all(dev, dev->dev->bus);
		dev->l1ss_supported = false;
		dev->l1_1_pcipm_supported = false;
		dev->l1_2_pcipm_supported = false;
		dev->l1_1_aspm_supported = false;
		dev->l1_2_aspm_supported = false;
		break;
	case MSM_PCIE_ENABLE_L1SS:
		PCIE_DBG_FS(dev, "\n\nPCIe: RC%d: enable L1ss\n\n",
			dev->rc_idx);
		dev->l1ss_supported = true;
		dev->l1_1_pcipm_supported = true;
		dev->l1_2_pcipm_supported = true;
		dev->l1_1_aspm_supported = true;
		dev->l1_2_aspm_supported = true;
		if (dev->link_status == MSM_PCIE_LINK_ENABLED) {
			struct pci_bus *bus, *c_bus;
			struct list_head *children = &dev->dev->bus->children;

			list_for_each_entry_safe(bus, c_bus, children, node)
				pci_walk_bus(bus,
					&msm_pcie_config_l1ss_enable, dev);

			msm_pcie_config_l1ss_enable(dev->dev, dev);
			msm_pcie_check_l1ss_support_all(dev);
			msm_pcie_config_l1ss_enable_all(dev);
		}
		break;
	case MSM_PCIE_ENUMERATION:
@@ -4087,10 +4066,8 @@ static int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options)
	if (!dev->msi_gicm_addr)
		msm_pcie_config_msi_controller(dev);

	if (dev->enumerated) {
		pci_walk_bus(dev->dev->bus, &msm_pcie_config_device, dev);
		msm_pcie_config_link_pm_rc(dev, dev->dev, true);
	}
	if (dev->enumerated)
		msm_pcie_config_link_pm(dev, true);

	goto out;

@@ -4516,7 +4493,8 @@ int msm_pcie_enumerate(u32 rc_idx)
				goto out;
			}

			msm_pcie_config_link_pm_rc(dev, dev->dev, true);
			msm_pcie_check_l1ss_support_all(dev);
			msm_pcie_config_link_pm(dev, true);
		} else {
			PCIE_ERR(dev, "PCIe: failed to enable RC%d.\n",
				dev->rc_idx);
@@ -5441,38 +5419,219 @@ static void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev)
		disable_irq(dev->wake_n);
}

static bool msm_pcie_check_l0s_support(struct pci_dev *pdev,
					struct msm_pcie_dev_t *pcie_dev)
{
	struct pci_dev *parent = pdev->bus->self;
	u32 val;

	/* check parent supports L0s */
	if (parent) {
		u32 val2;

		pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCAP,
					&val);
		pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCTL,
					&val2);
		val = (val & BIT(10)) && (val2 & PCI_EXP_LNKCTL_ASPM_L0S);
		if (!val) {
			PCIE_DBG(pcie_dev,
				"PCIe: RC%d: Parent PCI device %02x:%02x.%01x does not support L0s\n",
				pcie_dev->rc_idx, parent->bus->number,
				PCI_SLOT(parent->devfn),
				PCI_FUNC(parent->devfn));
			return false;
		}
	}

	pci_read_config_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCAP, &val);
	if (!(val & BIT(10))) {
		PCIE_DBG(pcie_dev,
			"PCIe: RC%d: PCI device %02x:%02x.%01x does not support L0s\n",
			pcie_dev->rc_idx, pdev->bus->number,
			PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
		return false;
	}

	return true;
}

static bool msm_pcie_check_l1_support(struct pci_dev *pdev,
					struct msm_pcie_dev_t *pcie_dev)
{
	struct pci_dev *parent = pdev->bus->self;
	u32 val;

	/* check parent supports L1 */
	if (parent) {
		u32 val2;

		pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCAP,
					&val);
		pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCTL,
					&val2);
		val = (val & BIT(11)) && (val2 & PCI_EXP_LNKCTL_ASPM_L1);
		if (!val) {
			PCIE_DBG(pcie_dev,
				"PCIe: RC%d: Parent PCI device %02x:%02x.%01x does not support L1\n",
				pcie_dev->rc_idx, parent->bus->number,
				PCI_SLOT(parent->devfn),
				PCI_FUNC(parent->devfn));
			return false;
		}
	}

	pci_read_config_dword(pdev, pdev->pcie_cap + PCI_EXP_LNKCAP, &val);
	if (!(val & BIT(11))) {
		PCIE_DBG(pcie_dev,
			"PCIe: RC%d: PCI device %02x:%02x.%01x does not support L1\n",
			pcie_dev->rc_idx, pdev->bus->number,
			PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
		return false;
	}

	return true;
}

static int msm_pcie_check_l1ss_support(struct pci_dev *pdev, void *dev)
{
	struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
	u32 val;
	u32 l1ss_cap_id_offset, l1ss_cap_offset, l1ss_ctl1_offset;

	if (!pcie_dev->l1ss_supported)
		return -ENXIO;

	l1ss_cap_id_offset = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
	if (!l1ss_cap_id_offset) {
		PCIE_DBG(pcie_dev,
			"PCIe: RC%d: PCI device %02x:%02x.%01x could not find L1ss capability register\n",
			pcie_dev->rc_idx, pdev->bus->number,
			PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
		pcie_dev->l1ss_supported = 0;
		return -ENXIO;
	}

	l1ss_cap_offset = l1ss_cap_id_offset + PCI_L1SS_CAP;
	l1ss_ctl1_offset = l1ss_cap_id_offset + PCI_L1SS_CTL1;

	pci_read_config_dword(pdev, l1ss_cap_offset, &val);
	pcie_dev->l1_1_pcipm_supported &= !!(val & (PCI_L1SS_CAP_PCIPM_L1_1));
	pcie_dev->l1_2_pcipm_supported &= !!(val & (PCI_L1SS_CAP_PCIPM_L1_2));
	pcie_dev->l1_1_aspm_supported &= !!(val & (PCI_L1SS_CAP_ASPM_L1_1));
	pcie_dev->l1_2_aspm_supported &= !!(val & (PCI_L1SS_CAP_ASPM_L1_2));
	if (!pcie_dev->l1_1_pcipm_supported &&
		!pcie_dev->l1_2_pcipm_supported &&
		!pcie_dev->l1_1_aspm_supported &&
		!pcie_dev->l1_2_aspm_supported) {
		PCIE_DBG(pcie_dev,
			"PCIe: RC%d: PCI device %02x:%02x.%01x does not support any L1ss\n",
			pcie_dev->rc_idx, pdev->bus->number,
			PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
		pcie_dev->l1ss_supported = 0;
		return -ENXIO;
	}

	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)
{
	u32 val;
	u32 lnkcap_offset = pdev->pcie_cap + PCI_EXP_LNKCAP;
	u32 lnkctl_offset = pdev->pcie_cap + PCI_EXP_LNKCTL;
	int ret;

	pci_read_config_dword(pdev, lnkcap_offset, &val);
	if (!(val & BIT(10))) {
		PCIE_DBG(dev,
			"PCIe: RC%d: PCI device does not support L0s\n",
			dev->rc_idx);
	PCIE_DBG(dev, "PCIe: RC%d: PCI device %02x:%02x.%01x %s\n",
		dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn),
		PCI_FUNC(pdev->devfn), enable ? "enable" : "disable");

	if (enable) {
		ret = msm_pcie_check_l0s_support(pdev, dev);
		if (!ret)
			return;
	}

	if (enable)
		msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, 0,
			PCI_EXP_LNKCTL_ASPM_L0S);
	else
	} else {
		msm_pcie_config_clear_set_dword(pdev, lnkctl_offset,
			PCI_EXP_LNKCTL_ASPM_L0S, 0);

	pci_read_config_dword(pdev, lnkctl_offset, &val);
	PCIE_DBG2(dev, "PCIe: RC%d: LINKCTRLSTATUS:0x%x\n", dev->rc_idx, val);
	}
}

static int msm_pcie_config_l0s_disable(struct pci_dev *pdev, void *dev)
static void msm_pcie_config_l0s_disable_all(struct msm_pcie_dev_t *dev,
				struct pci_bus *bus)
{
	struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
	struct pci_dev *pdev;

	msm_pcie_config_l0s(pcie_dev, pdev, false);
	return 0;
	if (!dev->l0s_supported)
		return;

	list_for_each_entry(pdev, &bus->devices, bus_list) {
		struct pci_bus *child;

		child  = pdev->subordinate;
		if (child)
			msm_pcie_config_l0s_disable_all(dev, child);
		msm_pcie_config_l0s(dev, pdev, false);
	}
}

static int msm_pcie_config_l0s_enable(struct pci_dev *pdev, void *dev)
@@ -5483,38 +5642,51 @@ static int msm_pcie_config_l0s_enable(struct pci_dev *pdev, void *dev)
	return 0;
}

static void msm_pcie_config_l0s_enable_all(struct msm_pcie_dev_t *dev)
{
	if (dev->l0s_supported)
		pci_walk_bus(dev->dev->bus, msm_pcie_config_l0s_enable, dev);
}

static void msm_pcie_config_l1(struct msm_pcie_dev_t *dev,
				struct pci_dev *pdev, bool enable)
{
	u32 val;
	u32 lnkcap_offset = pdev->pcie_cap + PCI_EXP_LNKCAP;
	u32 lnkctl_offset = pdev->pcie_cap + PCI_EXP_LNKCTL;
	int ret;

	pci_read_config_dword(pdev, lnkcap_offset, &val);
	if (!(val & BIT(11))) {
		PCIE_DBG(dev,
			"PCIe: RC%d: PCI device does not support L1\n",
			dev->rc_idx);
	PCIE_DBG(dev, "PCIe: RC%d: PCI device %02x:%02x.%01x %s\n",
		dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn),
		PCI_FUNC(pdev->devfn), enable ? "enable" : "disable");

	if (enable) {
		ret = msm_pcie_check_l1_support(pdev, dev);
		if (!ret)
			return;
	}

	if (enable)
		msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, 0,
			PCI_EXP_LNKCTL_ASPM_L1);
	else
	} else {
		msm_pcie_config_clear_set_dword(pdev, lnkctl_offset,
			PCI_EXP_LNKCTL_ASPM_L1, 0);

	pci_read_config_dword(pdev, lnkctl_offset, &val);
	PCIE_DBG2(dev, "PCIe: RC%d: LINKCTRLSTATUS:0x%x\n", dev->rc_idx, val);
	}
}

static int msm_pcie_config_l1_disable(struct pci_dev *pdev, void *dev)
static void msm_pcie_config_l1_disable_all(struct msm_pcie_dev_t *dev,
				struct pci_bus *bus)
{
	struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;
	struct pci_dev *pdev;

	msm_pcie_config_l1(pcie_dev, pdev, false);
	return 0;
	if (!dev->l1_supported)
		return;

	list_for_each_entry(pdev, &bus->devices, bus_list) {
		struct pci_bus *child;

		child  = pdev->subordinate;
		if (child)
			msm_pcie_config_l1_disable_all(dev, child);
		msm_pcie_config_l1(dev, pdev, false);
	}
}

static int msm_pcie_config_l1_enable(struct pci_dev *pdev, void *dev)
@@ -5525,39 +5697,34 @@ static int msm_pcie_config_l1_enable(struct pci_dev *pdev, void *dev)
	return 0;
}

static void msm_pcie_config_l1_enable_all(struct msm_pcie_dev_t *dev)
{
	if (dev->l1_supported)
		pci_walk_bus(dev->dev->bus, msm_pcie_config_l1_enable, dev);
}

static void msm_pcie_config_l1ss(struct msm_pcie_dev_t *dev,
				struct pci_dev *pdev, bool enable)
{
	bool l1_1_pcipm_support, l1_2_pcipm_support;
	bool l1_1_aspm_support, l1_2_aspm_support;
	u32 val, val2;
	u32 l1ss_cap_id_offset, l1ss_cap_offset, l1ss_ctl1_offset;
	u32 l1ss_cap_id_offset, l1ss_ctl1_offset;
	u32 devctl2_offset = pdev->pcie_cap + PCI_EXP_DEVCTL2;

	PCIE_DBG(dev, "PCIe: RC%d: PCI device %02x:%02x.%01x %s\n",
		dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn),
		PCI_FUNC(pdev->devfn), enable ? "enable" : "disable");

	l1ss_cap_id_offset = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
	if (!l1ss_cap_id_offset) {
		PCIE_DBG(dev,
			"PCIe: RC%d could not find L1ss capability register for device\n",
			dev->rc_idx);
			"PCIe: RC%d: PCI device %02x:%02x.%01x could not find L1ss capability register\n",
			dev->rc_idx, pdev->bus->number, PCI_SLOT(pdev->devfn),
			PCI_FUNC(pdev->devfn));
		return;
	}

	l1ss_cap_offset = l1ss_cap_id_offset + PCI_L1SS_CAP;
	l1ss_ctl1_offset = l1ss_cap_id_offset + PCI_L1SS_CTL1;

	pci_read_config_dword(pdev, l1ss_cap_offset, &val);
	l1_1_pcipm_support = !!(val & (PCI_L1SS_CAP_PCIPM_L1_1));
	l1_2_pcipm_support = !!(val & (PCI_L1SS_CAP_PCIPM_L1_2));
	l1_1_aspm_support = !!(val & (PCI_L1SS_CAP_ASPM_L1_1));
	l1_2_aspm_support = !!(val & (PCI_L1SS_CAP_ASPM_L1_2));
	if (!l1_1_pcipm_support && !l1_2_pcipm_support &&
		!l1_1_aspm_support && !l1_2_aspm_support) {
		PCIE_DBG(dev,
			"PCIe: RC%d: PCI device does not support any L1ss\n",
			dev->rc_idx);
		return;
	}

	/* Enable the AUX Clock and the Core Clk to be synchronous for L1ss */
	if (pci_is_root_bus(pdev->bus) && !dev->aux_clk_sync) {
		if (enable)
@@ -5571,19 +5738,23 @@ static void msm_pcie_config_l1ss(struct msm_pcie_dev_t *dev,
	if (enable) {
		msm_pcie_config_clear_set_dword(pdev, devctl2_offset, 0,
			PCI_EXP_DEVCTL2_LTR_EN);

		msm_pcie_config_clear_set_dword(pdev, l1ss_ctl1_offset, 0,
			(l1_1_pcipm_support ? PCI_L1SS_CTL1_PCIPM_L1_1 : 0) |
			(l1_2_pcipm_support ? PCI_L1SS_CTL1_PCIPM_L1_2 : 0) |
			(l1_1_aspm_support ? PCI_L1SS_CTL1_ASPM_L1_1 : 0) |
			(l1_2_aspm_support ? PCI_L1SS_CTL1_ASPM_L1_2 : 0));
			(dev->l1_1_pcipm_supported ?
				PCI_L1SS_CTL1_PCIPM_L1_1 : 0) |
			(dev->l1_2_pcipm_supported ?
				PCI_L1SS_CTL1_PCIPM_L1_2 : 0) |
			(dev->l1_1_aspm_supported ?
				PCI_L1SS_CTL1_ASPM_L1_1 : 0) |
			(dev->l1_2_aspm_supported ?
				PCI_L1SS_CTL1_ASPM_L1_2 : 0));
	} else {
		msm_pcie_config_clear_set_dword(pdev, devctl2_offset,
			PCI_EXP_DEVCTL2_LTR_EN, 0);

		msm_pcie_config_clear_set_dword(pdev, l1ss_ctl1_offset,
			(l1_1_pcipm_support ? PCI_L1SS_CTL1_PCIPM_L1_1 : 0) |
			(l1_2_pcipm_support ? PCI_L1SS_CTL1_PCIPM_L1_2 : 0) |
			(l1_1_aspm_support ? PCI_L1SS_CTL1_ASPM_L1_1 : 0) |
			(l1_2_aspm_support ? PCI_L1SS_CTL1_ASPM_L1_2 : 0), 0);
			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);
	}

	pci_read_config_dword(pdev, l1ss_ctl1_offset, &val);
@@ -5602,157 +5773,58 @@ static int msm_pcie_config_l1ss_disable(struct pci_dev *pdev, void *dev)
	return 0;
}

static int msm_pcie_config_l1ss_enable(struct pci_dev *pdev, void *dev)
{
	struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;

	msm_pcie_config_l1ss(pcie_dev, pdev, true);
	return 0;
}

static void msm_pcie_config_clock_power_management(struct msm_pcie_dev_t *dev,
				struct pci_dev *pdev)
{
	u32 val;
	u32 lnkcap_offset = pdev->pcie_cap + PCI_EXP_LNKCAP;
	u32 lnkctl_offset = pdev->pcie_cap + PCI_EXP_LNKCTL;

	if (pci_is_root_bus(pdev->bus))
		return;

	pci_read_config_dword(pdev, lnkcap_offset, &val);
	if (val & PCI_EXP_LNKCAP_CLKPM)
		msm_pcie_config_clear_set_dword(pdev, lnkctl_offset, 0,
			PCI_EXP_LNKCTL_CLKREQ_EN);
	else
		PCIE_DBG(dev,
			"PCIe: RC%d: PCI device does not support clock power management\n",
			dev->rc_idx);
}

static void msm_pcie_config_link_pm(struct msm_pcie_dev_t *dev,
				struct pci_dev *pdev, bool enable)
{
	if (dev->common_clk_en)
		msm_pcie_config_clear_set_dword(pdev,
			pdev->pcie_cap + PCI_EXP_LNKCTL, 0,
			PCI_EXP_LNKCTL_CCC);

	if (dev->clk_power_manage_en)
		msm_pcie_config_clock_power_management(dev, pdev);
	if (dev->l0s_supported)
		msm_pcie_config_l0s(dev, pdev, enable);
	if (dev->l1ss_supported)
		msm_pcie_config_l1ss(dev, pdev, enable);
	if (dev->l1_supported)
		msm_pcie_config_l1(dev, pdev, enable);
}

static void msm_pcie_config_link_pm_rc(struct msm_pcie_dev_t *dev,
				struct pci_dev *pdev, bool enable)
static void msm_pcie_config_l1ss_disable_all(struct msm_pcie_dev_t *dev,
				struct pci_bus *bus)
{
	bool child_l0s_enable = 0, child_l1_enable = 0, child_l1ss_enable = 0;
	struct pci_dev *pdev;

	if (!pdev->subordinate) {
		PCIE_DBG(dev,
			"PCIe: RC%d: no device connected to root complex\n",
			dev->rc_idx);
	if (!dev->l1ss_supported)
		return;
	}

	if (dev->l0s_supported) {
		struct pci_dev *child_pdev, *c_pdev;

		list_for_each_entry_safe(child_pdev, c_pdev,
			&pdev->subordinate->devices, bus_list) {
			u32 val;
	list_for_each_entry(pdev, &bus->devices, bus_list) {
		struct pci_bus *child;

			pci_read_config_dword(child_pdev,
				child_pdev->pcie_cap + PCI_EXP_LNKCTL, &val);
			child_l0s_enable = !!(val & PCI_EXP_LNKCTL_ASPM_L0S);
			if (child_l0s_enable)
				break;
		child  = pdev->subordinate;
		if (child)
			msm_pcie_config_l1ss_disable_all(dev, child);
		msm_pcie_config_l1ss_disable(pdev, dev);
	}

		if (child_l0s_enable)
			msm_pcie_config_l0s(dev, pdev, enable);
		else
			dev->l0s_supported = false;
}

	if (dev->l1ss_supported) {
		struct pci_dev *child_pdev, *c_pdev;

		list_for_each_entry_safe(child_pdev, c_pdev,
			&pdev->subordinate->devices, bus_list) {
			u32 val;
			u32 l1ss_cap_id_offset =
				pci_find_ext_capability(child_pdev,
					PCI_EXT_CAP_ID_L1SS);

			if (!l1ss_cap_id_offset)
				continue;

			pci_read_config_dword(child_pdev,
				l1ss_cap_id_offset + PCI_L1SS_CTL1, &val);
			child_l1ss_enable = !!(val &
				(PCI_L1SS_CTL1_PCIPM_L1_1 |
				PCI_L1SS_CTL1_PCIPM_L1_2 |
				PCI_L1SS_CTL1_ASPM_L1_1 |
				PCI_L1SS_CTL1_ASPM_L1_2));
			if (child_l1ss_enable)
				break;
		}

		if (child_l1ss_enable)
			msm_pcie_config_l1ss(dev, pdev, enable);
		else
			dev->l1ss_supported = false;
	}

	if (dev->l1_supported) {
		struct pci_dev *child_pdev, *c_pdev;

		list_for_each_entry_safe(child_pdev, c_pdev,
			&pdev->subordinate->devices, bus_list) {
			u32 val;
static int msm_pcie_config_l1ss_enable(struct pci_dev *pdev, void *dev)
{
	struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)dev;

			pci_read_config_dword(child_pdev,
				child_pdev->pcie_cap + PCI_EXP_LNKCTL, &val);
			child_l1_enable = !!(val & PCI_EXP_LNKCTL_ASPM_L1);
			if (child_l1_enable)
				break;
	msm_pcie_config_l1ss(pcie_dev, pdev, true);
	return 0;
}

		if (child_l1_enable)
			msm_pcie_config_l1(dev, pdev, enable);
		else
			dev->l1_supported = false;
	}
static void msm_pcie_config_l1ss_enable_all(struct msm_pcie_dev_t *dev)
{
	if (dev->l1ss_supported)
		pci_walk_bus(dev->dev->bus, msm_pcie_config_l1ss_enable, dev);
}

static int msm_pcie_config_device(struct pci_dev *dev, void *pdev)
static void msm_pcie_config_link_pm(struct msm_pcie_dev_t *dev, bool enable)
{
	struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)pdev;
	u8 busnr = dev->bus->number;
	u8 slot = PCI_SLOT(dev->devfn);
	u8 func = PCI_FUNC(dev->devfn);

	PCIE_DBG(pcie_dev, "PCIe: RC%d: configure PCI device %02x:%02x.%01x\n",
		pcie_dev->rc_idx, busnr, slot, func);

	if (!pci_is_root_bus(dev->bus))
		msm_pcie_config_link_pm(pcie_dev, dev, true);
	struct pci_bus *bus = dev->dev->bus;

	return 0;
	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);
	}
}

/* Hook to setup PCI device during PCI framework scan */
int pcibios_add_device(struct pci_dev *dev)
static void msm_pcie_check_l1ss_support_all(struct msm_pcie_dev_t *dev)
{
	struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev->bus);

	return msm_pcie_config_device(dev, pcie_dev);
	pci_walk_bus(dev->dev->bus, msm_pcie_check_l1ss_support, dev);
}

static int msm_pcie_probe(struct platform_device *pdev)
@@ -5806,6 +5878,15 @@ static int msm_pcie_probe(struct platform_device *pdev)
			!msm_pcie_dev[rc_idx].l1ss_supported;
	PCIE_DBG(&msm_pcie_dev[rc_idx], "L1ss is %s supported.\n",
		msm_pcie_dev[rc_idx].l1ss_supported ? "" : "not");
	msm_pcie_dev[rc_idx].l1_1_aspm_supported =
		msm_pcie_dev[rc_idx].l1ss_supported;
	msm_pcie_dev[rc_idx].l1_2_aspm_supported =
		msm_pcie_dev[rc_idx].l1ss_supported;
	msm_pcie_dev[rc_idx].l1_1_pcipm_supported =
		msm_pcie_dev[rc_idx].l1ss_supported;
	msm_pcie_dev[rc_idx].l1_1_pcipm_supported =
		msm_pcie_dev[rc_idx].l1ss_supported;

	msm_pcie_dev[rc_idx].common_clk_en =
		of_property_read_bool((&pdev->dev)->of_node,
				"qcom,common-clk-en");