* [PATCH 1/3] dt-bindings: soundwire: qcom: describe multi-master
2026-09-11 8:21 [PATCH 0/3] soundwire: qcom: add multi-master support Srinivas Kandagatla
@ 2026-09-11 8:21 ` Srinivas Kandagatla
2026-09-11 8:21 ` [PATCH 2/3] soundwire: qcom: add multi-master support Srinivas Kandagatla
2026-09-11 8:21 ` [PATCH 3/3] soundwire: qcom: program MM_SYNC for multi-master Srinivas Kandagatla
2 siblings, 0 replies; 5+ messages in thread
From: Srinivas Kandagatla @ 2026-09-11 8:21 UTC (permalink / raw)
To: robh, vkoul
Cc: krzk+dt, conor+dt, srini, yung-chuan.liao, pierre-louis.bossart,
prasad.kumpatla, jingyi.wang, sibi.sankar, quic_srivasam,
linux-arm-msm, devicetree, linux-kernel, linux-sound,
Srinivas Kandagatla
v3.1.0+ Qualcomm SoundWire IPs can be paired to expose one logical
bus with more than two DATA lanes. Add the two properties that
describe such a pair:
qcom,multi-master-mode role in the pair ("primary" or "dependent")
qcom,multi-master-peer <phandle, bus-port-offset> to the other IP
Both nodes carry both properties.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
---
.../bindings/soundwire/qcom,soundwire.yaml | 109 ++++++++++++++++--
1 file changed, 100 insertions(+), 9 deletions(-)
diff --git a/Documentation/devicetree/bindings/soundwire/qcom,soundwire.yaml b/Documentation/devicetree/bindings/soundwire/qcom,soundwire.yaml
index 8e6973fa229c..6cf3285ded92 100644
--- a/Documentation/devicetree/bindings/soundwire/qcom,soundwire.yaml
+++ b/Documentation/devicetree/bindings/soundwire/qcom,soundwire.yaml
@@ -215,6 +215,36 @@ properties:
maximum: 4
- const: 0xff
+ qcom,multi-master-mode:
+ description:
+ Role in v3.1.0+ multi-master mode. Both nodes set this; the
+ primary owns SWR_CLK, the dependent contributes DATA lanes
+ only.
+ $ref: /schemas/types.yaml#/definitions/string
+ enum: [ primary, dependent ]
+
+ qcom,multi-master-peer:
+ description:
+ Peers in multi-master mode. Each entry is a
+ <peer-phandle, bus-port-offset> pair. Peer N's DPn slots
+ 1, 2, 3, ... occupy bus ports (offset+1), (offset+2), ...
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ items:
+ - description: peer phandle
+ - description: bus port offset (last primary-local port)
+ minItems: 1
+
+ num-lanes:
+ description:
+ Number of DATA lanes this IP exposes locally. Required in
+ multi-master mode; on the primary it defines the boundary
+ between local bus lanes (0..num-lanes-1) and lanes contributed
+ by the dependent.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+ maximum: 8
+
label:
maxItems: 1
@@ -224,21 +254,82 @@ required:
- interrupts
- clocks
- clock-names
- - '#sound-dai-cells'
- '#address-cells'
- '#size-cells'
- - qcom,ports-offset1
- - qcom,ports-offset2
-
-oneOf:
- - required:
- - qcom,ports-sinterval-low
- - required:
- - qcom,ports-sinterval
allOf:
- $ref: soundwire-controller.yaml#
+ # Single-master (no qcom,multi-master-mode): needs port config.
+ - if:
+ not:
+ required:
+ - qcom,multi-master-mode
+ then:
+ required:
+ - '#sound-dai-cells'
+ - qcom,ports-offset1
+ - qcom,ports-offset2
+ oneOf:
+ - required:
+ - qcom,ports-sinterval-low
+ - required:
+ - qcom,ports-sinterval
+
+ # Multi-master primary: drives the bus, needs port config + MM props.
+ - if:
+ properties:
+ qcom,multi-master-mode:
+ const: primary
+ required:
+ - qcom,multi-master-mode
+ then:
+ properties:
+ compatible:
+ contains:
+ const: qcom,soundwire-v3.1.0
+ required:
+ - '#sound-dai-cells'
+ - qcom,ports-offset1
+ - qcom,ports-offset2
+ - qcom,multi-master-peer
+ - num-lanes
+ oneOf:
+ - required:
+ - qcom,ports-sinterval-low
+ - required:
+ - qcom,ports-sinterval
+
+ # Multi-master dependent: contributes DATA lanes
+ - if:
+ properties:
+ qcom,multi-master-mode:
+ const: dependent
+ required:
+ - qcom,multi-master-mode
+ then:
+ properties:
+ compatible:
+ contains:
+ const: qcom,soundwire-v3.1.0
+ '#sound-dai-cells': false
+ qcom,din-ports: false
+ qcom,dout-ports: false
+ qcom,ports-word-length: false
+ qcom,ports-sinterval-low: false
+ qcom,ports-sinterval: false
+ qcom,ports-offset1: false
+ qcom,ports-offset2: false
+ qcom,ports-lane-control: false
+ qcom,ports-block-pack-mode: false
+ qcom,ports-hstart: false
+ qcom,ports-hstop: false
+ qcom,ports-block-group-count: false
+ qcom,ports-ch-mask: false
+ required:
+ - qcom,multi-master-peer
+ - num-lanes
+
unevaluatedProperties: false
examples:
--
2.53.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH 2/3] soundwire: qcom: add multi-master support
2026-09-11 8:21 [PATCH 0/3] soundwire: qcom: add multi-master support Srinivas Kandagatla
2026-09-11 8:21 ` [PATCH 1/3] dt-bindings: soundwire: qcom: describe multi-master Srinivas Kandagatla
@ 2026-09-11 8:21 ` Srinivas Kandagatla
2026-09-14 17:21 ` Pierre-Louis Bossart
2026-09-11 8:21 ` [PATCH 3/3] soundwire: qcom: program MM_SYNC for multi-master Srinivas Kandagatla
2 siblings, 1 reply; 5+ messages in thread
From: Srinivas Kandagatla @ 2026-09-11 8:21 UTC (permalink / raw)
To: robh, vkoul
Cc: krzk+dt, conor+dt, srini, yung-chuan.liao, pierre-louis.bossart,
prasad.kumpatla, jingyi.wang, sibi.sankar, quic_srivasam,
linux-arm-msm, devicetree, linux-kernel, linux-sound,
Srinivas Kandagatla
v3.1.0+ Qualcomm SoundWire IPs can be paired to expose one logical
bus with more than two DATA lanes. One IP owns SWR_CLK and drives
the bus; the other contributes DATA lanes only.
Support this pairing on the driver side. A device link between the
two IPs enforces correct unbind ordering and keeps the peer resumed
while the primary is active.
Single-master deployments (no qcom,multi-master-mode in DT) are
unaffected.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
---
drivers/soundwire/qcom.c | 171 +++++++++++++++++++++++++++++++++++----
1 file changed, 156 insertions(+), 15 deletions(-)
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 35ffffd541bd..a5f39868161a 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -10,6 +10,7 @@
#include <linux/debugfs.h>
#include <linux/of.h>
#include <linux/of_irq.h>
+#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>
@@ -111,6 +112,7 @@
#define SWRM_DPn_PORT_HCTRL_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DPn_BLOCK_CTRL3_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DPn_SAMPLECTRL2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
+#define SWRM_DPn_SLOT_STRIDE 0x100
#define SWR_V1_3_MSTR_MAX_REG_ADDR 0x1740
#define SWR_V2_0_MSTR_MAX_REG_ADDR 0x50ac
@@ -192,6 +194,13 @@ struct qcom_swrm_ctrl {
const unsigned int *reg_layout;
void __iomem *mmio;
struct reset_control *audio_cgcr;
+ u8 num_lanes;
+ bool is_dependent;
+ struct qcom_swrm_ctrl *peer_ctrl;
+ u8 peer_first_lane;
+ u8 num_peer_lanes;
+ bool is_primary;
+ u32 peer_dpn_offset;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
#endif
@@ -1040,9 +1049,41 @@ static int qcom_swrm_pre_bank_switch(struct sdw_bus *bus)
u32p_replace_bits(&val, ctrl->cols_index, SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK);
u32p_replace_bits(&val, ctrl->rows_index, SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK);
+ if (ctrl->peer_ctrl)
+ ctrl->peer_ctrl->reg_write(ctrl->peer_ctrl, reg, val);
+
return ctrl->reg_write(ctrl, reg, val);
}
+static struct qcom_swrm_ctrl *
+qcom_swrm_port_target(struct qcom_swrm_ctrl *ctrl, u8 port_num, u32 *reg)
+{
+ u8 lane = ctrl->pconfig[port_num].lane_control;
+
+ if (ctrl->peer_ctrl && lane >= ctrl->peer_first_lane &&
+ lane < ctrl->peer_first_lane + ctrl->num_peer_lanes) {
+ *reg -= ctrl->peer_dpn_offset;
+ return ctrl->peer_ctrl;
+ }
+ return ctrl;
+}
+
+static int qcom_swrm_port_reg_write(struct qcom_swrm_ctrl *ctrl, u8 port_num,
+ u32 reg, u32 val)
+{
+ struct qcom_swrm_ctrl *tgt = qcom_swrm_port_target(ctrl, port_num, ®);
+
+ return tgt->reg_write(tgt, reg, val);
+}
+
+static int qcom_swrm_port_reg_read(struct qcom_swrm_ctrl *ctrl, u8 port_num,
+ u32 reg, u32 *val)
+{
+ struct qcom_swrm_ctrl *tgt = qcom_swrm_port_target(ctrl, port_num, ®);
+
+ return tgt->reg_read(tgt, reg, val);
+}
+
static int qcom_swrm_port_params(struct sdw_bus *bus,
struct sdw_port_params *p_params,
unsigned int bank)
@@ -1050,8 +1091,9 @@ static int qcom_swrm_port_params(struct sdw_bus *bus,
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
u32 offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL_1];
- return ctrl->reg_write(ctrl, SWRM_DPn_BLOCK_CTRL_1(offset, p_params->num),
- p_params->bps - 1);
+ return qcom_swrm_port_reg_write(ctrl, p_params->num,
+ SWRM_DPn_BLOCK_CTRL_1(offset, p_params->num),
+ p_params->bps - 1);
}
static int qcom_swrm_transport_params(struct sdw_bus *bus,
@@ -1072,7 +1114,7 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
value |= pcfg->off2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT;
value |= pcfg->si & 0xff;
- ret = ctrl->reg_write(ctrl, reg, value);
+ ret = qcom_swrm_port_reg_write(ctrl, params->port_num, reg, value);
if (ret)
goto err;
@@ -1081,7 +1123,7 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
value = (pcfg->si >> 8) & 0xff;
reg = SWRM_DPn_SAMPLECTRL2_BANK(offset, params->port_num, bank);
- ret = ctrl->reg_write(ctrl, reg, value);
+ ret = qcom_swrm_port_reg_write(ctrl, params->port_num, reg, value);
if (ret)
goto err;
}
@@ -1091,7 +1133,10 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
reg = SWRM_DPn_PORT_CTRL_2_BANK(offset, params->port_num, bank);
value = pcfg->lane_control;
- ret = ctrl->reg_write(ctrl, reg, value);
+ if (ctrl->peer_ctrl && value >= ctrl->peer_first_lane &&
+ value < ctrl->peer_first_lane + ctrl->num_peer_lanes)
+ value -= ctrl->peer_first_lane;
+ ret = qcom_swrm_port_reg_write(ctrl, params->port_num, reg, value);
if (ret)
goto err;
}
@@ -1102,7 +1147,7 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
reg = SWRM_DPn_BLOCK_CTRL2_BANK(offset, params->port_num, bank);
value = pcfg->blk_group_count;
- ret = ctrl->reg_write(ctrl, reg, value);
+ ret = qcom_swrm_port_reg_write(ctrl, params->port_num, reg, value);
if (ret)
goto err;
}
@@ -1112,10 +1157,10 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
if (pcfg->hstart != SWR_INVALID_PARAM && pcfg->hstop != SWR_INVALID_PARAM) {
value = (pcfg->hstop << 4) | pcfg->hstart;
- ret = ctrl->reg_write(ctrl, reg, value);
+ ret = qcom_swrm_port_reg_write(ctrl, params->port_num, reg, value);
} else {
value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL;
- ret = ctrl->reg_write(ctrl, reg, value);
+ ret = qcom_swrm_port_reg_write(ctrl, params->port_num, reg, value);
}
if (ret)
@@ -1124,7 +1169,8 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
if (pcfg->bp_mode != SWR_INVALID_PARAM) {
offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL3_BANK];
reg = SWRM_DPn_BLOCK_CTRL3_BANK(offset, params->port_num, bank);
- ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode);
+ ret = qcom_swrm_port_reg_write(ctrl, params->port_num, reg,
+ pcfg->bp_mode);
}
err:
@@ -1142,14 +1188,14 @@ static int qcom_swrm_port_enable(struct sdw_bus *bus,
reg = SWRM_DPn_PORT_CTRL_BANK(offset, enable_ch->port_num, bank);
- ctrl->reg_read(ctrl, reg, &val);
+ qcom_swrm_port_reg_read(ctrl, enable_ch->port_num, reg, &val);
if (enable_ch->enable)
val |= (enable_ch->ch_mask << SWRM_DP_PORT_CTRL_EN_CHAN_SHFT);
else
val &= ~(0xff << SWRM_DP_PORT_CTRL_EN_CHAN_SHFT);
- return ctrl->reg_write(ctrl, reg, val);
+ return qcom_swrm_port_reg_write(ctrl, enable_ch->port_num, reg, val);
}
static const struct sdw_master_port_ops qcom_swrm_port_ops = {
@@ -1562,6 +1608,68 @@ static int swrm_reg_show(struct seq_file *s_file, void *data)
DEFINE_SHOW_ATTRIBUTE(swrm_reg);
#endif
+static int qcom_swrm_multi_master_setup(struct qcom_swrm_ctrl *ctrl)
+{
+ struct of_phandle_args args;
+ struct qcom_swrm_ctrl *peer;
+ struct platform_device *pdev;
+ u32 offset;
+ int ret;
+
+ ret = of_parse_phandle_with_fixed_args(ctrl->dev->of_node,
+ "qcom,multi-master-peer",
+ 1, 0, &args);
+ if (ret)
+ return -EINVAL;
+
+ pdev = of_find_device_by_node(args.np);
+ of_node_put(args.np);
+ if (!pdev)
+ return -EPROBE_DEFER;
+
+ if (pdev->dev.driver != ctrl->dev->driver) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ peer = platform_get_drvdata(pdev);
+ if (!peer || !peer->is_dependent) {
+ ret = -EPROBE_DEFER;
+ goto out;
+ }
+
+ if (!ctrl->num_lanes || !peer->num_lanes ||
+ ctrl->num_lanes + peer->num_lanes > SDW_MAX_LANES) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ offset = args.args[0];
+ if (offset < ctrl->num_lanes) {
+ dev_err(ctrl->dev, "qcom,multi-master-peer: offset %u < num-lanes %u\n",
+ offset, ctrl->num_lanes);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!device_link_add(ctrl->dev, &pdev->dev,
+ DL_FLAG_AUTOREMOVE_CONSUMER | DL_FLAG_PM_RUNTIME)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ctrl->peer_ctrl = peer;
+ peer->peer_ctrl = ctrl;
+ ctrl->peer_first_lane = ctrl->num_lanes;
+ ctrl->num_peer_lanes = peer->num_lanes;
+ ctrl->peer_dpn_offset = offset * SWRM_DPn_SLOT_STRIDE;
+
+ ret = 0;
+out:
+ put_device(&pdev->dev);
+ return ret;
+}
+
static int qcom_swrm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1576,6 +1684,9 @@ static int qcom_swrm_probe(struct platform_device *pdev)
if (!ctrl)
return -ENOMEM;
+ if (!of_property_read_u32(dev->of_node, "num-lanes", &val))
+ ctrl->num_lanes = val;
+
memset(ctrl->page1_cache, 0xff, sizeof(ctrl->page1_cache));
memset(ctrl->page2_cache, 0xff, sizeof(ctrl->page2_cache));
@@ -1636,9 +1747,19 @@ static int qcom_swrm_probe(struct platform_device *pdev)
ctrl->bus.compute_params = &qcom_swrm_compute_params;
ctrl->bus.clk_stop_timeout = 300;
- ret = qcom_swrm_get_port_config(ctrl);
- if (ret)
- goto err_clk;
+ if (of_property_match_string(dev->of_node, "qcom,multi-master-mode",
+ "dependent") < 0) {
+ ret = qcom_swrm_get_port_config(ctrl);
+ if (ret)
+ goto err_clk;
+ }
+
+ if (of_property_match_string(dev->of_node, "qcom,multi-master-mode", "primary") >= 0) {
+ ret = qcom_swrm_multi_master_setup(ctrl);
+ if (ret)
+ goto err_clk;
+ ctrl->is_primary = true;
+ }
params = &ctrl->bus.params;
params->max_dr_freq = DEFAULT_CLK_FREQ;
@@ -1689,6 +1810,16 @@ static int qcom_swrm_probe(struct platform_device *pdev)
ctrl->bus.controller_id = val;
}
+ if (of_property_match_string(dev->of_node, "qcom,multi-master-mode", "dependent") >= 0) {
+ ctrl->is_dependent = true;
+ dev_dbg(dev,
+ "Qualcomm SoundWire multi-master dependent v%x.%x.%x registered (%u lanes)\n",
+ (ctrl->version >> 24) & 0xff,
+ (ctrl->version >> 16) & 0xff,
+ ctrl->version & 0xffff, ctrl->num_lanes);
+ return 0;
+ }
+
ret = sdw_bus_master_add(&ctrl->bus, dev, dev->fwnode);
if (ret) {
dev_err(dev, "Failed to register Soundwire controller (%d)\n",
@@ -1696,7 +1827,11 @@ static int qcom_swrm_probe(struct platform_device *pdev)
goto err_clk;
}
+ if (ctrl->is_primary && ctrl->peer_ctrl)
+ qcom_swrm_init(ctrl->peer_ctrl);
+
qcom_swrm_init(ctrl);
+
wait_for_completion_timeout(&ctrl->enumeration,
msecs_to_jiffies(TIMEOUT_MS));
ret = qcom_swrm_register_dais(ctrl);
@@ -1733,7 +1868,13 @@ static void qcom_swrm_remove(struct platform_device *pdev)
{
struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(&pdev->dev);
- sdw_bus_master_delete(&ctrl->bus);
+ if (ctrl->is_primary && ctrl->peer_ctrl) {
+ ctrl->peer_ctrl->peer_ctrl = NULL;
+ ctrl->peer_ctrl = NULL;
+ }
+
+ if (!ctrl->is_dependent)
+ sdw_bus_master_delete(&ctrl->bus);
clk_disable_unprepare(ctrl->hclk);
}
--
2.53.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH 3/3] soundwire: qcom: program MM_SYNC for multi-master
2026-09-11 8:21 [PATCH 0/3] soundwire: qcom: add multi-master support Srinivas Kandagatla
2026-09-11 8:21 ` [PATCH 1/3] dt-bindings: soundwire: qcom: describe multi-master Srinivas Kandagatla
2026-09-11 8:21 ` [PATCH 2/3] soundwire: qcom: add multi-master support Srinivas Kandagatla
@ 2026-09-11 8:21 ` Srinivas Kandagatla
2 siblings, 0 replies; 5+ messages in thread
From: Srinivas Kandagatla @ 2026-09-11 8:21 UTC (permalink / raw)
To: robh, vkoul
Cc: krzk+dt, conor+dt, srini, yung-chuan.liao, pierre-louis.bossart,
prasad.kumpatla, jingyi.wang, sibi.sankar, quic_srivasam,
linux-arm-msm, devicetree, linux-kernel, linux-sound,
Srinivas Kandagatla
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@oss.qualcomm.com>
---
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
^ permalink raw reply [flat|nested] 5+ messages in thread