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

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

Merge "msm: pcie: disable/enable link LPM during bandwidth scaling"

parents 7a37de45 b709fb33
Loading
Loading
Loading
Loading
+178 −44
Original line number Diff line number Diff line
@@ -551,6 +551,12 @@ struct msm_pcie_irq_info_t {
	uint32_t num;
};

/* bandwidth info structure */
struct msm_pcie_bw_scale_info_t {
	u32 cx_vreg_min;
	u32 rate_change_freq;
};

/* phy info structure */
struct msm_pcie_phy_info_t {
	u32 offset;
@@ -662,12 +668,15 @@ struct msm_pcie_dev_t {

	struct msm_pcie_vreg_info_t *cx_vreg;
	struct msm_pcie_clk_info_t *rate_change_clk;
	struct msm_pcie_bw_scale_info_t *bw_scale;
	u32 bw_gen_max;

	bool cfg_access;
	spinlock_t cfg_lock;
	unsigned long irqsave_flags;
	struct mutex enumerate_lock;
	struct mutex setup_lock;
	struct mutex clk_lock;

	struct irq_domain *irq_domain;
	DECLARE_BITMAP(msi_irq_in_use, PCIE_MSI_NR_IRQS);
@@ -836,6 +845,7 @@ static struct pcie_drv_sta {
	struct msm_pcie_dev_t *msm_pcie_dev;
	struct rpmsg_device *rpdev;
	struct work_struct drv_connect; /* connect worker */
	u32 rate_change_vote; /* each bit corresponds to RC vote for 100MHz */
	struct mutex drv_lock;
} pcie_drv;

@@ -3171,6 +3181,12 @@ static int msm_pcie_clk_init(struct msm_pcie_dev_t *dev)
			msm_pcie_config_clock_mem(dev, info);

		if (info->freq) {
			if (!strcmp(info->name, "pcie_phy_refgen_clk")) {
				mutex_lock(&dev->clk_lock);
				pcie_drv.rate_change_vote |= BIT(dev->rc_idx);
				mutex_unlock(&dev->clk_lock);
			}

			rc = clk_set_rate(info->hdl, info->freq);
			if (rc) {
				PCIE_ERR(dev,
@@ -3251,6 +3267,17 @@ static void msm_pcie_clk_deinit(struct msm_pcie_dev_t *dev)
		if (dev->clk[i].hdl)
			clk_disable_unprepare(dev->clk[i].hdl);

	if (dev->rate_change_clk) {
		mutex_lock(&dev->clk_lock);

		pcie_drv.rate_change_vote &= ~BIT(dev->rc_idx);
		if (!pcie_drv.rate_change_vote)
			clk_set_rate(dev->rate_change_clk->hdl,
					RATE_CHANGE_19P2MHZ);

		mutex_unlock(&dev->clk_lock);
	}

	if (dev->bus_client) {
		PCIE_DBG(dev, "PCIe: removing bus vote for RC%d\n",
			dev->rc_idx);
@@ -3722,6 +3749,29 @@ static int msm_pcie_get_reset(struct msm_pcie_dev_t *pcie_dev)
	return 0;
}

static int msm_pcie_get_bw_scale(struct msm_pcie_dev_t *pcie_dev)
{
	int size = 0;
	struct platform_device *pdev = pcie_dev->pdev;

	of_get_property(pdev->dev.of_node, "qcom,bw-scale", &size);
	if (size) {
		pcie_dev->bw_scale = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
		if (!pcie_dev->bw_scale)
			return -ENOMEM;

		of_property_read_u32_array(pdev->dev.of_node, "qcom,bw-scale",
				(u32 *)pcie_dev->bw_scale, size / sizeof(u32));

		pcie_dev->bw_gen_max = size / sizeof(u32);
	} else {
		PCIE_DBG(pcie_dev, "RC%d: bandwidth scaling is not supported\n",
			pcie_dev->rc_idx);
	}

	return 0;
}

static int msm_pcie_get_phy(struct msm_pcie_dev_t *pcie_dev)
{
	int ret, size = 0;
@@ -3934,6 +3984,10 @@ static int msm_pcie_get_resources(struct msm_pcie_dev_t *dev,
	if (ret)
		return ret;

	ret = msm_pcie_get_bw_scale(dev);
	if (ret)
		return ret;

	ret = msm_pcie_get_phy(dev);
	if (ret)
		return ret;
@@ -3966,6 +4020,50 @@ static void msm_pcie_release_resources(struct msm_pcie_dev_t *dev)
	dev->rumi = NULL;
}

static void msm_pcie_scale_link_bandwidth(struct msm_pcie_dev_t *pcie_dev,
					u16 target_link_speed)
{
	struct msm_pcie_bw_scale_info_t *bw_scale;
	u32 index = target_link_speed - PCI_EXP_LNKCTL2_TLS_2_5GT;

	if (!pcie_dev->bw_scale)
		return;

	if (index >= pcie_dev->bw_gen_max) {
		PCIE_ERR(pcie_dev,
			"PCIe: RC%d: invalid target link speed: %d\n",
			pcie_dev->rc_idx, target_link_speed);
		return;
	}

	bw_scale = &pcie_dev->bw_scale[index];

	if (pcie_dev->cx_vreg)
		regulator_set_voltage(pcie_dev->cx_vreg->hdl,
					bw_scale->cx_vreg_min,
					pcie_dev->cx_vreg->max_v);

	if (pcie_dev->rate_change_clk) {
		mutex_lock(&pcie_dev->clk_lock);

		/* it is okay to always scale up */
		clk_set_rate(pcie_dev->rate_change_clk->hdl,
				RATE_CHANGE_100MHZ);

		if (bw_scale->rate_change_freq == RATE_CHANGE_100MHZ)
			pcie_drv.rate_change_vote |= BIT(pcie_dev->rc_idx);
		else
			pcie_drv.rate_change_vote &= ~BIT(pcie_dev->rc_idx);

		/* scale down to 19.2MHz if no one needs 100MHz */
		if (!pcie_drv.rate_change_vote)
			clk_set_rate(pcie_dev->rate_change_clk->hdl,
					RATE_CHANGE_19P2MHZ);

		mutex_unlock(&pcie_dev->clk_lock);
	}
}

static int msm_pcie_link_train(struct msm_pcie_dev_t *dev)
{
	int link_check_count = 0;
@@ -4033,6 +4131,39 @@ static int msm_pcie_link_train(struct msm_pcie_dev_t *dev)
		return MSM_PCIE_ERROR;
	}

	if (dev->bw_scale) {
		u32 index;
		u32 current_link_speed;
		struct msm_pcie_bw_scale_info_t *bw_scale;

		/*
		 * check if the link up GEN speed is less than the max/default
		 * supported. If it is, scale down CX corner and rate change
		 * clock accordingly.
		 */
		current_link_speed = readl_relaxed(dev->dm_core +
						PCIE20_CAP_LINKCTRLSTATUS);
		current_link_speed = ((current_link_speed >> 16) &
					PCI_EXP_LNKSTA_CLS);

		index = current_link_speed - PCI_EXP_LNKCTL2_TLS_2_5GT;
		if (index >= dev->bw_gen_max) {
			PCIE_ERR(dev,
				"PCIe: RC%d: unsupported gen speed: %d\n",
				dev->rc_idx, current_link_speed);
			return 0;
		}

		bw_scale = &dev->bw_scale[index];

		if (bw_scale->cx_vreg_min < dev->cx_vreg->min_v) {
			msm_pcie_write_reg_field(dev->dm_core,
				PCIE20_CAP + PCI_EXP_LNKCTL2,
				PCI_EXP_LNKCAP_SLS, current_link_speed);
			msm_pcie_scale_link_bandwidth(dev, current_link_speed);
		}
	}

	return 0;
}

@@ -6140,9 +6271,6 @@ static int msm_pcie_link_retrain(struct msm_pcie_dev_t *pcie_dev,
	u32 cnt_max = 1000; /* 100ms timeout */
	u32 link_status_lbms_mask = PCI_EXP_LNKSTA_LBMS << PCI_EXP_LNKCTL;

	/* force link to L0 */
	msm_pcie_write_mask(pcie_dev->parf + PCIE20_PARF_PM_CTRL,  0, BIT(5));

	cnt = 0;
	/* confirm link is in L0 */
	while (((readl_relaxed(pcie_dev->parf + PCIE20_PARF_LTSSM) &
@@ -6175,34 +6303,34 @@ static int msm_pcie_link_retrain(struct msm_pcie_dev_t *pcie_dev,
		usleep_range(100, 105);
	}

	/* re-enable link LPM */
	msm_pcie_write_mask(pcie_dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0);

	return 0;
}

static void msm_pcie_set_link_width(struct msm_pcie_dev_t *pcie_dev,
					u16 *target_link_width)
static int msm_pcie_set_link_width(struct msm_pcie_dev_t *pcie_dev,
					u16 target_link_width)
{
	switch (*target_link_width) {
	u16 link_width;

	switch (target_link_width) {
	case PCI_EXP_LNKSTA_NLW_X1:
		*target_link_width = LINK_WIDTH_X1;
		link_width = LINK_WIDTH_X1;
		break;
	case PCI_EXP_LNKSTA_NLW_X2:
		*target_link_width = LINK_WIDTH_X2;
		link_width = LINK_WIDTH_X2;
		break;
	default:
		PCIE_ERR(pcie_dev,
			"PCIe: RC%d: unsupported link width request: %d\n",
			pcie_dev->rc_idx, *target_link_width);
		*target_link_width = 0;
		return;
			pcie_dev->rc_idx, target_link_width);
		return -EINVAL;
	}

	msm_pcie_write_reg_field(pcie_dev->dm_core,
				PCIE20_PORT_LINK_CTRL_REG,
				LINK_WIDTH_MASK << LINK_WIDTH_SHIFT,
				*target_link_width);
				link_width);

	return 0;
}

int msm_pcie_set_link_bandwidth(struct pci_dev *pci_dev, u16 target_link_speed,
@@ -6213,6 +6341,8 @@ int msm_pcie_set_link_bandwidth(struct pci_dev *pci_dev, u16 target_link_speed,
	u16 link_status;
	u16 current_link_speed;
	u16 current_link_width;
	bool set_link_speed = true;
	bool set_link_width = true;
	int ret;

	if (!pci_dev)
@@ -6228,54 +6358,57 @@ int msm_pcie_set_link_bandwidth(struct pci_dev *pci_dev, u16 target_link_speed,
	target_link_width <<= PCI_EXP_LNKSTA_NLW_SHIFT;

	if (target_link_speed == current_link_speed)
		target_link_speed = 0;
		set_link_speed = false;

	if (target_link_width == current_link_width)
		target_link_width = 0;

	if (target_link_width)
		msm_pcie_set_link_width(pcie_dev, &target_link_width);
		set_link_width = false;

	if (!target_link_speed && !target_link_width)
	if (!set_link_speed && !set_link_width)
		return 0;

	if (target_link_speed)
	if (set_link_width) {
		ret = msm_pcie_set_link_width(pcie_dev, target_link_width);
		if (ret)
			return ret;
	}

	if (set_link_speed)
		msm_pcie_config_clear_set_dword(root_pci_dev,
						root_pci_dev->pcie_cap +
						PCI_EXP_LNKCTL2,
						PCI_EXP_LNKSTA_CLS,
						target_link_speed);

	/* increase CX and rate change clk freq if target speed is Gen3 */
	if (target_link_speed == PCI_EXP_LNKCTL2_TLS_8_0GT) {
		if (pcie_dev->cx_vreg)
			regulator_set_voltage(pcie_dev->cx_vreg->hdl,
						RPMH_REGULATOR_LEVEL_NOM,
						pcie_dev->cx_vreg->max_v);
	/* disable link L1. Need to be in L0 for gen switch */
	msm_pcie_config_l1(pcie_dev, root_pci_dev, false);
	msm_pcie_write_mask(pcie_dev->parf + PCIE20_PARF_PM_CTRL,  0, BIT(5));

		if (pcie_dev->rate_change_clk)
			clk_set_rate(pcie_dev->rate_change_clk->hdl,
					RATE_CHANGE_100MHZ);
	}
	if (target_link_speed > current_link_speed)
		msm_pcie_scale_link_bandwidth(pcie_dev, target_link_speed);

	ret = msm_pcie_link_retrain(pcie_dev, root_pci_dev);
	if (ret)
		return ret;
		goto out;

	/* decrease CX and rate change clk freq if link is in Gen1 */
	pcie_capability_read_word(root_pci_dev, PCI_EXP_LNKSTA, &link_status);
	if ((link_status & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKCTL2_TLS_2_5GT) {
		if (pcie_dev->cx_vreg)
			regulator_set_voltage(pcie_dev->cx_vreg->hdl,
						RPMH_REGULATOR_LEVEL_LOW_SVS,
						pcie_dev->cx_vreg->max_v);

		if (pcie_dev->rate_change_clk)
			clk_set_rate(pcie_dev->rate_change_clk->hdl,
					RATE_CHANGE_19P2MHZ);
	if ((link_status & PCI_EXP_LNKSTA_CLS) != target_link_speed ||
		(link_status & PCI_EXP_LNKSTA_NLW) != target_link_width) {
		PCIE_ERR(pcie_dev,
			"PCIe: RC%d: failed to switch bandwidth: target speed: %d width: %d\n",
			pcie_dev->rc_idx, target_link_speed,
			target_link_width >> PCI_EXP_LNKSTA_NLW_SHIFT);
		ret = -EIO;
		goto out;
	}

	return 0;
	if (target_link_speed < current_link_speed)
		msm_pcie_scale_link_bandwidth(pcie_dev, target_link_speed);
out:
	/* re-enable link L1 */
	msm_pcie_write_mask(pcie_dev->parf + PCIE20_PARF_PM_CTRL, BIT(5), 0);
	msm_pcie_config_l1(pcie_dev, root_pci_dev, true);

	return ret;
}
EXPORT_SYMBOL(msm_pcie_set_link_bandwidth);

@@ -6561,6 +6694,7 @@ static int __init pcie_init(void)
		msm_pcie_dev[i].cfg_access = true;
		mutex_init(&msm_pcie_dev[i].enumerate_lock);
		mutex_init(&msm_pcie_dev[i].setup_lock);
		mutex_init(&msm_pcie_dev[i].clk_lock);
		mutex_init(&msm_pcie_dev[i].recovery_lock);
		spin_lock_init(&msm_pcie_dev[i].wakeup_lock);
		spin_lock_init(&msm_pcie_dev[i].irq_lock);