summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLoic Poulain <loic.poulain@linaro.org>2021-02-11 15:48:34 +0100
committerLoic Poulain <loic.poulain@linaro.org>2021-02-11 20:39:33 +0100
commit32f69ac6bc215c2f97f7c6db6dad279c652382f7 (patch)
tree24db6eb1006448cda390bdc4db01b162065088bc
parent2ecdddda7bbc542ddfcd572187a0b984c1dd4de1 (diff)
mhi: pci_generic: Ensure device readiness before starting MHI5.11.0-quectel-v4
The PCI device may have not been bound from cold boot and be in undefined state, or simply not yet ready for MHI operations. This change ensures that the MHI layer is reset to initial state and ready for MHI initialization and power up. Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
-rw-r--r--drivers/bus/mhi/pci_generic.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c
index 56bd9ed3ad8e..a1b296fda2d1 100644
--- a/drivers/bus/mhi/pci_generic.c
+++ b/drivers/bus/mhi/pci_generic.c
@@ -17,6 +17,8 @@
#include <linux/timer.h>
#include <linux/workqueue.h>
+#include "core/internal.h"
+
#define MHI_PCI_DEFAULT_BAR_NUM 0
#define MHI_POST_RESET_DELAY_MS 500
@@ -338,6 +340,7 @@ static int mhi_pci_claim(struct mhi_controller *mhi_cntrl,
return err;
}
mhi_cntrl->regs = pcim_iomap_table(pdev)[bar_num];
+ mhi_cntrl->bhi = mhi_cntrl->regs + readl(mhi_cntrl->regs + BHIOFF);
err = pci_set_dma_mask(pdev, dma_mask);
if (err) {
@@ -473,6 +476,31 @@ static void health_check(struct timer_list *t)
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
}
+static void __mhi_sw_reset(struct mhi_controller *mhi_cntrl)
+{
+ unsigned int max_wait_ready = 100;
+
+ if (MHI_IN_PBL(mhi_get_exec_env(mhi_cntrl))) {
+ /* nothing to do, ready for BHI */
+ return;
+ }
+
+ if (mhi_get_mhi_state(mhi_cntrl) >= MHI_STATE_M0) {
+ dev_warn(mhi_cntrl->cntrl_dev, "Need reset\n");
+ writel(MHICTRL_RESET_MASK, mhi_cntrl->regs + MHICTRL);
+ msleep(10);
+ }
+
+ while (mhi_get_mhi_state(mhi_cntrl) != MHI_STATE_READY) {
+ if (!max_wait_ready--) {
+ dev_warn(mhi_cntrl->cntrl_dev, "Not ready (state %u)\n",
+ mhi_get_mhi_state(mhi_cntrl));
+ break;
+ }
+ msleep(50);
+ }
+}
+
static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
const struct mhi_pci_dev_info *info = (struct mhi_pci_dev_info *) id->driver_data;
@@ -533,6 +561,9 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_unregister;
}
+ /* Before starting MHI, ensure device is in good initial state */
+ __mhi_sw_reset(mhi_cntrl);
+
err = mhi_sync_power_up(mhi_cntrl);
if (err) {
dev_err(&pdev->dev, "failed to power up MHI controller\n");
@@ -614,6 +645,8 @@ static void mhi_pci_reset_done(struct pci_dev *pdev)
return;
}
+ __mhi_sw_reset(mhi_cntrl);
+
err = mhi_sync_power_up(mhi_cntrl);
if (err) {
dev_err(&pdev->dev, "failed to power up MHI controller\n");