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

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

Merge "msm: ep_pcie: Sending PME for device initiated D3cold exit"

parents a91c0ba8 a13ebeb9
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -94,6 +94,8 @@
#define PCIE20_SUBSYSTEM               0x2c
#define PCIE20_CAP_ID_NXT_PTR          0x40
#define PCIE20_CON_STATUS              0x44
#define PCIE20_MASK_PME_EN             BIT(8)
#define PCIE20_MASK_PME_STATUS         BIT(15)
#define PCIE20_MSI_CAP_ID_NEXT_CTRL    0x50
#define PCIE20_MSI_LOWER               0x54
#define PCIE20_MSI_UPPER               0x58
@@ -360,6 +362,7 @@ struct ep_pcie_dev_t {
	bool			     mhi_soc_reset_en;
	bool			     aoss_rst_clear;
	bool			     avoid_reboot_in_d3hot;
	bool			     pme_in_wake_from_d3cold;
	u32                          dbi_base_reg;
	u32                          slv_space_reg;
	u32                          phy_status_reg;
@@ -411,6 +414,8 @@ struct ep_pcie_dev_t {
	int                          perst_irq;
	atomic_t                     host_wake_pending;
	bool			     conf_ipa_msi_iatu;
	bool			     wake_from_d3cold;
	bool			     pme_en_d3;

	struct ep_pcie_register_event *event_reg;
	struct work_struct           handle_bme_work;
+83 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/interconnect.h>
#include <linux/iopoll.h>

#include "ep_pcie_com.h"
#include <asm/dma-iommu.h>
@@ -46,6 +47,9 @@
#define ICC_AVG_BW				500
#define ICC_PEAK_BW				800
#define PERST_RAW_RESET_STATUS			BIT(11)
#define PCIE_PME_COUNT				2
#define PCIE_PME_SLEEP_DELAY_US		10000
#define PCIE_PME_RESEND_DELAY_US		100000

/* debug mask sys interface */
static int ep_pcie_debug_mask;
@@ -120,6 +124,7 @@ static const struct ep_pcie_irq_info_t ep_pcie_irq_info[EP_PCIE_MAX_IRQ] = {
};

static int ep_pcie_core_wakeup_host_internal(enum ep_pcie_event event);
static void ep_pcie_core_issue_inband_pme(void);

int ep_pcie_get_debug_mask(void)
{
@@ -790,6 +795,17 @@ static void ep_pcie_core_init(struct ep_pcie_dev_t *dev, bool configured)
		ep_pcie_write_mask(dev->dm_core + PCIE20_CAP_ID_NXT_PTR, 0,
						BIT(31)|BIT(30)|BIT(27));

		if (dev->pme_in_wake_from_d3cold && dev->pme_en_d3) {
			/*
			 * PME_ENABLE is cleared after d3cold state if
			 * retention flops are not present in the target.
			 * Set PME_ENABLE, if it is seen as set during
			 * d3hot to send PME message
			 */
			ep_pcie_write_mask(dev->dm_core + PCIE20_CON_STATUS, 0, PCIE20_MASK_PME_EN);
			dev->pme_en_d3 = false;
		}

		/* Set the Endpoint L0s Acceptable Latency to 1us (max) */
		ep_pcie_write_reg_field(dev->dm_core,
			PCIE20_DEVICE_CAPABILITIES,
@@ -1675,6 +1691,46 @@ static void ep_pcie_core_toggle_wake_gpio(bool is_on)

}

static void ep_pcie_core_issue_pme_for_wake_from_d3cold(void)
{
	struct ep_pcie_dev_t *dev = &ep_pcie_dev;
	u32 pme_count = 0, pme_reg;
	bool pme_en, pme_status;

	pme_reg = readl_relaxed(dev->dm_core + PCIE20_CON_STATUS);
	pme_en = pme_reg & PCIE20_MASK_PME_EN;
	pme_status = pme_reg & PCIE20_MASK_PME_STATUS;

	EP_PCIE_INFO(dev, "PCIe V%d: pme_reg: 0x%x, pme_en: %d, pme_status: %d\n",
			dev->rev, pme_reg, pme_en, pme_status);

	if (pme_en) {
		do {
			/* Sending PME for device initiated d3_cold exit */
			ep_pcie_core_issue_inband_pme();
			/*Polling for pme_status to be 0 for 100ms*/
			readx_poll_timeout(readl_relaxed, dev->dm_core + PCIE20_CON_STATUS, pme_reg,
				!(pme_reg & PCIE20_MASK_PME_STATUS), PCIE_PME_SLEEP_DELAY_US,
				PCIE_PME_RESEND_DELAY_US);

			pme_status = pme_reg & PCIE20_MASK_PME_STATUS;
			EP_PCIE_DBG(dev, "PCIe V%d: pme_status:%d\n", dev->rev, pme_status);

			pme_count++;

			if (!pme_status)
				break;

		} while (pme_count < PCIE_PME_COUNT);

		if (pme_status && pme_count == PCIE_PME_COUNT) {
			EP_PCIE_INFO(dev,
			"PCIe V%d: Host failed to acknowledge PME for device-initiated wake\n",
			dev->rev);
		}
	}
}

int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt)
{
	int ret = 0;
@@ -1951,6 +2007,16 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt)
			dev->rev);
	}

	if (dev->pme_in_wake_from_d3cold && dev->wake_from_d3cold) {
		/*
		 *  Sending PME after link training for device
		 *  initiated D3cold to D0 transition, based on
		 *  PCIe specification
		 */
		ep_pcie_core_issue_pme_for_wake_from_d3cold();
		dev->wake_from_d3cold = false;
	}

checkbme:
	/* Clear AOSS_CC_RESET_STATUS::PERST_RAW_RESET_STATUS when linking up */
	if (dev->aoss_rst_clear)
@@ -2277,6 +2343,9 @@ static irqreturn_t ep_pcie_handle_dstate_change_irq(int irq, void *data)
			dev->rev, dev->d3_counter);
		ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, 0, BIT(1));

		dev->pme_en_d3 = readl_relaxed(dev->dm_core +
						PCIE20_CON_STATUS) & PCIE20_MASK_PME_EN;

		if (dev->enumerated)
			ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_D3_HOT);
		else
@@ -3147,6 +3216,13 @@ static int ep_pcie_core_wakeup_host_internal(enum ep_pcie_event event)
	if (!atomic_read(&dev->perst_deast)) {
		/*D3 cold handling*/
		ep_pcie_core_toggle_wake_gpio(true);
		if (dev->pme_in_wake_from_d3cold) {
			/*
			 * Set below flag for device initiated
			 * d3cold wake to send PME message
			 */
			dev->wake_from_d3cold = true;
		}
	} else if (dev->l23_ready) {
		EP_PCIE_ERR(dev,
			"PCIe V%d: request to assert WAKE# when in D3hot\n",
@@ -3423,6 +3499,13 @@ static int ep_pcie_probe(struct platform_device *pdev)
	"PCIe V%d: PME during reboot/panic (in D3hot) is %s needed\n",
	ep_pcie_dev.rev, ep_pcie_dev.avoid_reboot_in_d3hot ? "" : "not");

	ep_pcie_dev.pme_in_wake_from_d3cold =
		of_property_read_bool((&pdev->dev)->of_node,
				"qcom,pme-in-wake-from-d3cold");
	EP_PCIE_DBG(&ep_pcie_dev,
	"PCIe V%d: PME is%s sent during wake from d3cold\n",
	ep_pcie_dev.rev, ep_pcie_dev.pme_in_wake_from_d3cold ? "" : " not");

	ret = of_property_read_u32((&pdev->dev)->of_node,
				"qcom,mhi-soc-reset-offset",
				&ep_pcie_dev.mhi_soc_reset_offset);