// SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
/* Observed on some targets that after SOC_GLOBAL_RESET, MHISTATUS * has SYSERR bit set and thus need to set MHICTRL_RESET * to clear SYSERR.
*/
ath12k_pci_write32(ab, MHICTRL, MHICTRL_RESET_MASK);
staticchar *ath12k_mhi_op_callback_to_str(enum mhi_callback reason)
{ switch (reason) { case MHI_CB_IDLE: return"MHI_CB_IDLE"; case MHI_CB_PENDING_DATA: return"MHI_CB_PENDING_DATA"; case MHI_CB_LPM_ENTER: return"MHI_CB_LPM_ENTER"; case MHI_CB_LPM_EXIT: return"MHI_CB_LPM_EXIT"; case MHI_CB_EE_RDDM: return"MHI_CB_EE_RDDM"; case MHI_CB_EE_MISSION_MODE: return"MHI_CB_EE_MISSION_MODE"; case MHI_CB_SYS_ERROR: return"MHI_CB_SYS_ERROR"; case MHI_CB_FATAL_ERROR: return"MHI_CB_FATAL_ERROR"; case MHI_CB_BW_REQ: return"MHI_CB_BW_REQ"; default: return"UNKNOWN";
}
}
ath12k_dbg(ab, ATH12K_DBG_BOOT, "mhi notify status reason %s\n",
ath12k_mhi_op_callback_to_str(cb));
switch (cb) { case MHI_CB_SYS_ERROR:
ath12k_warn(ab, "firmware crashed: MHI_CB_SYS_ERROR\n"); break; case MHI_CB_EE_RDDM: if (ab_pci->mhi_pre_cb == MHI_CB_EE_RDDM) {
ath12k_dbg(ab, ATH12K_DBG_BOOT, "do not queue again for consecutive RDDM event\n"); break;
}
staticchar *ath12k_mhi_state_to_str(enum ath12k_mhi_state mhi_state)
{ switch (mhi_state) { case ATH12K_MHI_INIT: return"INIT"; case ATH12K_MHI_DEINIT: return"DEINIT"; case ATH12K_MHI_POWER_ON: return"POWER_ON"; case ATH12K_MHI_POWER_OFF: return"POWER_OFF"; case ATH12K_MHI_POWER_OFF_KEEP_DEV: return"POWER_OFF_KEEP_DEV"; case ATH12K_MHI_FORCE_POWER_OFF: return"FORCE_POWER_OFF"; case ATH12K_MHI_SUSPEND: return"SUSPEND"; case ATH12K_MHI_RESUME: return"RESUME"; case ATH12K_MHI_TRIGGER_RDDM: return"TRIGGER_RDDM"; case ATH12K_MHI_RDDM_DONE: return"RDDM_DONE"; default: return"UNKNOWN";
}
};
switch (mhi_state) { case ATH12K_MHI_INIT: if (!test_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state)) return 0; break; case ATH12K_MHI_DEINIT: case ATH12K_MHI_POWER_ON: if (test_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state) &&
!test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state)) return 0; break; case ATH12K_MHI_FORCE_POWER_OFF: if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state)) return 0; break; case ATH12K_MHI_POWER_OFF: case ATH12K_MHI_POWER_OFF_KEEP_DEV: case ATH12K_MHI_SUSPEND: if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state) &&
!test_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state)) return 0; break; case ATH12K_MHI_RESUME: if (test_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state)) return 0; break; case ATH12K_MHI_TRIGGER_RDDM: if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state) &&
!test_bit(ATH12K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state)) return 0; break; case ATH12K_MHI_RDDM_DONE: return 0; default:
ath12k_err(ab, "unhandled mhi state: %s(%d)\n",
ath12k_mhi_state_to_str(mhi_state), mhi_state);
}
ath12k_err(ab, "failed to set mhi state %s(%d) in current mhi state (0x%lx)\n",
ath12k_mhi_state_to_str(mhi_state), mhi_state,
ab_pci->mhi_state);
switch (mhi_state) { case ATH12K_MHI_INIT:
ret = mhi_prepare_for_power_up(ab_pci->mhi_ctrl); break; case ATH12K_MHI_DEINIT:
mhi_unprepare_after_power_down(ab_pci->mhi_ctrl);
ret = 0; break; case ATH12K_MHI_POWER_ON: /* In case of resume, QRTR's resume_early() is called * right after ath12k' resume_early(). Since QRTR requires * MHI mission mode state when preparing IPCR channels * (see ee_mask of that channel), we need to use the 'sync' * version here to make sure MHI is in that state when we * return. Or QRTR might resume before that state comes, * and as a result it fails. * * The 'sync' version works for non-resume (normal power on) * case as well.
*/
ret = mhi_sync_power_up(ab_pci->mhi_ctrl); break; case ATH12K_MHI_POWER_OFF:
mhi_power_down(ab_pci->mhi_ctrl, true);
ret = 0; break; case ATH12K_MHI_POWER_OFF_KEEP_DEV:
mhi_power_down_keep_dev(ab_pci->mhi_ctrl, true);
ret = 0; break; case ATH12K_MHI_FORCE_POWER_OFF:
mhi_power_down(ab_pci->mhi_ctrl, false);
ret = 0; break; case ATH12K_MHI_SUSPEND:
ret = mhi_pm_suspend(ab_pci->mhi_ctrl); break; case ATH12K_MHI_RESUME:
ret = mhi_pm_resume(ab_pci->mhi_ctrl); break; case ATH12K_MHI_TRIGGER_RDDM:
ret = mhi_force_rddm_mode(ab_pci->mhi_ctrl); break; case ATH12K_MHI_RDDM_DONE: break; default:
ath12k_err(ab, "unhandled MHI state (%d)\n", mhi_state);
ret = -EINVAL;
}
if (ret) goto out;
ath12k_mhi_set_state_bit(ab_pci, mhi_state);
return 0;
out:
ath12k_err(ab, "failed to set mhi state: %s(%d)\n",
ath12k_mhi_state_to_str(mhi_state), mhi_state); return ret;
}
int ath12k_mhi_start(struct ath12k_pci *ab_pci)
{ int ret;
ret = ath12k_mhi_set_state(ab_pci, ATH12K_MHI_INIT); if (ret) goto out;
ret = ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_ON); if (ret) goto out;
return 0;
out: return ret;
}
void ath12k_mhi_stop(struct ath12k_pci *ab_pci, bool is_suspend)
{ /* During suspend we need to use mhi_power_down_keep_dev() * workaround, otherwise ath12k_core_resume() will timeout * during resume.
*/ if (is_suspend)
ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_OFF_KEEP_DEV); else
ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_OFF);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.