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

Commit 98080685 authored by Siddartha Mohanadoss's avatar Siddartha Mohanadoss
Browse files

mhi_dev: mhi: Update initialization sequence



As part of receiving a callback once the IPA driver is
ready, move the MHI initialization sequence of setting
device ready bit after IPA HW is ready. Once the callback
is received the IPA DMA is used for caching control and data
from the MHI host.

Change-Id: I0ec3b64f3407395bf749a63b521feb84ed46d9f9
Signed-off-by: default avatarSiddartha Mohanadoss <smohanad@codeaurora.org>
parent 188ab649
Loading
Loading
Loading
Loading
+136 −161
Original line number Diff line number Diff line
@@ -259,7 +259,7 @@ static int mhi_hwc_init(struct mhi_dev *mhi)
	ipa_init_params.msi.mask = ((1 << cfg.msg_num) - 1);
	ipa_init_params.first_er_idx = erdb_cfg.base;
	ipa_init_params.first_ch_idx = HW_CHANNEL_BASE;
	ipa_init_params.mmio_addr = ((uint32_t) mhi_ctx->mmio_base_pa_addr)
	ipa_init_params.mmio_addr = ((uint32_t) mhi_ctx->mmio_base_pa_addr);
	ipa_init_params.assert_bit40 = true;

	mhi_log(MHI_MSG_ERROR,
@@ -470,14 +470,14 @@ int mhi_dev_send_event(struct mhi_dev *mhi, int evnt_ring,
				sizeof(union mhi_dev_ring_element_type)) +
				ring->ring_ctx->generic.rbase;

	mhi_log(MHI_MSG_ERROR, ("ev.rp = %llx for %lld\n",
				ring->ring_ctx_shadow->ev.rp, evnt_ring_idx));
	mhi_log(MHI_MSG_ERROR, "ev.rp = %llx for %lld\n",
				ring->ring_ctx_shadow->ev.rp, evnt_ring_idx);

	host_rp_update.host_pa = (mhi->ev_ctx_shadow.host_pa +
	host_rp_addr.host_pa = (mhi->ev_ctx_shadow.host_pa +
			sizeof(struct mhi_dev_ev_ctx) *
			evnt_ring) + (uint32_t) &ring->ring_ctx->ev.rp -
			(uint32_t) ring->ring_ctx;
	mhi_dev_write_to_host(&host_rp_update, &ring->ring_ctx_shadow->ev.rp,
	mhi_dev_write_to_host(&host_rp_addr, &ring->ring_ctx_shadow->ev.rp,
						sizeof(uint64_t),
						mhi);

@@ -497,7 +497,6 @@ int mhi_dev_send_event(struct mhi_dev *mhi, int evnt_ring,

	msi_addr.host_pa = (uint64_t)((uint64_t)cfg.upper << 32) |
						(uint64_t)cfg.lower;
	msi_addr.host_pa = 0xfee0f00c;
	msi = cfg.data + mhi_ctx->mhi_ep_msi_num;
	mhi_log(MHI_MSG_ERROR, "Sending MSI %d to 0x%llx as data = 0x%x\n",
			mhi_ctx->mhi_ep_msi_num, msi_addr.host_pa, msi);
@@ -1177,12 +1176,7 @@ EXPORT_SYMBOL(mhi_dev_resume);

static int mhi_dev_ring_init(struct mhi_dev *dev)
{
	int rc = 0, i = 0;
	enum mhi_dev_state state;
	uint32_t max_cnt = 0;
	struct ep_pcie_msi_config cfg;
	struct mhi_addr msi_addr;
	uint32_t msi = 0;
	int i = 0;

	mhi_log(MHI_MSG_INFO, "initializing all rings");
	dev->cmd_ring_idx = 0;
@@ -1208,60 +1202,6 @@ static int mhi_dev_ring_init(struct mhi_dev *dev)
		mhi_ring_set_cb(&dev->ring[i], mhi_dev_process_tre_ring);
	}

	rc = mhi_dev_mmio_get_mhi_state(dev, &state);
	if (rc) {
		pr_err("%s: get mhi state failed\n", __func__);
		return rc;
	}

	rc = ep_pcie_get_msi_config(mhi_ctx->phandle, &cfg);
	if (rc) {
		pr_err("MHI: error geting msi configs\n");
		return rc;
	}

	msi_addr.host_pa = 0xfee0f00c;
	msi = cfg.data + mhi_ctx->mhi_ep_msi_num;
	mhi_log(MHI_MSG_ERROR("Sending MSI %d to 0x%llx  as data = 0x%X\n",
			mhi_ctx->mhi_ep_msi_num, msi_addr.host_pa, msi));

	mhi_dev_write_to_host(&msi_addr, &msi, 4, dev);

	while (state != MHI_DEV_M0_STATE && max_cnt < MHI_DEV_M0_MAX_CNT) {
		/* Wait for Host to set the M0 state */
		usleep_range(MHI_M0_WAIT_MIN_USLEEP, MHI_M0_WAIT_MAX_USLEEP);
		rc = mhi_dev_mmio_get_mhi_state(dev, &state);
		if (rc) {
			pr_err("%s: get mhi state failed\n", __func__);
			return rc;
		}
		max_cnt++;
	}

	mhi_log(MHI_MSG_INFO, "state:%d\n", state);

	if (state == MHI_DEV_M0_STATE) {
		rc = mhi_dev_cache_host_cfg(dev);
		if (rc) {
			pr_err("Failed to cache the host config\n");
			return rc;
		}

		rc = mhi_dev_mmio_set_env(dev, MHI_ENV_VALUE);
		if (rc) {
			pr_err("%s: env setting failed\n", __func__);
			return rc;
		}
	} else {
		pr_err("MHI device failed to enter M0\n");
		return -EINVAL;
	}

	rc = mhi_hwc_init(dev);
	if (rc) {
		pr_err("error during hwc_init\n");
		return rc;
	}

	return 0;
}
@@ -1641,11 +1581,16 @@ exit:
}
EXPORT_SYMBOL(mhi_dev_write_channel);

static void mhi_dev_process_ring_init(struct work_struct *work)
static void mhi_dev_enable(struct work_struct *work)
{
	int rc = 0;
	struct ep_pcie_msi_config msi_cfg;
	struct mhi_dev *mhi = container_of(work,
				struct mhi_dev, ring_init_cb_work);
	int rc = 0;

	enum mhi_dev_state state;
	uint32_t max_cnt = 0;


	rc = ipa_dma_init();
	if (rc) {
@@ -1665,7 +1610,71 @@ static void mhi_dev_process_ring_init(struct work_struct *work)
		return;
	}

	/* Invoke MHI SM when device is in RESET state */
	mhi_dev_sm_init(mhi);

	/* set the env before setting the ready bit */
	rc = mhi_dev_mmio_set_env(mhi, MHI_ENV_VALUE);
	if (rc) {
		pr_err("%s: env setting failed\n", __func__);
		return;
	}
	mhi_uci_init();

	/* All set...let's notify the host */
	mhi_dev_sm_set_ready();

	rc = ep_pcie_get_msi_config(mhi->phandle, &msi_cfg);
	if (rc) {
		pr_err("MHI: error geting msi configs\n");
		return;
	}

	rc = ep_pcie_trigger_msi(mhi->phandle, mhi->mhi_ep_msi_num);
	if (rc)
		return;

	rc = mhi_dev_mmio_get_mhi_state(mhi, &state);
	if (rc) {
		pr_err("%s: get mhi state failed\n", __func__);
		return;
	}

	while (state != MHI_DEV_M0_STATE && max_cnt < MHI_DEV_M0_MAX_CNT) {
		/* Wait for Host to set the M0 state */
		usleep_range(MHI_M0_WAIT_MIN_USLEEP, MHI_M0_WAIT_MAX_USLEEP);
		rc = mhi_dev_mmio_get_mhi_state(mhi, &state);
		if (rc) {
			pr_err("%s: get mhi state failed\n", __func__);
			return;
		}
		max_cnt++;
	}

	mhi_log(MHI_MSG_INFO, "state:%d\n", state);

	if (state == MHI_DEV_M0_STATE) {
		rc = mhi_dev_cache_host_cfg(mhi);
		if (rc) {
			pr_err("Failed to cache the host config\n");
			return;
		}

		rc = mhi_dev_mmio_set_env(mhi, MHI_ENV_VALUE);
		if (rc) {
			pr_err("%s: env setting failed\n", __func__);
			return;
		}
	} else {
		pr_err("MHI device failed to enter M0\n");
		return;
	}

	rc = mhi_hwc_init(mhi_ctx);
	if (rc) {
		pr_err("error during hwc_init\n");
		return;
	}
}

static void mhi_ring_init_cb(void *data)
@@ -1685,7 +1694,6 @@ static int get_device_tree_data(struct platform_device *pdev)
	struct mhi_dev *mhi;
	int rc = 0;
	struct resource *res_mem = NULL;
	struct ep_pcie_msi_config msi_cfg;

	mhi = devm_kzalloc(&pdev->dev,
			sizeof(struct mhi_dev), GFP_KERNEL);
@@ -1757,88 +1765,21 @@ static int get_device_tree_data(struct platform_device *pdev)
		return rc;
	}

	mhi_ctx->phandle = ep_pcie_get_phandle(mhi_ctx->ifc_id);
	if (!mhi_ctx->phandle) {
		pr_err("PCIe driver is not ready yet.\n");
		return -EPROBE_DEFER;
	}

	rc = mhi_dev_mmio_init(mhi_ctx);
	if (rc) {
		pr_err("Failed to update the MMIO init\n");
		return rc;
	}

	/* Invoke MHI SM when device is in RESET state */
	mhi_dev_sm_init(mhi_ctx);

	/* set the env before setting the ready bit */
	rc = mhi_dev_mmio_set_env(mhi, MHI_ENV_VALUE);
	if (rc) {
		pr_err("%s: env setting failed\n", __func__);
		return rc;
	}

	mhi_dev_sm_set_ready();
	rc = mhi_dev_mmio_write(mhi, MHIVER, mhi->mhi_version);
	if (rc) {
		pr_err("Failed to update the MHI version\n");
		return rc;
	return 0;
}

	mhi->event_reg.events = EP_PCIE_EVENT_PM_D3_HOT |
			EP_PCIE_EVENT_PM_D3_COLD |
			EP_PCIE_EVENT_PM_D0 |
			EP_PCIE_EVENT_PM_RST_DEAST |
			EP_PCIE_EVENT_MHI_A7 |
			EP_PCIE_EVENT_LINKDOWN;
	mhi->event_reg.user = mhi;
	mhi->event_reg.mode = EP_PCIE_TRIGGER_CALLBACK;
	mhi->event_reg.callback = mhi_dev_sm_pcie_handler;
static int mhi_init(struct mhi_dev *mhi)
{
	int rc = 0, i = 0;
	struct platform_device *pdev = mhi->pdev;

	rc = ep_pcie_register_event(mhi_ctx->phandle, &mhi_ctx->event_reg);
	if (rc) {
		pr_err("PCIe register for MHI SM cb failed\n");
		return rc;
	}

	rc = ep_pcie_get_msi_config(mhi_ctx->phandle, &msi_cfg);
	rc = mhi_dev_mmio_init(mhi);
	if (rc) {
		pr_err("MHI: error geting msi configs\n");
		return rc;
	}

	rc = ep_pcie_trigger_msi(mhi_ctx->phandle, mhi_ctx->mhi_ep_msi_num);
	if (rc)
		return rc;

	INIT_WORK(&mhi->chdb_ctrl_work, mhi_dev_scheduler);

	mhi->pending_ring_wq = alloc_workqueue("mhi_pending_wq",
							WQ_HIGHPRI, 0);
	if (!mhi->pending_ring_wq) {
		rc = -ENOMEM;
		return rc;
	}

	INIT_WORK(&mhi->pending_work, mhi_dev_process_ring_pending);

	INIT_WORK(&mhi->ring_init_cb_work, mhi_dev_process_ring_init);

	mhi->ring_init_wq = alloc_workqueue("mhi_ring_init_cb_wq",
							WQ_HIGHPRI, 0);
	if (!mhi->ring_init_wq) {
		rc = -ENOMEM;
		pr_err("Failed to update the MMIO init\n");
		return rc;
	}

	return 0;
}

static int mhi_init(struct mhi_dev *mhi)
{
	int i = 0;
	struct platform_device *pdev = mhi->pdev;

	mhi->ring = devm_kzalloc(&pdev->dev,
			(sizeof(struct mhi_dev_ring) *
@@ -1882,11 +1823,37 @@ static int mhi_dev_probe(struct platform_device *pdev)
		}
	}

	mhi_ctx->phandle = ep_pcie_get_phandle(mhi_ctx->ifc_id);
	if (!mhi_ctx->phandle) {
		pr_err("PCIe driver is not ready yet.\n");
		return -EPROBE_DEFER;
	}

	if (ep_pcie_get_linkstatus(mhi_ctx->phandle) != EP_PCIE_LINK_ENABLED) {
		pr_err("PCIe link is not ready to use.\n");
		return -EPROBE_DEFER;
	}

	INIT_WORK(&mhi_ctx->chdb_ctrl_work, mhi_dev_scheduler);

	mhi_ctx->pending_ring_wq = alloc_workqueue("mhi_pending_wq",
							WQ_HIGHPRI, 0);
	if (!mhi_ctx->pending_ring_wq) {
		rc = -ENOMEM;
		return rc;
	}

	INIT_WORK(&mhi_ctx->pending_work, mhi_dev_process_ring_pending);

	INIT_WORK(&mhi_ctx->ring_init_cb_work, mhi_dev_enable);

	mhi_ctx->ring_init_wq = alloc_workqueue("mhi_ring_init_cb_wq",
							WQ_HIGHPRI, 0);
	if (!mhi_ctx->ring_init_wq) {
		rc = -ENOMEM;
		return rc;
	}

	INIT_LIST_HEAD(&mhi_ctx->event_ring_list);
	INIT_LIST_HEAD(&mhi_ctx->process_ring_list);
	mutex_init(&mhi_ctx->mhi_lock);
@@ -1917,26 +1884,34 @@ static int mhi_dev_probe(struct platform_device *pdev)
	if (!mhi_ctx->write_handle)
		return -ENOMEM;

	rc = ipa_register_ipa_ready_cb(mhi_ring_init_cb, mhi_ctx);
	if (rc < 0) {
		if (rc == -EEXIST) {
			rc = ipa_dma_init();
	rc = mhi_dev_mmio_write(mhi_ctx, MHIVER, mhi_ctx->mhi_version);
	if (rc) {
				pr_err("ipa dma init failed\n");
		pr_err("Failed to update the MHI version\n");
		return rc;
	}

			rc = ipa_dma_enable();
	mhi_ctx->event_reg.events = EP_PCIE_EVENT_PM_D3_HOT |
		EP_PCIE_EVENT_PM_D3_COLD |
		EP_PCIE_EVENT_PM_D0 |
		EP_PCIE_EVENT_PM_RST_DEAST |
		EP_PCIE_EVENT_MHI_A7 |
		EP_PCIE_EVENT_LINKDOWN;
	mhi_ctx->event_reg.user = mhi_ctx;
	mhi_ctx->event_reg.mode = EP_PCIE_TRIGGER_CALLBACK;
	mhi_ctx->event_reg.callback = mhi_dev_sm_pcie_handler;

	rc = ep_pcie_register_event(mhi_ctx->phandle, &mhi_ctx->event_reg);
	if (rc) {
				pr_err("ipa enable failed\n");
		pr_err("Failed to register for events from PCIe\n");
		return rc;
	}

			rc = mhi_dev_ring_init(mhi_ctx);
			if (rc)
				return rc;
	pr_err("Registering with IPA\n");

			mhi_uci_init();
	rc = ipa_register_ipa_ready_cb(mhi_ring_init_cb, mhi_ctx);
	if (rc < 0) {
		if (rc == -EEXIST) {
			mhi_ring_init_cb(mhi_ctx);
		} else {
			pr_err("Error calling IPA cb with %d\n", rc);
			return rc;
+1 −1
Original line number Diff line number Diff line
@@ -254,7 +254,7 @@ int mhi_dev_process_ring(struct mhi_dev_ring *ring)
		mhi_dev_ring_inc_index(ring, ring->rd_offset);
	}

	if !(ring->rd_offset == ring->wr_offset) {
	if (!(ring->rd_offset == ring->wr_offset)) {
		mhi_log(MHI_MSG_ERROR,
				"Error with the rd offset/wr offset\n");
		return -EINVAL;
+2 −1
Original line number Diff line number Diff line
@@ -448,7 +448,8 @@ static int mhi_sm_change_to_M0(void)
		MHI_SM_DBG("Nothing to do, already in M0 state\n");
		res = 0;
		goto exit;
	} else if (old_state == MHI_DEV_M3_STATE) {
	} else if (old_state == MHI_DEV_M3_STATE ||
				old_state == MHI_DEV_READY_STATE) {
		/*  Retrieve MHI configuration*/
		res = mhi_dev_config_outbound_iatu(mhi_sm_ctx->mhi_dev);
		if (res) {