Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 29 additions & 6 deletions drivers/soundwire/cadence_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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("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)
Expand Down Expand Up @@ -2363,7 +2374,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;
Expand All @@ -2389,7 +2402,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;
Expand Down Expand Up @@ -2440,7 +2455,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;
Expand All @@ -2464,7 +2481,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;
Expand All @@ -2487,7 +2506,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);
Expand All @@ -2503,7 +2524,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);
Expand Down
1 change: 1 addition & 0 deletions drivers/soundwire/cadence_master.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
20 changes: 18 additions & 2 deletions drivers/soundwire/intel_ace2x.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions drivers/soundwire/mipi_disco.c
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,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");

Expand Down
14 changes: 14 additions & 0 deletions include/linux/soundwire/sdw.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,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.
Expand Down Expand Up @@ -394,6 +398,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;
};
Expand Down Expand Up @@ -838,6 +844,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;

/**
Expand Down
Loading