Files
pmaports-rtwo/device/testing/linux-postmarketos-qcom-sm8550/ath12k-mhi-keep-awake.patch
T
snlavaiseandClaude Opus 5.5 8a87204d48 linux-postmarketos-qcom-sm8550: motorola-rtwo display, DP, WiFi, audio DSPs
Bring-up of the Moto Edge 40 Pro (rtwo) on the SM8550 kernel:

- dts: NT37705 DSI panel with DSC, Goodix GT9916P touch, ADSP/CDSP with
  pmic-glink (battery, UCSI), Adreno 740, WiFi (WCN7850/ath12k), physical
  keys, and USB-C DisplayPort (pmic-glink altmode -> PS5169 redriver ->
  FSA4480 -> QMP combo PHY -> mdss_dp0) following the sm8550-qrd layout.
- DP link capped at HBR (link-frequencies on &mdss_dp0_out): the DP->HDMI
  converter of a common USB-C hub trains fine at HBR2 but its HDMI output
  flickers and drops HPD; HBR x2 still covers 1080p60.
- new drivers: typec-mux-ps5169.c (Parade PS5169 redriver as typec
  switch/retimer), panel-novatek-nt37705.c.
- patches: msm DP invalid LTTPR caps + no push_idle with the link down
  (hardware reset on unplug), msm DSI keeps the panel DSC config, ath12k
  regd fixes and MHI keep-awake, ICC keepalive for the MDP fetch path.
- rtwo.config / config-motorola-rtwo.aarch64: options for all of the above.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DnHwDU5yL8L6qgPEN5CV5m
2026-09-26 20:02:55 -03:00

88 lines
3.2 KiB
Diff

Add ath12k.mhi_keep_awake to keep the WCN7850 out of MHI M1/M2.
Diagnostic for the rtwo WiFi bring-up. With CONFIG_ATH12K_DEBUG the log
shows that the firmware returns HTC credits for the WMI endpoint
normally (trailers on EP0, ~3 ms after each command) until the moment
the device reports M1 and the host moves it to M2 (MHI_CB_IDLE, 22 us
after the last credit is spent). After that the target sends nothing on
any endpoint and there is no RDDM/SYS_ERR, so it is asleep, not crashed.
WCN7850 uses shadow registers for the CE doorbells (below
ACCESS_ALWAYS_OFF), so those writes never go through pci_ops->wakeup().
mhi_keep_awake=1 takes an MHI device wake reference right after power
up and holds it until mhi_stop, so the device stays in M0. With it
off, MHI_CB_IDLE is logged at warn level to see when it happens.
--- a/drivers/net/wireless/ath/ath12k/pci.h 2026-09-22 20:54:12.225709859 -0300
+++ b/drivers/net/wireless/ath/ath12k/pci.h 2026-09-22 20:54:12.243985679 -0300
@@ -93,6 +93,7 @@
ATH12K_PCI_FLAG_IS_MSI_64,
ATH12K_PCI_ASPM_RESTORE,
ATH12K_PCI_FLAG_MULTI_MSI_VECTORS,
+ ATH12K_PCI_FLAG_MHI_KEEP_AWAKE,
};
struct ath12k_pci_ops {
--- a/drivers/net/wireless/ath/ath12k/mhi.c 2026-09-22 20:54:12.223301456 -0300
+++ b/drivers/net/wireless/ath/ath12k/mhi.c 2026-09-22 20:54:12.244083641 -0300
@@ -18,6 +18,16 @@
#define OTP_VALID_DUALMAC_BOARD_ID_MASK 0x1000
#define MHI_CB_INVALID 0xff
+/* rtwo bring-up: the WMI endpoint runs out of HTC credits at the exact
+ * moment the device reports M1 and the host moves it to M2
+ * (MHI_CB_IDLE); after that the target never sends anything again.
+ * Holding MHI device wake for the whole session keeps it in M0, to
+ * tell whether the M1/M2 transition is what loses the WMI doorbells.
+ */
+static bool ath12k_mhi_keep_awake;
+module_param_named(mhi_keep_awake, ath12k_mhi_keep_awake, bool, 0644);
+MODULE_PARM_DESC(mhi_keep_awake, "Hold MHI device wake while powered on (never enter M1/M2)");
+
void ath12k_mhi_set_mhictrl_reset(struct ath12k_base *ab)
{
u32 val;
@@ -148,6 +158,11 @@
case MHI_CB_SYS_ERROR:
ath12k_warn(ab, "firmware crashed: MHI_CB_SYS_ERROR\n");
break;
+ case MHI_CB_IDLE:
+ /* rtwo: log at warn level so it shows up without debug_mask */
+ ath12k_warn(ab, "mhi idle: device moved to M2 (keep_awake %d)\n",
+ test_bit(ATH12K_PCI_FLAG_MHI_KEEP_AWAKE, &ab_pci->flags));
+ break;
case MHI_CB_EE_RDDM:
if (ab_pci->mhi_pre_cb == MHI_CB_EE_RDDM) {
ath12k_dbg(ab, ATH12K_DBG_BOOT,
@@ -493,6 +508,20 @@
if (ret)
goto out;
+ if (ath12k_mhi_keep_awake) {
+ ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
+ if (ret) {
+ ath12k_warn(ab_pci->ab,
+ "mhi_keep_awake: failed to hold device wake: %d\n",
+ ret);
+ ret = 0;
+ } else {
+ set_bit(ATH12K_PCI_FLAG_MHI_KEEP_AWAKE, &ab_pci->flags);
+ ath12k_info(ab_pci->ab,
+ "mhi_keep_awake: holding device wake, M1/M2 disabled\n");
+ }
+ }
+
return 0;
out:
@@ -501,6 +530,9 @@
void ath12k_mhi_stop(struct ath12k_pci *ab_pci, bool is_suspend)
{
+ if (test_and_clear_bit(ATH12K_PCI_FLAG_MHI_KEEP_AWAKE, &ab_pci->flags))
+ mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
+
/* During suspend we need to use mhi_power_down_keep_dev()
* workaround, otherwise ath12k_core_resume() will timeout
* during resume.