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

Commit 95e2d34b authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ep_pcie: add support for BME in IRQ mode"

parents a6f19e5c 50e944c5
Loading
Loading
Loading
Loading
+1 −6
Original line number Diff line number Diff line
@@ -110,12 +110,7 @@ int ep_pcie_register_event(struct ep_pcie_hw *phandle,
	if (phandle)
		return phandle->register_event(reg);

	if (ep_pcie_dev.perst_enum)
	return ep_pcie_core_register_event(reg);

	pr_err("ep_pcie:%s: the input driver handle is NULL.",
		__func__);
	return -EINVAL;
}
EXPORT_SYMBOL(ep_pcie_register_event);

+5 −2
Original line number Diff line number Diff line
@@ -210,6 +210,7 @@ enum ep_pcie_irq {
	EP_PCIE_INT_LINK_UP,
	EP_PCIE_INT_LINK_DOWN,
	EP_PCIE_INT_BRIDGE_FLUSH_N,
	EP_PCIE_INT_BME,
	EP_PCIE_INT_GLOBAL,
	EP_PCIE_MAX_IRQ,
};
@@ -309,6 +310,7 @@ struct ep_pcie_dev_t {
	unsigned long                isr_save_flags;
	ulong                        linkdown_counter;
	ulong                        linkup_counter;
	ulong                        bme_counter;
	ulong                        pm_to_counter;
	ulong                        d0_counter;
	ulong                        d3_counter;
@@ -331,6 +333,7 @@ struct ep_pcie_dev_t {

	struct ep_pcie_register_event *event_reg;
	struct work_struct	     handle_perst_work;
	struct work_struct           handle_bme_work;
};

extern struct ep_pcie_dev_t ep_pcie_dev;
@@ -347,14 +350,14 @@ static inline void ep_pcie_write_mask(void __iomem *addr,
	wmb();
}

static inline void ep_pcie_write_reg(void *base, u32 offset, u32 value)
static inline void ep_pcie_write_reg(void __iomem *base, u32 offset, u32 value)
{
	writel_relaxed(value, base + offset);
	/* ensure register write goes through before next regiser operation */
	wmb();
}

static inline void ep_pcie_write_reg_field(void *base, u32 offset,
static inline void ep_pcie_write_reg_field(void __iomem *base, u32 offset,
	const u32 mask, u32 val)
{
	u32 shift = find_first_bit((void *)&mask, 32);
+144 −53
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ static const struct ep_pcie_irq_info_t ep_pcie_irq_info[EP_PCIE_MAX_IRQ] = {
	{"int_link_up",	0},
	{"int_link_down",	0},
	{"int_bridge_flush_n",	0},
	{"int_bme",	0},
	{"int_global",	0}
};

@@ -982,19 +983,47 @@ static void ep_pcie_release_resources(struct ep_pcie_dev_t *dev)
	dev->phy = NULL;
	dev->mmio = NULL;
	dev->msi = NULL;
}

	if (dev->bus_client) {
		msm_bus_scale_unregister_client(dev->bus_client);
		dev->bus_client = 0;
static void ep_pcie_enumeration_complete(struct ep_pcie_dev_t *dev)
{
	dev->enumerated = true;
	dev->link_status = EP_PCIE_LINK_ENABLED;

	if (dev->gpio[EP_PCIE_GPIO_MDM2AP].num) {
		/* assert MDM2AP Status GPIO */
		EP_PCIE_DBG2(dev, "PCIe V%d: assert MDM2AP Status.\n",
				dev->rev);
		EP_PCIE_DBG(dev,
			"PCIe V%d: MDM2APStatus GPIO initial:%d.\n",
			dev->rev,
			gpio_get_value(
			dev->gpio[EP_PCIE_GPIO_MDM2AP].num));
		gpio_set_value(dev->gpio[EP_PCIE_GPIO_MDM2AP].num,
			dev->gpio[EP_PCIE_GPIO_MDM2AP].on);
		EP_PCIE_DBG(dev,
			"PCIe V%d: MDM2APStatus GPIO after assertion:%d.\n",
			dev->rev,
			gpio_get_value(
			dev->gpio[EP_PCIE_GPIO_MDM2AP].num));
	}

	hw_drv.device_id = readl_relaxed(dev->dm_core);
	EP_PCIE_DBG(&ep_pcie_dev,
		"PCIe V%d: register driver for device 0x%x.\n",
		ep_pcie_dev.rev, hw_drv.device_id);
	ep_pcie_register_drv(&hw_drv);
	ep_pcie_notify_event(dev, EP_PCIE_EVENT_LINKUP);

	return;
}

int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt)
{
	int ret = 0;
	u32 val;
	u32 retries;
	u32 bme;
	u32 val = 0;
	u32 retries = 0;
	u32 bme = 0;
	bool ltssm_en = false;
	struct ep_pcie_dev_t *dev = &ep_pcie_dev;

@@ -1222,8 +1251,10 @@ checkbme:
					0x7FFFE000);
	}

	if (!(opt & EP_PCIE_OPT_ENUM_ASYNC)) {
		/* Wait for up to 1000ms for BME to be set */
		retries = 0;

		bme = readl_relaxed(dev->dm_core +
		PCIE20_COMMAND_STATUS) & BIT(2);
		while (!bme && (retries < BME_CHECK_MAX_COUNT)) {
@@ -1232,36 +1263,25 @@ checkbme:
			bme = readl_relaxed(dev->dm_core +
				PCIE20_COMMAND_STATUS) & BIT(2);
		}
	} else {
		EP_PCIE_DBG(dev,
			"PCIe V%d: EP_PCIE_OPT_ENUM_ASYNC is true.\n",
			dev->rev);
	}

	if (bme) {
		dev->link_status = EP_PCIE_LINK_ENABLED;
		EP_PCIE_DBG(dev,
			"PCIe V%d: PCIe link is up and BME is enabled after %d checkings (%d ms).\n",
			dev->rev, retries,
			BME_TIMEOUT_US_MIN * retries / 1000);

		if (dev->gpio[EP_PCIE_GPIO_MDM2AP].num) {
			/* assert MDM2AP Status GPIO */
			EP_PCIE_DBG2(dev, "PCIe V%d: assert MDM2AP Status .\n",
				dev->rev);
			EP_PCIE_DBG(dev,
				"PCIe V%d: MDM2APStatus GPIO initial:%d.\n",
				dev->rev,
				gpio_get_value(
					dev->gpio[EP_PCIE_GPIO_MDM2AP].num));
			gpio_set_value(dev->gpio[EP_PCIE_GPIO_MDM2AP].num,
					dev->gpio[EP_PCIE_GPIO_MDM2AP].on);
			EP_PCIE_DBG(dev,
				"PCIe V%d: MDM2APStatus GPIO after assertion:%d.\n",
				dev->rev,
				gpio_get_value(
					dev->gpio[EP_PCIE_GPIO_MDM2AP].num));
		}
		ep_pcie_enumeration_complete(dev);
	} else {
		if (!(opt & EP_PCIE_OPT_ENUM_ASYNC))
			EP_PCIE_ERR(dev,
				"PCIe V%d: PCIe link is up but BME is still disabled after max waiting time.\n",
				dev->rev);
		if (!ep_pcie_debug_keep_resource) {
		if (!ep_pcie_debug_keep_resource &&
				!(opt&EP_PCIE_OPT_ENUM_ASYNC)) {
			ret = EP_PCIE_ERROR;
			dev->link_status = EP_PCIE_LINK_DISABLED;
			goto link_fail;
@@ -1363,6 +1383,38 @@ int ep_pcie_core_mask_irq_event(enum ep_pcie_irq_event event,
	return rc;
}

static irqreturn_t ep_pcie_handle_bme_irq(int irq, void *data)
{
	struct ep_pcie_dev_t *dev = data;
	unsigned long irqsave_flags;

	spin_lock_irqsave(&dev->isr_lock, irqsave_flags);

	dev->bme_counter++;
	EP_PCIE_DBG(dev,
		"PCIe V%d: No. %ld BME IRQ.\n", dev->rev, dev->bme_counter);

	if (readl_relaxed(dev->dm_core + PCIE20_COMMAND_STATUS) & BIT(2)) {
		/* BME has been enabled */
		if (!dev->enumerated) {
			EP_PCIE_DBG(dev,
				"PCIe V%d:BME is set. Enumeration is complete\n",
				dev->rev);
			schedule_work(&dev->handle_bme_work);
		} else {
			EP_PCIE_DBG(dev,
				"PCIe V%d:BME is set again after the enumeration has completed\n",
				dev->rev);
		}
	} else {
		EP_PCIE_DBG(dev,
				"PCIe V%d:BME is still disabled\n", dev->rev);
	}

	spin_unlock_irqrestore(&dev->isr_lock, irqsave_flags);
	return IRQ_HANDLED;
}

static irqreturn_t ep_pcie_handle_linkdown_irq(int irq, void *data)
{
	struct ep_pcie_dev_t *dev = data;
@@ -1497,19 +1549,19 @@ static int ep_pcie_enumeration(struct ep_pcie_dev_t *dev)
			"PCIe V%d: PCIe link enumeration failed.\n",
			ep_pcie_dev.rev);
	} else {
		if (dev->link_status == EP_PCIE_LINK_ENABLED) {
			EP_PCIE_INFO(&ep_pcie_dev,
				"PCIe V%d: PCIe link enumeration is successful with host side.\n",
				ep_pcie_dev.rev);

		dev->enumerated = true;

		hw_drv.device_id = readl_relaxed(dev->dm_core);
		EP_PCIE_DBG(&ep_pcie_dev,
			"PCIe V%d: register driver for device 0x%x.\n",
			ep_pcie_dev.rev, hw_drv.device_id);
		ep_pcie_register_drv(&hw_drv);

		ep_pcie_notify_event(dev, EP_PCIE_EVENT_LINKUP);
		} else if (dev->link_status == EP_PCIE_LINK_UP) {
			EP_PCIE_INFO(&ep_pcie_dev,
				"PCIe V%d: PCIe link training is successful with host side. Waiting for enumeration to complete.\n",
				ep_pcie_dev.rev);
		} else {
			EP_PCIE_ERR(&ep_pcie_dev,
				"PCIe V%d: PCIe link is in the unexpected status: %d\n",
				ep_pcie_dev.rev, dev->link_status);
		}
	}

	return ret;
@@ -1523,6 +1575,14 @@ static void handle_perst_func(struct work_struct *work)
	ep_pcie_enumeration(dev);
}

static void handle_bme_func(struct work_struct *work)
{
	struct ep_pcie_dev_t *dev = container_of(work,
			struct ep_pcie_dev_t, handle_bme_work);

	ep_pcie_enumeration_complete(dev);
}

static irqreturn_t ep_pcie_handle_perst_irq(int irq, void *data)
{
	struct ep_pcie_dev_t *dev = data;
@@ -1595,7 +1655,7 @@ static irqreturn_t ep_pcie_handle_global_irq(int irq, void *data)
				EP_PCIE_DUMP(dev,
					"PCIe V%d: handle BME event.\n",
					dev->rev);
				dev->link_status = EP_PCIE_LINK_ENABLED;
				ep_pcie_handle_bme_irq(irq, data);
				break;
			case EP_PCIE_INT_EVT_PM_TURNOFF:
				EP_PCIE_DUMP(dev,
@@ -1640,6 +1700,10 @@ int32_t ep_pcie_irq_init(struct ep_pcie_dev_t *dev)

	EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev);

	/* Initialize all works to be performed before registering for IRQs*/
	INIT_WORK(&dev->handle_perst_work, handle_perst_func);
	INIT_WORK(&dev->handle_bme_work, handle_bme_func);

	if (dev->aggregated_irq) {
		ret = devm_request_irq(pdev,
			dev->irq[EP_PCIE_INT_GLOBAL].num,
@@ -1653,12 +1717,41 @@ int32_t ep_pcie_irq_init(struct ep_pcie_dev_t *dev)
			return ret;
		}

		ret = enable_irq_wake(dev->irq[EP_PCIE_INT_GLOBAL].num);
		if (ret) {
			EP_PCIE_ERR(dev,
				"PCIe V%d: Unable to enable wake for Global interrupt\n",
				dev->rev);
			return ret;
		}

		EP_PCIE_DBG(dev,
			"PCIe V%d: request global interrupt %d\n",
			dev->rev, dev->irq[EP_PCIE_INT_GLOBAL].num);
		goto perst_irq;
	}

	/* register handler for BME interrupt */
	ret = devm_request_irq(pdev,
		dev->irq[EP_PCIE_INT_BME].num,
		ep_pcie_handle_bme_irq,
		IRQF_TRIGGER_RISING, dev->irq[EP_PCIE_INT_BME].name,
		dev);
	if (ret) {
		EP_PCIE_ERR(dev,
			"PCIe V%d: Unable to request BME interrupt %d\n",
			dev->rev, dev->irq[EP_PCIE_INT_BME].num);
		return ret;
	}

	ret = enable_irq_wake(dev->irq[EP_PCIE_INT_BME].num);
	if (ret) {
		EP_PCIE_ERR(dev,
			"PCIe V%d: Unable to enable wake for BME interrupt\n",
			dev->rev);
		return ret;
	}

	/* register handler for linkdown interrupt */
	ret = devm_request_irq(pdev,
		dev->irq[EP_PCIE_INT_LINK_DOWN].num,
@@ -1732,8 +1825,6 @@ perst_irq:
		return ret;
	}

	INIT_WORK(&dev->handle_perst_work, handle_perst_func);

	return 0;
}

+2 −1
Original line number Diff line number Diff line
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015,2017, 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
@@ -60,6 +60,7 @@ enum ep_pcie_options {
	EP_PCIE_OPT_AST_WAKE = 0x1,
	EP_PCIE_OPT_POWER_ON = 0x2,
	EP_PCIE_OPT_ENUM = 0x4,
	EP_PCIE_OPT_ENUM_ASYNC = 0x8,
	EP_PCIE_OPT_ALL = 0xFFFFFFFF,
};