[PATCH 3/3] soundwire: qcom: program MM_SYNC for multi-master
From: Srinivas Kandagatla
Date: Fri Sep 11 2026 - 04:29:34 EST
The primary and dependent frame generators must lock to a single
SWR_CLK for the shared bus to run. Program SWRM_V3_MM_SYNC_CONFIG
on both sides at init, and re-apply on resume as the register does
not survive a clock stop.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@xxxxxxxxxxxxxxxx>
---
drivers/soundwire/qcom.c | 47 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index a5f39868161a..3b9b1a53b082 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -46,6 +46,18 @@
#define SWRM_V3_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(23, 18)
#define SWRM_COMP_MASTER_ID 0x104
+
+#define SWRM_V3_MM_SYNC_CONFIG 0x108
+#define SWRM_V3_MM_SYNC_CONNECTED_MASTER_MASK GENMASK(15, 0)
+#define SWRM_V3_MM_SYNC_IS_DEPENDENT_MASTER BIT(16)
+#define SWRM_V3_MM_SYNC_MASK_CONTROL_BITS BIT(17)
+
+#define SWRM_V3_COMP_FEATURE_CFG 0x10
+#define SWRM_V3_COMP_FEATURE_CFG_BASE 0x00E
+#define SWRM_V3_COMP_FEATURE_CFG_FORCE_MODE_EN BIT(9)
+#define SWRM_V3_COMP_FEATURE_CFG_CLK_PIN_AVAIL BIT(10)
+#define SWRM_V3_COMP_FEATURE_CFG_CLK_STOP_EXEC_ON_CMD_IGNORE BIT(12)
+
#define SWRM_V1_3_INTERRUPT_STATUS 0x200
#define SWRM_V2_0_INTERRUPT_STATUS 0x5000
#define SWRM_INTERRUPT_STATUS_RMSK GENMASK(16, 0)
@@ -892,6 +904,37 @@ static bool swrm_wait_for_frame_gen_enabled(struct qcom_swrm_ctrl *ctrl)
return false;
}
+static void qcom_swrm_program_mm_sync(struct qcom_swrm_ctrl *ctrl)
+{
+ struct qcom_swrm_ctrl *peer = ctrl->peer_ctrl;
+ u32 conn_mask;
+
+ if (!peer)
+ return;
+
+ conn_mask = BIT(peer->bus.controller_id - 1) &
+ SWRM_V3_MM_SYNC_CONNECTED_MASTER_MASK;
+
+ if (ctrl->is_primary) {
+ ctrl->reg_write(ctrl, SWRM_V3_MM_SYNC_CONFIG, conn_mask);
+ ctrl->reg_write(ctrl, SWRM_V3_COMP_FEATURE_CFG,
+ SWRM_V3_COMP_FEATURE_CFG_BASE |
+ SWRM_V3_COMP_FEATURE_CFG_FORCE_MODE_EN |
+ SWRM_V3_COMP_FEATURE_CFG_CLK_PIN_AVAIL |
+ SWRM_V3_COMP_FEATURE_CFG_CLK_STOP_EXEC_ON_CMD_IGNORE);
+ return;
+ }
+
+ ctrl->reg_write(ctrl, SWRM_V3_MM_SYNC_CONFIG,
+ SWRM_V3_MM_SYNC_IS_DEPENDENT_MASTER |
+ SWRM_V3_MM_SYNC_MASK_CONTROL_BITS | conn_mask);
+
+ ctrl->reg_write(ctrl, SWRM_V3_COMP_FEATURE_CFG,
+ SWRM_V3_COMP_FEATURE_CFG_BASE |
+ SWRM_V3_COMP_FEATURE_CFG_FORCE_MODE_EN |
+ SWRM_V3_COMP_FEATURE_CFG_CLK_STOP_EXEC_ON_CMD_IGNORE);
+}
+
static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
{
u32 val;
@@ -918,6 +961,8 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
u32p_replace_bits(&val, SWRM_DEF_CMD_NO_PINGS, SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK);
ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val);
+ qcom_swrm_program_mm_sync(ctrl);
+
if (ctrl->version == SWRM_VERSION_1_7_0) {
ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, SWRM_EE_CPU);
ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL,
@@ -1909,6 +1954,8 @@ static int __maybe_unused swrm_runtime_resume(struct device *dev)
} else {
reset_control_reset(ctrl->audio_cgcr);
+ qcom_swrm_program_mm_sync(ctrl);
+
if (ctrl->version == SWRM_VERSION_1_7_0) {
ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, SWRM_EE_CPU);
ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL,
--
2.53.0