Skip to content
Merged
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
85 changes: 76 additions & 9 deletions drivers/soundwire/cadence_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -2098,6 +2098,36 @@ static unsigned int sdw_cdns_read_pdi1_buffer_size(unsigned int actual_data_size
return total * 2;
}

int sdw_cdns_bpt_find_bandwidth(int command, /* 0: write, 1: read */
int row, int col, int frame_rate,
unsigned int *tx_dma_bandwidth,
unsigned int *rx_dma_bandwidth)
{
unsigned int bpt_bits = row * (col - 1);
unsigned int bpt_bytes = bpt_bits >> 3;
unsigned int pdi0_buffer_size;
unsigned int pdi1_buffer_size;
unsigned int data_per_frame;

data_per_frame = sdw_cdns_bra_actual_data_size(bpt_bytes);
if (!data_per_frame)
return -EINVAL;

if (command == 0) {
pdi0_buffer_size = sdw_cdns_write_pdi0_buffer_size(data_per_frame);
pdi1_buffer_size = SDW_CDNS_WRITE_PDI1_BUFFER_SIZE;
} else {
pdi0_buffer_size = SDW_CDNS_READ_PDI0_BUFFER_SIZE;
pdi1_buffer_size = sdw_cdns_read_pdi1_buffer_size(data_per_frame);
}

*tx_dma_bandwidth = pdi0_buffer_size * 8 * frame_rate;
*rx_dma_bandwidth = pdi1_buffer_size * 8 * frame_rate;

return 0;
}
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,
Expand All @@ -2118,9 +2148,6 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
if (!actual_bpt_bytes)
return -EINVAL;

if (data_bytes < actual_bpt_bytes)
actual_bpt_bytes = data_bytes;

/*
* the caller may want to set the number of bytes per frame,
* allow when possible
Expand All @@ -2130,6 +2157,9 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */

*data_per_frame = actual_bpt_bytes;

if (data_bytes < actual_bpt_bytes)
actual_bpt_bytes = data_bytes;

if (command == 0) {
/*
* for writes we need to send all the data_bytes per frame,
Expand Down Expand Up @@ -2367,7 +2397,7 @@ EXPORT_SYMBOL(sdw_cdns_prepare_write_dma_buffer);

int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size,
int data_per_frame, u8 *dma_buffer, int dma_buffer_size,
int *dma_buffer_total_bytes)
int *dma_buffer_total_bytes, unsigned int fake_size)
{
int total_dma_data_written = 0;
u8 *p_dma_buffer = dma_buffer;
Expand Down Expand Up @@ -2419,6 +2449,43 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si
if (ret < 0)
return ret;

counter++;

p_dma_buffer += dma_data_written;
dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written;
}

/* 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;
ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer,
dma_buffer_size, &dma_data_written,
counter);
if (ret < 0)
return ret;

counter++;

fake_size -= data_per_frame;
p_dma_buffer += dma_data_written;
dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written;
}

if (fake_size) {
header[1] = fake_size;
ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer,
dma_buffer_size, &dma_data_written,
counter);
if (ret < 0)
return ret;

counter++;

p_dma_buffer += dma_data_written;
dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written;
}

Expand Down Expand Up @@ -2499,14 +2566,14 @@ int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer,
ret = check_frame_start(header, counter);
if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d start header %x\n",
__func__, i, num_frames, header);
__func__, i + 1, num_frames, header);
return ret;
}

ret = check_frame_end(footer);
if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d end footer %x\n",
__func__, i, num_frames, footer);
__func__, i + 1, num_frames, footer);
return ret;
}

Expand Down Expand Up @@ -2577,7 +2644,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
ret = check_frame_start(header, counter);
if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d start header %x\n",
__func__, i, num_frames, header);
__func__, i + 1, num_frames, header);
return ret;
}

Expand All @@ -2592,7 +2659,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf

if (crc != expected_crc) {
dev_err(dev, "%s: bad frame %d/%d crc %#x expected %#x\n",
__func__, i, num_frames, crc, expected_crc);
__func__, i + 1, num_frames, crc, expected_crc);
return -EIO;
}

Expand All @@ -2603,7 +2670,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
ret = check_frame_end(footer);
if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d end footer %x\n",
__func__, i, num_frames, footer);
__func__, i + 1, num_frames, footer);
return ret;
}

Expand Down
7 changes: 6 additions & 1 deletion drivers/soundwire/cadence_master.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ void sdw_cdns_config_update(struct sdw_cdns *cdns);
int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns);

/* SoundWire BPT/BRA helpers to format data */
int sdw_cdns_bpt_find_bandwidth(int command, /* 0: write, 1: read */
int row, int col, int frame_rate,
unsigned int *tx_dma_bandwidth,
unsigned int *rx_dma_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,
Expand All @@ -221,7 +226,7 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data,

int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size,
int data_per_frame, u8 *dma_buffer, int dma_buffer_size,
int *dma_buffer_total_bytes);
int *dma_buffer_total_bytes, unsigned int fake_size);

int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer,
int dma_buffer_size, int num_frames);
Expand Down
3 changes: 3 additions & 0 deletions drivers/soundwire/generic_bandwidth_allocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ static void sdw_compute_dp0_port_params(struct sdw_bus *bus)
struct sdw_master_runtime *m_rt;

list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
/* DP0 is for BPT only */
if (m_rt->stream->type != SDW_STREAM_BPT)
continue;
sdw_compute_dp0_master_ports(m_rt);
sdw_compute_dp0_slave_ports(m_rt);
}
Expand Down
61 changes: 56 additions & 5 deletions drivers/soundwire/intel_ace2x.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ static int sdw_slave_bpt_stream_add(struct sdw_slave *slave, struct sdw_stream_r
return ret;
}

#define READ_PDI1_MIN_SIZE 12

static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *slave,
struct sdw_bpt_msg *msg)
{
Expand All @@ -53,15 +55,23 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
struct sdw_stream_runtime *stream;
struct sdw_stream_config sconfig;
struct sdw_port_config *pconfig;
unsigned int pdi0_buf_size_pre_frame;
unsigned int pdi1_buf_size_pre_frame;
unsigned int pdi0_buffer_size;
unsigned int tx_dma_bandwidth;
unsigned int pdi1_buffer_size;
unsigned int rx_dma_bandwidth;
unsigned int fake_num_frames;
unsigned int data_per_frame;
unsigned int tx_total_bytes;
struct sdw_cdns_pdi *pdi0;
struct sdw_cdns_pdi *pdi1;
unsigned int rx_alignment;
unsigned int tx_alignment;
unsigned int num_frames;
unsigned int fake_size;
unsigned int tx_pad;
unsigned int rx_pad;
int command;
int ret1;
int ret;
Expand Down Expand Up @@ -138,6 +148,13 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *

command = (msg->flags & SDW_MSG_FLAG_WRITE) ? 0 : 1;

ret = sdw_cdns_bpt_find_bandwidth(command, cdns->bus.params.row,
cdns->bus.params.col,
prop->default_frame_rate,
&tx_dma_bandwidth, &rx_dma_bandwidth);
if (ret < 0)
goto deprepare_stream;

ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, cdns->bus.params.col,
msg->len, SDW_BPT_MSG_MAX_BYTES, &data_per_frame,
&pdi0_buffer_size, &pdi1_buffer_size, &num_frames);
Expand All @@ -148,10 +165,44 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
sdw->bpt_ctx.pdi1_buffer_size = pdi1_buffer_size;
sdw->bpt_ctx.num_frames = num_frames;
sdw->bpt_ctx.data_per_frame = data_per_frame;
tx_dma_bandwidth = div_u64((u64)pdi0_buffer_size * 8 * (u64)prop->default_frame_rate,
num_frames);
rx_dma_bandwidth = div_u64((u64)pdi1_buffer_size * 8 * (u64)prop->default_frame_rate,
num_frames);

rx_alignment = hda_sdw_bpt_get_buf_size_alignment(rx_dma_bandwidth);
tx_alignment = hda_sdw_bpt_get_buf_size_alignment(tx_dma_bandwidth);

if (command) { /* read */
/* 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, &pdi0_buf_size_pre_frame,
&pdi1_buf_size_pre_frame, &fake_num_frames);
if (ret < 0)
goto deprepare_stream;

/* find fake pdi1 buffer size */
rx_pad = rx_alignment - (pdi1_buffer_size % rx_alignment);
while (rx_pad <= READ_PDI1_MIN_SIZE) {
rx_pad += rx_alignment;
}
pdi1_buffer_size += rx_pad;
/* It is fine if we request more than enough byte to read */
fake_num_frames = DIV_ROUND_UP(rx_pad, pdi1_buf_size_pre_frame);
fake_size = fake_num_frames * data_per_frame;

/* find fake pdi0 buffer size */
pdi0_buffer_size += (fake_num_frames * pdi0_buf_size_pre_frame);
tx_pad = tx_alignment - (pdi0_buffer_size % tx_alignment);
pdi0_buffer_size += tx_pad;
} else { /* write */
/*
* For the write command, the rx data block is 4, and the rx buffer size of a frame
* is 8. So the rx buffer size (pdi0_buffer_size) is always a mutiple of rx
* alignment.
*/
tx_pad = tx_alignment - (pdi0_buffer_size % tx_alignment);
pdi0_buffer_size += tx_pad;

}

dev_dbg(cdns->dev, "Message len %d transferred in %d frames (%d per frame)\n",
msg->len, num_frames, data_per_frame);
Expand All @@ -177,7 +228,7 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
ret = sdw_cdns_prepare_read_dma_buffer(msg->dev_num, msg->addr, msg->len,
data_per_frame,
sdw->bpt_ctx.dmab_tx_bdl.area,
pdi0_buffer_size, &tx_total_bytes);
pdi0_buffer_size, &tx_total_bytes, fake_size);
}

if (!ret)
Expand Down
7 changes: 7 additions & 0 deletions include/sound/hda-sdw-bpt.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ int hda_sdw_bpt_wait(struct device *dev, struct hdac_ext_stream *bpt_tx_stream,
int hda_sdw_bpt_close(struct device *dev, struct hdac_ext_stream *bpt_tx_stream,
struct snd_dma_buffer *dmab_tx_bdl, struct hdac_ext_stream *bpt_rx_stream,
struct snd_dma_buffer *dmab_rx_bdl);

unsigned int hda_sdw_bpt_get_buf_size_alignment(unsigned int dma_bandwidth);
#else
static inline int hda_sdw_bpt_open(struct device *dev, int link_id,
struct hdac_ext_stream **bpt_tx_stream,
Expand Down Expand Up @@ -64,6 +66,11 @@ static inline int hda_sdw_bpt_close(struct device *dev, struct hdac_ext_stream *
WARN_ONCE(1, "SoundWire BPT is disabled");
return -EOPNOTSUPP;
}

static inline unsigned int hda_sdw_bpt_get_buf_size_alignment(unsigned int dma_bandwidth)
{
return 0;
}
#endif

#endif /* __HDA_SDW_BPT_H */
13 changes: 13 additions & 0 deletions sound/soc/sof/intel/hda-sdw-bpt.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* Hardware interface for SoundWire BPT support with HDA DMA
*/

#include <linux/lcm.h>
#include <sound/hdaudio_ext.h>
#include <sound/hda-mlink.h>
#include <sound/hda-sdw-bpt.h>
Expand Down Expand Up @@ -247,6 +248,18 @@ static int hda_sdw_bpt_dma_disable(struct device *dev, struct hdac_ext_stream *s
return ret;
}

#define FIFO_ALIGNMENT 64

unsigned int hda_sdw_bpt_get_buf_size_alignment(unsigned int dma_bandwidth)
{
unsigned int num_channels = DIV_ROUND_UP(dma_bandwidth, BPT_FREQUENCY * 32);
unsigned int data_block = num_channels * 4;
unsigned int alignment = lcm(data_block, FIFO_ALIGNMENT);

return alignment;
}
EXPORT_SYMBOL_NS(hda_sdw_bpt_get_buf_size_alignment, "SND_SOC_SOF_INTEL_HDA_SDW_BPT");

int hda_sdw_bpt_open(struct device *dev, int link_id, struct hdac_ext_stream **bpt_tx_stream,
struct snd_dma_buffer *dmab_tx_bdl, u32 bpt_tx_num_bytes,
u32 tx_dma_bandwidth, struct hdac_ext_stream **bpt_rx_stream,
Expand Down
Loading