From 256170ffc3f936a971db9fc84757cd0df7e42555 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 24 Mar 2026 16:20:04 +0000 Subject: [PATCH 1/4] soundwire: Add bra_block_alignment property support Add a property to struct sdw_slave_prop equivalent to the Disco property "mipi-sdw-bra-mode-block-alignment". The SoundWire Disco specification defines this as: "The data payload size for this BRA Mode shall be an integer multiple of the value of this Property." Change-Id: I27ab84b0ed0f236a5eae58600400a4c386132480 Signed-off-by: Richard Fitzgerald Co-developed-by: Bard Liao Signed-off-by: Bard Liao --- drivers/soundwire/mipi_disco.c | 3 +++ include/linux/soundwire/sdw.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index c69b78cd0b6209..b122bd1e7321ba 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -471,6 +471,9 @@ int sdw_slave_read_prop(struct sdw_slave *slave) device_property_read_u32(dev, "mipi-sdw-sdca-interrupt-register-list", &prop->sdca_interrupt_register_list); + device_property_read_u32(dev, "mipi-sdw-bra-mode-block-alignment", + &prop->bra_block_alignment); + prop->commit_register_supported = mipi_device_property_read_bool(dev, "mipi-sdw-commit-register-supported"); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 0845182f75f9ab..edf8c41e48c88b 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -364,6 +364,8 @@ struct sdw_dpn_prop { * @commit_register_supported: is PCP_Commit register supported * @scp_int1_mask: SCP_INT1_MASK desired settings * @lane_maps: Lane mapping for the slave, only valid if lane_control_support is set + * @bra_block_alignment: If non-zero the length of data in a BRA frame must be + * a multiple of this number of bytes. * @clock_reg_supported: the Peripheral implements the clock base and scale * registers introduced with the SoundWire 1.2 specification. SDCA devices * do not need to set this boolean property as the registers are required. @@ -394,6 +396,7 @@ struct sdw_slave_prop { u8 commit_register_supported; u8 scp_int1_mask; u8 lane_maps[SDW_MAX_LANES]; + u32 bra_block_alignment; bool clock_reg_supported; bool use_domain_irq; }; From 14fb24db588369df4b4b3da9f426a10771926366 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 25 Mar 2026 09:54:54 +0800 Subject: [PATCH 2/4] soundwire: intel: handle Peripheral bra_block_alignment The data pre frame size should be a multiple of bra_block_alignment. Signed-off-by: Bard Liao --- drivers/soundwire/cadence_master.c | 11 +++++++++++ drivers/soundwire/cadence_master.h | 1 + drivers/soundwire/intel_ace2x.c | 2 ++ 3 files changed, 14 insertions(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index fa6e2421050dc0..dc76002cd80220 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -2139,6 +2139,7 @@ EXPORT_SYMBOL(sdw_cdns_bpt_find_bandwidth); int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */ int row, int col, unsigned int data_bytes, unsigned int requested_bytes_per_frame, + unsigned int bra_block_alignment, unsigned int *data_per_frame, unsigned int *pdi0_buffer_size, unsigned int *pdi1_buffer_size, unsigned int *num_frames) { @@ -2163,6 +2164,16 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */ if (requested_bytes_per_frame < actual_bpt_bytes) actual_bpt_bytes = requested_bytes_per_frame; + if (bra_block_alignment) { + /* align to a multiple of bra_block_alignment */ + if (actual_bpt_bytes < bra_block_alignment) { + pr_err("requested bytes per frame %u is smaller than block alignment %u\n", + actual_bpt_bytes, bra_block_alignment); + return -EINVAL; + } + actual_bpt_bytes -= (actual_bpt_bytes % bra_block_alignment); + } + *data_per_frame = actual_bpt_bytes; if (data_bytes < actual_bpt_bytes) diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index 668f807cff4b23..f4e41a9ab16589 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -218,6 +218,7 @@ int sdw_cdns_bpt_find_bandwidth(int command, /* 0: write, 1: read */ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */ int row, int col, unsigned int data_bytes, unsigned int requested_bytes_per_frame, + unsigned int bra_block_alignment, unsigned int *data_per_frame, unsigned int *pdi0_buffer_size, unsigned int *pdi1_buffer_size, unsigned int *num_frames); diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 6cd3a873237501..2c40949d5892e0 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -173,6 +173,7 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, cdns->bus.params.col, msg->sec[i].len, SDW_BPT_MSG_MAX_BYTES, + slave->prop.bra_block_alignment, &data_per_frame, &pdi0_buffer_size_, &pdi1_buffer_size_, &num_frames_); if (ret < 0) @@ -197,6 +198,7 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, cdns->bus.params.col, data_per_frame, SDW_BPT_MSG_MAX_BYTES, + slave->prop.bra_block_alignment, &data_per_frame, &pdi0_buf_size_pre_frame, &pdi1_buf_size_pre_frame, &fake_num_frames); if (ret < 0) From bc476b6721956c7f03bf25469b5b152f8d373f3e Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 25 Mar 2026 13:02:49 +0800 Subject: [PATCH 3/4] soundwire: get mipi-sdw-bra-mode-max-data-per-frame property Get the mipi-sdw-bra-mode-max-data-per-frame property which indicates the maximum data payload size (in bytes per frame excluding header, CRC, and footer) for the BRA Mode. Signed-off-by: Bard Liao --- drivers/soundwire/mipi_disco.c | 3 +++ include/linux/soundwire/sdw.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index b122bd1e7321ba..cfccaa33f4380b 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -474,6 +474,9 @@ int sdw_slave_read_prop(struct sdw_slave *slave) device_property_read_u32(dev, "mipi-sdw-bra-mode-block-alignment", &prop->bra_block_alignment); + device_property_read_u32(dev, "mipi-sdw-bra-mode-max-data-per-frame", + &prop->bra_max_data_per_frame); + prop->commit_register_supported = mipi_device_property_read_bool(dev, "mipi-sdw-commit-register-supported"); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index edf8c41e48c88b..0d4d3ddeda17d0 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -366,6 +366,8 @@ struct sdw_dpn_prop { * @lane_maps: Lane mapping for the slave, only valid if lane_control_support is set * @bra_block_alignment: If non-zero the length of data in a BRA frame must be * a multiple of this number of bytes. + * @bra_max_data_per_frame: If non-zero the maximum data payload size (in bytes per + * frame excluding header, CRC, and footer) for this BRA Mode * @clock_reg_supported: the Peripheral implements the clock base and scale * registers introduced with the SoundWire 1.2 specification. SDCA devices * do not need to set this boolean property as the registers are required. @@ -397,6 +399,7 @@ struct sdw_slave_prop { u8 scp_int1_mask; u8 lane_maps[SDW_MAX_LANES]; u32 bra_block_alignment; + u32 bra_max_data_per_frame; bool clock_reg_supported; bool use_domain_irq; }; From f013d39509f5b6a18822a31c69af1f08421645a5 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 25 Mar 2026 13:11:09 +0800 Subject: [PATCH 4/4] soundwire: intel_ace2x: handle the max_data_per_frame property The optional property indicates the maximum data payload size for the BRA mode. Signed-off-by: Bard Liao --- drivers/soundwire/intel_ace2x.c | 11 +++++++++-- include/linux/soundwire/sdw.h | 6 ++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 2c40949d5892e0..c7746820461524 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -57,6 +57,7 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * struct sdw_port_config *pconfig; unsigned int pdi0_buf_size_pre_frame; unsigned int pdi1_buf_size_pre_frame; + unsigned int max_data_per_frame; unsigned int pdi0_buffer_size_; unsigned int pdi1_buffer_size_; unsigned int pdi0_buffer_size; @@ -168,11 +169,17 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * pdi0_buffer_size = 0; pdi1_buffer_size = 0; num_frames = 0; + + if (slave->prop.bra_max_data_per_frame) + max_data_per_frame = slave->prop.bra_max_data_per_frame; + else + max_data_per_frame = SDW_BRA_MAX_BYTES_PER_FRAME; + /* Add up pdi buffer size and frame numbers of each BPT sections */ for (i = 0; i < msg->sections; i++) { ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, cdns->bus.params.col, - msg->sec[i].len, SDW_BPT_MSG_MAX_BYTES, + msg->sec[i].len, max_data_per_frame, slave->prop.bra_block_alignment, &data_per_frame, &pdi0_buffer_size_, &pdi1_buffer_size_, &num_frames_); @@ -197,7 +204,7 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave * /* Get buffer size of a full frame */ ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, cdns->bus.params.col, - data_per_frame, SDW_BPT_MSG_MAX_BYTES, + data_per_frame, max_data_per_frame, slave->prop.bra_block_alignment, &data_per_frame, &pdi0_buf_size_pre_frame, &pdi1_buf_size_pre_frame, &fake_num_frames); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 0d4d3ddeda17d0..f7fda6921ecdd2 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -844,6 +844,12 @@ struct sdw_defer { */ #define SDW_BPT_MSG_MAX_BYTES (1024 * 1024) +/* + * According to mipi SoundWire DisCo Specification_v2-1, + * this maximum value shall not exceed 470. + */ +#define SDW_BRA_MAX_BYTES_PER_FRAME 470 + struct sdw_bpt_msg; /**