Merge tag 'soundwire-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire

Pull soundwire updates from Vinod Koul:

 - Intel dmi quirks ghost list handling for Asus Zenbook Duo,
   Asus ROG Zephyrus Duo and Asus Expertbook. Intel Peripheral
   bra_block_alignment handling

 - Cadence library BRA_NumBytes[8] support

 - Qualcomm SCP address paging, bus mclk_freq support. Increase of
   data ports to 17 and driver improvements

* tag 'soundwire-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire:
  soundwire: dmi-quirks: Disable ghost Realtek on Asus ROG Zephyrus Duo
  soundwire: stream: validate slave port properties
  soundwire: honor clock_reg_supported in the clock scaling check
  soundwire: qcom: set the bus mclk_freq property
  soundwire: dmi-quirks: Disable ghost Realtek on Asus Zenbook Duo
  soundwire: intel_ace2x: handle the max_data_per_frame property
  soundwire: get mipi-sdw-bra-mode-max-data-per-frame property
  soundwire: intel: handle Peripheral bra_block_alignment
  soundwire: Add bra_block_alignment property support
  soundwire: cadence_master: add BRA_NumBytes[8] support
  soundwire: bus.h: repair kernel-doc comments
  soundwire: intel_auxdevice: Add cs42l44 to wake_capable_list
  soundwire: qcom: add SCP address paging support
  soundwire: dmi-quirks: add a global ghost list
  soundwire: dmi-quirks: Disable ghost Realtek on Asus Expertbook
  soundwire: qcom: Allocate sruntime array dynamically
  soundwire: qcom: Fix port exhaustion check in stream_alloc_ports
  dt-bindings: soundwire: qcom: Increase max data ports to 17
This commit is contained in:
Linus Torvalds
2026-08-24 12:16:16 -07:00
12 changed files with 164 additions and 33 deletions
@@ -90,7 +90,7 @@ properties:
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
minItems: 3
maxItems: 16
maxItems: 17
qcom,ports-sinterval-low:
$ref: /schemas/types.yaml#/definitions/uint8-array
@@ -101,7 +101,7 @@ properties:
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
minItems: 3
maxItems: 16
maxItems: 17
qcom,ports-sinterval:
$ref: /schemas/types.yaml#/definitions/uint16-array
@@ -112,7 +112,7 @@ properties:
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
minItems: 3
maxItems: 16
maxItems: 17
qcom,ports-offset1:
$ref: /schemas/types.yaml#/definitions/uint8-array
@@ -123,7 +123,7 @@ properties:
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
minItems: 3
maxItems: 16
maxItems: 17
qcom,ports-offset2:
$ref: /schemas/types.yaml#/definitions/uint8-array
@@ -134,7 +134,7 @@ properties:
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
minItems: 3
maxItems: 16
maxItems: 17
qcom,ports-lane-control:
$ref: /schemas/types.yaml#/definitions/uint8-array
@@ -145,7 +145,7 @@ properties:
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
minItems: 3
maxItems: 16
maxItems: 17
qcom,ports-block-pack-mode:
$ref: /schemas/types.yaml#/definitions/uint8-array
@@ -158,7 +158,7 @@ properties:
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
minItems: 3
maxItems: 16
maxItems: 17
items:
oneOf:
- minimum: 0
@@ -175,7 +175,7 @@ properties:
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
minItems: 3
maxItems: 16
maxItems: 17
items:
oneOf:
- minimum: 0
@@ -192,7 +192,7 @@ properties:
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
minItems: 3
maxItems: 16
maxItems: 17
items:
oneOf:
- minimum: 0
@@ -208,7 +208,7 @@ properties:
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications.
minItems: 3
maxItems: 16
maxItems: 17
items:
oneOf:
- minimum: 0
+5 -2
View File
@@ -816,8 +816,11 @@ bool is_clock_scaling_supported_by_slave(struct sdw_slave *slave)
/*
* Dynamic scaling is a defined by SDCA. However, some devices expose the class ID but
* can't support dynamic scaling. We might need a quirk to handle such devices.
* The clock base and scale registers themselves are SoundWire 1.2, so a device
* may implement them without setting the class field; the driver says so with
* clock_reg_supported.
*/
return slave->id.class_id;
return slave->id.class_id || slave->prop.clock_reg_supported;
}
EXPORT_SYMBOL(is_clock_scaling_supported_by_slave);
@@ -1384,7 +1387,7 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave)
* DisCo property to discover support for the scaling registers
* from platform firmware.
*/
if (!slave->id.class_id && !slave->prop.clock_reg_supported)
if (!is_clock_scaling_supported_by_slave(slave))
return 0;
scale_index = sdw_slave_get_scale_index(slave, &base);
+5 -5
View File
@@ -73,7 +73,7 @@ struct sdw_msg {
};
/**
* struct sdw_btp_section - Message section structure
* struct sdw_bpt_section - Message section structure
* @addr: Start Register address accessed in the Slave
* @len: number of bytes to transfer. More than 64Kb can be transferred
* but a practical limit of SDW_BPT_MSG_MAX_BYTES is enforced.
@@ -87,7 +87,7 @@ struct sdw_bpt_section {
};
/**
* struct sdw_btp_msg - Message structure
* struct sdw_bpt_msg - Message structure
* @sec: Pointer to array of sections
* @sections: Number of sections in the array
* @dev_num: Slave device number
@@ -110,7 +110,7 @@ int sdw_find_row_index(int row);
int sdw_find_col_index(int col);
/**
* sdw_port_runtime: Runtime port parameters for Master or Slave
* struct sdw_port_runtime - Runtime port parameters for Master or Slave
*
* @num: Port number. For audio streams, valid port number ranges from
* [1,14]
@@ -133,7 +133,7 @@ struct sdw_port_runtime {
};
/**
* sdw_slave_runtime: Runtime Stream parameters for Slave
* struct sdw_slave_runtime - Runtime Stream parameters for Slave
*
* @slave: Slave handle
* @direction: Data direction for Slave
@@ -151,7 +151,7 @@ struct sdw_slave_runtime {
};
/**
* sdw_master_runtime: Runtime stream parameters for Master
* struct sdw_master_runtime - Runtime stream parameters for Master
*
* @bus: Bus handle
* @stream: Stream runtime handle
+29 -6
View File
@@ -2134,6 +2134,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)
{
@@ -2158,6 +2159,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("effective 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)
@@ -2358,7 +2369,9 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, i
p_data = sec[i].buf;
while (section_size >= data_per_frame) {
header[1] = data_per_frame;
header[0] &= ~BIT(0);
header[0] |= (data_per_frame >> 8) & BIT(0);
header[1] = data_per_frame & 0xFF;
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
@@ -2384,7 +2397,9 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, i
}
if (section_size) {
header[1] = section_size;
header[0] &= ~BIT(0);
header[0] |= (section_size >> 8) & BIT(0);
header[1] = section_size & 0xFF;
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
@@ -2435,7 +2450,9 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, in
start_register = sec[i].addr;
data_size = sec[i].len;
while (data_size >= data_per_frame) {
header[1] = data_per_frame;
header[0] &= ~BIT(0);
header[0] |= (data_per_frame >> 8) & BIT(0);
header[1] = data_per_frame & 0xFF;
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
@@ -2459,7 +2476,9 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, in
}
if (data_size) {
header[1] = data_size;
header[0] &= ~BIT(0);
header[0] |= (data_size >> 8) & BIT(0);
header[1] = data_size & 0xFF;
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
@@ -2482,7 +2501,9 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, in
/* Add fake frame */
header[0] &= ~GENMASK(7, 6); /* Set inactive flag in BPT/BRA frame heade */
while (fake_size >= data_per_frame) {
header[1] = data_per_frame;
header[0] &= ~BIT(0);
header[0] |= (data_per_frame >> 8) & BIT(0);
header[1] = data_per_frame & 0xFF;
ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer,
dma_buffer_size, &dma_data_written,
counter);
@@ -2498,7 +2519,9 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, in
}
if (fake_size) {
header[1] = fake_size;
header[0] &= ~BIT(0);
header[0] |= (fake_size >> 8) & BIT(0);
header[1] = fake_size & 0xFF;
ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer,
dma_buffer_size, &dma_data_written,
counter);
+1
View File
@@ -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);
+41 -1
View File
@@ -15,6 +15,14 @@ struct adr_remap {
u64 remapped_adr;
};
static const struct adr_remap global_ghost_adr[] = {
{
0x000000D010010500ull,
0x0000000000000000ull
},
{}
};
/*
* Some TigerLake devices based on an initial Intel BIOS do not expose
* the correct _ADR in the DSDT.
@@ -178,6 +186,20 @@ static const struct dmi_system_id adr_remap_quirk_table[] = {
.driver_data = (void *)hp_omen_16,
},
/* PTL devices */
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUS"),
DMI_MATCH(DMI_BOARD_NAME, "B9406CAA"),
},
.driver_data = (void *)ghost_realtek,
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUS"),
DMI_MATCH(DMI_BOARD_NAME, "GX651AR"),
},
.driver_data = (void *)ghost_realtek,
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUS"),
@@ -185,6 +207,13 @@ static const struct dmi_system_id adr_remap_quirk_table[] = {
},
.driver_data = (void *)ghost_realtek,
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUS"),
DMI_MATCH(DMI_BOARD_NAME, "UX8407AA"),
},
.driver_data = (void *)ghost_realtek,
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -205,6 +234,7 @@ static const struct dmi_system_id adr_remap_quirk_table[] = {
u64 sdw_dmi_override_adr(struct sdw_bus *bus, u64 addr)
{
const struct dmi_system_id *dmi_id;
int i;
/* check if any address remap quirk applies */
dmi_id = dmi_first_match(adr_remap_quirk_table);
@@ -216,10 +246,20 @@ u64 sdw_dmi_override_adr(struct sdw_bus *bus, u64 addr)
dev_dbg(bus->dev, "remapped _ADR 0x%llx as 0x%llx\n",
addr, map->remapped_adr);
addr = map->remapped_adr;
break;
goto out;
}
}
}
/* remap the ghost ADRs */
for (i = 0; i < ARRAY_SIZE(global_ghost_adr); i++) {
if (global_ghost_adr[i].adr == addr) {
dev_dbg(bus->dev, "remapped _ADR 0x%llx as 0x%llx\n",
addr, global_ghost_adr[i].remapped_adr);
addr = global_ghost_adr[i].remapped_adr;
break;
}
}
out:
return addr;
}
+18 -2
View File
@@ -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,25 @@ 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;
if (max_data_per_frame > SDW_BRA_MAX_BYTES_PER_FRAME) {
dev_warn(&slave->dev,
"BRA max_data_per_frame %u exceeds limit %u, clamping\n",
max_data_per_frame, SDW_BRA_MAX_BYTES_PER_FRAME);
max_data_per_frame = SDW_BRA_MAX_BYTES_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_);
if (ret < 0)
@@ -196,7 +211,8 @@ 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);
if (ret < 0)
+1
View File
@@ -54,6 +54,7 @@ static struct wake_capable_part wake_capable_list[] = {
{0x01fa, 0x2A30},
{0x01fa, 0x2A3B},
{0x01fa, 0x4243},
{0x01fa, 0x4244},
{0x01fa, 0x4245},
{0x01fa, 0x4249},
{0x01fa, 0x4747},
+6
View File
@@ -470,6 +470,12 @@ 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);
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");
+21 -3
View File
@@ -134,7 +134,6 @@
#define TIMEOUT_MS 100
#define QCOM_SWRM_MAX_RD_LEN 0x1
#define DEFAULT_CLK_FREQ 9600000
#define SWRM_MAX_DAIS 0xF
#define SWR_INVALID_PARAM 0xFF
#define SWR_HSTOP_MAX_VAL 0xF
#define SWR_HSTART_MIN_VAL 0x0
@@ -215,7 +214,7 @@ struct qcom_swrm_ctrl {
u8 wcmd_id;
/* Port numbers are 1 - 14 */
struct qcom_swrm_port_config *pconfig;
struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS];
struct sdw_stream_runtime **sruntime;
enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val);
int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val);
@@ -976,6 +975,20 @@ static enum sdw_command_response qcom_swrm_xfer_msg(struct sdw_bus *bus,
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
int ret, i, len;
if (msg->page) {
ret = qcom_swrm_cmd_fifo_wr_cmd(ctrl, msg->addr_page1,
msg->dev_num,
SDW_SCP_ADDRPAGE1);
if (ret)
return ret;
ret = qcom_swrm_cmd_fifo_wr_cmd(ctrl, msg->addr_page2,
msg->dev_num,
SDW_SCP_ADDRPAGE2);
if (ret)
return ret;
}
if (msg->flags == SDW_MSG_FLAG_READ) {
for (i = 0; i < msg->len;) {
len = min(msg->len - i, QCOM_SWRM_MAX_RD_LEN);
@@ -1271,7 +1284,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
else
pn = find_first_zero_bit(port_mask, maxport);
if (pn > maxport) {
if (pn >= maxport) {
dev_err(ctrl->dev, "All ports busy\n");
return -EBUSY;
}
@@ -1384,6 +1397,10 @@ static int qcom_swrm_register_dais(struct qcom_swrm_ctrl *ctrl)
struct device *dev = ctrl->dev;
int i;
ctrl->sruntime = devm_kcalloc(dev, num_dais, sizeof(*ctrl->sruntime), GFP_KERNEL);
if (!ctrl->sruntime)
return -ENOMEM;
/* PDM dais are only tested for now */
dais = devm_kcalloc(dev, num_dais, sizeof(*dais), GFP_KERNEL);
if (!dais)
@@ -1616,6 +1633,7 @@ static int qcom_swrm_probe(struct platform_device *pdev)
prop = &ctrl->bus.prop;
prop->max_clk_freq = DEFAULT_CLK_FREQ;
prop->mclk_freq = DEFAULT_CLK_FREQ;
prop->num_clk_gears = 0;
prop->num_clk_freq = MAX_FREQ_NUM;
prop->clk_freq = &qcom_swrm_freq_tbl[0];
+13 -4
View File
@@ -1060,14 +1060,23 @@ static int sdw_slave_port_config(struct sdw_slave *slave,
i = 0;
list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
/*
* TODO: Check valid port range as defined by DisCo/
* slave
*/
if (!is_bpt_stream) {
ret = sdw_slave_port_is_valid_range(&slave->dev, port_config[i].num);
if (ret < 0)
return ret;
/*
* A port in the generic valid range may still be unsupported by
* the Slave or unavailable for the requested stream direction.
*/
if (!sdw_get_slave_dpn_prop(slave, s_rt->direction,
port_config[i].num)) {
dev_err(&slave->dev,
"port %u not supported for %s\n",
port_config[i].num,
s_rt->direction == SDW_DATA_DIR_TX ? "TX" : "RX");
return -EINVAL;
}
} else if (port_config[i].num) {
return -EINVAL;
}
+14
View File
@@ -365,6 +365,10 @@ 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.
* @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.
@@ -395,6 +399,8 @@ struct sdw_slave_prop {
u8 commit_register_supported;
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;
};
@@ -837,6 +843,14 @@ 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.
* Note that the largest number of bytes accessible by a single BRA operation is limited to 470
* bytes when using lane 0, but goes up to 502 bytes when using one of the optional extra lanes.
*/
#define SDW_BRA_MAX_BYTES_PER_FRAME 470
struct sdw_bpt_msg;
/**