@@ -159,6 +159,7 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl)
error_exit_rddm:
dev_err(dev, "RDDM transfer failed. Current EE: %s\n",
TO_MHI_EXEC_STR(ee));
+ mhi_debug_reg_dump(mhi_cntrl);
return -EIO;
}
@@ -168,6 +169,7 @@ int mhi_download_rddm_image(struct mhi_controller *mhi_cntrl, bool in_panic)
{
void __iomem *base = mhi_cntrl->bhie;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
+ rwlock_t *pm_lock = &mhi_cntrl->pm_lock;
struct mhi_buf *mhi_buf = NULL;
u32 rx_status;
int ret;
@@ -217,6 +219,15 @@ int mhi_download_rddm_image(struct mhi_controller *mhi_cntrl, bool in_panic)
dma_unmap_single(mhi_cntrl->cntrl_dev, mhi_buf->dma_addr,
mhi_buf->len, DMA_TO_DEVICE);
+ if (ret) {
+ dev_err(dev, "RDDM transfer failed. RXVEC_STATUS: 0x%x\n",
+ rx_status);
+ read_lock_bh(pm_lock);
+ if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
+ mhi_debug_reg_dump(mhi_cntrl);
+ read_unlock_bh(pm_lock);
+ }
+
return ret;
}
EXPORT_SYMBOL_GPL(mhi_download_rddm_image);
@@ -263,8 +274,22 @@ static int mhi_fw_load_bhie(struct mhi_controller *mhi_cntrl,
&tx_status) || tx_status,
msecs_to_jiffies(mhi_cntrl->timeout_ms));
if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) ||
- tx_status != BHIE_TXVECSTATUS_STATUS_XFER_COMPL)
+ tx_status != BHIE_TXVECSTATUS_STATUS_XFER_COMPL) {
+ dev_err(dev, "Upper:0x%x Lower:0x%x len:0x%zx sequence:%u\n",
+ upper_32_bits(mhi_buf->dma_addr),
+ lower_32_bits(mhi_buf->dma_addr),
+ mhi_buf->len, sequence_id);
+
+ dev_err(dev, "MHI pm_state: %s tx_status: %d ee: %s\n",
+ to_mhi_pm_state_str(mhi_cntrl->pm_state), tx_status,
+ TO_MHI_EXEC_STR(mhi_get_exec_env(mhi_cntrl)));
+
+ read_lock_bh(pm_lock);
+ if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
+ mhi_debug_reg_dump(mhi_cntrl);
+ read_unlock_bh(pm_lock);
return -EIO;
+ }
return (!ret) ? -ETIMEDOUT : 0;
}
@@ -273,21 +298,11 @@ static int mhi_fw_load_bhi(struct mhi_controller *mhi_cntrl,
dma_addr_t dma_addr,
size_t size)
{
- u32 tx_status, val, session_id;
- int i, ret;
+ u32 tx_status, session_id;
+ int ret;
void __iomem *base = mhi_cntrl->bhi;
rwlock_t *pm_lock = &mhi_cntrl->pm_lock;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
- struct {
- char *name;
- u32 offset;
- } error_reg[] = {
- { "ERROR_CODE", BHI_ERRCODE },
- { "ERROR_DBG1", BHI_ERRDBG1 },
- { "ERROR_DBG2", BHI_ERRDBG2 },
- { "ERROR_DBG3", BHI_ERRDBG3 },
- { NULL },
- };
read_lock_bh(pm_lock);
if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
@@ -319,16 +334,8 @@ static int mhi_fw_load_bhi(struct mhi_controller *mhi_cntrl,
if (tx_status == BHI_STATUS_ERROR) {
dev_err(dev, "Image transfer failed\n");
read_lock_bh(pm_lock);
- if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
- for (i = 0; error_reg[i].name; i++) {
- ret = mhi_read_reg(mhi_cntrl, base,
- error_reg[i].offset, &val);
- if (ret)
- break;
- dev_err(dev, "Reg: %s value: 0x%x\n",
- error_reg[i].name, val);
- }
- }
+ if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
+ mhi_debug_reg_dump(mhi_cntrl);
read_unlock_bh(pm_lock);
goto invalid_pm_state;
}
@@ -1707,3 +1707,68 @@ int mhi_get_channel_doorbell_offset(struct mhi_controller *mhi_cntrl, u32 *chdb_
return 0;
}
EXPORT_SYMBOL_GPL(mhi_get_channel_doorbell_offset);
+
+void mhi_debug_reg_dump(struct mhi_controller *mhi_cntrl)
+{
+ enum mhi_state state;
+ enum mhi_ee_type ee;
+ int i, ret;
+ u32 val;
+ void __iomem *mhi_base = mhi_cntrl->regs;
+ void __iomem *bhi_base = mhi_cntrl->bhi;
+ void __iomem *bhie_base = mhi_cntrl->bhie;
+ void __iomem *wake_db = mhi_cntrl->wake_db;
+ struct {
+ const char *name;
+ int offset;
+ void *base;
+ } debug_reg[] = {
+ { "MHI_CNTRL", MHICTRL, mhi_base},
+ { "MHI_STATUS", MHISTATUS, mhi_base},
+ { "MHI_WAKE_DB", 0, wake_db},
+ { "BHI_EXECENV", BHI_EXECENV, bhi_base},
+ { "BHI_STATUS", BHI_STATUS, bhi_base},
+ { "BHI_ERRCODE", BHI_ERRCODE, bhi_base},
+ { "BHI_ERRDBG1", BHI_ERRDBG1, bhi_base},
+ { "BHI_ERRDBG2", BHI_ERRDBG2, bhi_base},
+ { "BHI_ERRDBG3", BHI_ERRDBG3, bhi_base},
+ { "BHIE_TXVEC_DB", BHIE_TXVECDB_OFFS, bhie_base},
+ { "BHIE_TXVEC_STATUS", BHIE_TXVECSTATUS_OFFS, bhie_base},
+ { "BHIE_RXVEC_DB", BHIE_RXVECDB_OFFS, bhie_base},
+ { "BHIE_RXVEC_STATUS", BHIE_RXVECSTATUS_OFFS, bhie_base},
+ { "BHIE_IMGTXDB", BHI_IMGTXDB, bhie_base},
+ { NULL },
+ };
+
+ dev_info(&mhi_cntrl->mhi_dev->dev,
+ "host pm_state:%s dev_state:%s ee:%s\n",
+ to_mhi_pm_state_str(mhi_cntrl->pm_state),
+ mhi_state_str(mhi_cntrl->dev_state),
+ TO_MHI_EXEC_STR(mhi_cntrl->ee));
+
+ state = mhi_get_mhi_state(mhi_cntrl);
+
+ if (!mhi_cntrl->bhi) {
+ dev_err(&mhi_cntrl->mhi_dev->dev,
+ "BHI not initialized, failed to dump debug registers\n");
+ return;
+ }
+
+ ee = mhi_get_exec_env(mhi_cntrl);
+
+ dev_info(&mhi_cntrl->mhi_dev->dev,
+ "device ee:%s dev_state:%s\n", TO_MHI_EXEC_STR(ee),
+ mhi_state_str(state));
+
+ for (i = 0; debug_reg[i].name; i++) {
+ if (!debug_reg[i].base)
+ continue;
+
+ ret = mhi_read_reg(mhi_cntrl, debug_reg[i].base,
+ debug_reg[i].offset, &val);
+ dev_info(&mhi_cntrl->mhi_dev->dev,
+ "reg:%s val:0x%x, ret:%d\n", debug_reg[i].name, val,
+ ret);
+ }
+}
+EXPORT_SYMBOL_GPL(mhi_debug_reg_dump);
@@ -1267,8 +1267,10 @@ int mhi_sync_power_up(struct mhi_controller *mhi_cntrl)
msecs_to_jiffies(timeout_ms));
ret = (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -ETIMEDOUT;
- if (ret)
+ if (ret) {
+ mhi_debug_reg_dump(mhi_cntrl);
mhi_power_down(mhi_cntrl, false);
+ }
return ret;
}
@@ -834,4 +834,9 @@ bool mhi_queue_is_full(struct mhi_device *mhi_dev, enum dma_data_direction dir);
*/
int mhi_get_channel_doorbell_offset(struct mhi_controller *mhi_cntrl, u32 *chdb_offset);
+/**
+ * mhi_debug_reg_dump - dump MHI registers for debug purpose
+ * @mhi_cntrl: MHI controller
+ */
+void mhi_debug_reg_dump(struct mhi_controller *mhi_cntrl);
#endif /* _MHI_H_ */