Skip to content

Commit 077839c

Browse files
committed
ASoC/soundwire: add fake BPT frame to align Intel DMA buffer size
Bard Liao <yung-chuan.liao@linux.intel.com> says: There is a constraint on Intel DMA buffer size that needs to be a multiple of data block size. This series adds some fake BRA frames to add some extra buffer size to meet the constraint. The change is mainly on the soundwire tree. It would be better to go through the soundwire tree. Link: https://patch.msgid.link/20251014031450.3781789-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
2 parents 7b9798c + 4203990 commit 077839c

6 files changed

Lines changed: 161 additions & 15 deletions

File tree

drivers/soundwire/cadence_master.c

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,6 +2094,36 @@ static unsigned int sdw_cdns_read_pdi1_buffer_size(unsigned int actual_data_size
20942094
return total * 2;
20952095
}
20962096

2097+
int sdw_cdns_bpt_find_bandwidth(int command, /* 0: write, 1: read */
2098+
int row, int col, int frame_rate,
2099+
unsigned int *tx_dma_bandwidth,
2100+
unsigned int *rx_dma_bandwidth)
2101+
{
2102+
unsigned int bpt_bits = row * (col - 1);
2103+
unsigned int bpt_bytes = bpt_bits >> 3;
2104+
unsigned int pdi0_buffer_size;
2105+
unsigned int pdi1_buffer_size;
2106+
unsigned int data_per_frame;
2107+
2108+
data_per_frame = sdw_cdns_bra_actual_data_size(bpt_bytes);
2109+
if (!data_per_frame)
2110+
return -EINVAL;
2111+
2112+
if (command == 0) {
2113+
pdi0_buffer_size = sdw_cdns_write_pdi0_buffer_size(data_per_frame);
2114+
pdi1_buffer_size = SDW_CDNS_WRITE_PDI1_BUFFER_SIZE;
2115+
} else {
2116+
pdi0_buffer_size = SDW_CDNS_READ_PDI0_BUFFER_SIZE;
2117+
pdi1_buffer_size = sdw_cdns_read_pdi1_buffer_size(data_per_frame);
2118+
}
2119+
2120+
*tx_dma_bandwidth = pdi0_buffer_size * 8 * frame_rate;
2121+
*rx_dma_bandwidth = pdi1_buffer_size * 8 * frame_rate;
2122+
2123+
return 0;
2124+
}
2125+
EXPORT_SYMBOL(sdw_cdns_bpt_find_bandwidth);
2126+
20972127
int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
20982128
int row, int col, unsigned int data_bytes,
20992129
unsigned int requested_bytes_per_frame,
@@ -2114,9 +2144,6 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
21142144
if (!actual_bpt_bytes)
21152145
return -EINVAL;
21162146

2117-
if (data_bytes < actual_bpt_bytes)
2118-
actual_bpt_bytes = data_bytes;
2119-
21202147
/*
21212148
* the caller may want to set the number of bytes per frame,
21222149
* allow when possible
@@ -2126,6 +2153,9 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
21262153

21272154
*data_per_frame = actual_bpt_bytes;
21282155

2156+
if (data_bytes < actual_bpt_bytes)
2157+
actual_bpt_bytes = data_bytes;
2158+
21292159
if (command == 0) {
21302160
/*
21312161
* for writes we need to send all the data_bytes per frame,
@@ -2363,7 +2393,7 @@ EXPORT_SYMBOL(sdw_cdns_prepare_write_dma_buffer);
23632393

23642394
int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size,
23652395
int data_per_frame, u8 *dma_buffer, int dma_buffer_size,
2366-
int *dma_buffer_total_bytes)
2396+
int *dma_buffer_total_bytes, unsigned int fake_size)
23672397
{
23682398
int total_dma_data_written = 0;
23692399
u8 *p_dma_buffer = dma_buffer;
@@ -2415,6 +2445,43 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si
24152445
if (ret < 0)
24162446
return ret;
24172447

2448+
counter++;
2449+
2450+
p_dma_buffer += dma_data_written;
2451+
dma_buffer_size -= dma_data_written;
2452+
total_dma_data_written += dma_data_written;
2453+
}
2454+
2455+
/* Add fake frame */
2456+
header[0] &= ~GENMASK(7, 6); /* Set inactive flag in BPT/BRA frame heade */
2457+
while (fake_size >= data_per_frame) {
2458+
header[1] = data_per_frame;
2459+
ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer,
2460+
dma_buffer_size, &dma_data_written,
2461+
counter);
2462+
if (ret < 0)
2463+
return ret;
2464+
2465+
counter++;
2466+
2467+
fake_size -= data_per_frame;
2468+
p_dma_buffer += dma_data_written;
2469+
dma_buffer_size -= dma_data_written;
2470+
total_dma_data_written += dma_data_written;
2471+
}
2472+
2473+
if (fake_size) {
2474+
header[1] = fake_size;
2475+
ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer,
2476+
dma_buffer_size, &dma_data_written,
2477+
counter);
2478+
if (ret < 0)
2479+
return ret;
2480+
2481+
counter++;
2482+
2483+
p_dma_buffer += dma_data_written;
2484+
dma_buffer_size -= dma_data_written;
24182485
total_dma_data_written += dma_data_written;
24192486
}
24202487

@@ -2495,14 +2562,14 @@ int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer,
24952562
ret = check_frame_start(header, counter);
24962563
if (ret < 0) {
24972564
dev_err(dev, "%s: bad frame %d/%d start header %x\n",
2498-
__func__, i, num_frames, header);
2565+
__func__, i + 1, num_frames, header);
24992566
return ret;
25002567
}
25012568

25022569
ret = check_frame_end(footer);
25032570
if (ret < 0) {
25042571
dev_err(dev, "%s: bad frame %d/%d end footer %x\n",
2505-
__func__, i, num_frames, footer);
2572+
__func__, i + 1, num_frames, footer);
25062573
return ret;
25072574
}
25082575

@@ -2573,7 +2640,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
25732640
ret = check_frame_start(header, counter);
25742641
if (ret < 0) {
25752642
dev_err(dev, "%s: bad frame %d/%d start header %x\n",
2576-
__func__, i, num_frames, header);
2643+
__func__, i + 1, num_frames, header);
25772644
return ret;
25782645
}
25792646

@@ -2588,7 +2655,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
25882655

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

@@ -2599,7 +2666,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
25992666
ret = check_frame_end(footer);
26002667
if (ret < 0) {
26012668
dev_err(dev, "%s: bad frame %d/%d end footer %x\n",
2602-
__func__, i, num_frames, footer);
2669+
__func__, i + 1, num_frames, footer);
26032670
return ret;
26042671
}
26052672

drivers/soundwire/cadence_master.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,11 @@ void sdw_cdns_config_update(struct sdw_cdns *cdns);
209209
int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns);
210210

211211
/* SoundWire BPT/BRA helpers to format data */
212+
int sdw_cdns_bpt_find_bandwidth(int command, /* 0: write, 1: read */
213+
int row, int col, int frame_rate,
214+
unsigned int *tx_dma_bandwidth,
215+
unsigned int *rx_dma_bandwidth);
216+
212217
int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
213218
int row, int col, unsigned int data_bytes,
214219
unsigned int requested_bytes_per_frame,
@@ -221,7 +226,7 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data,
221226

222227
int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size,
223228
int data_per_frame, u8 *dma_buffer, int dma_buffer_size,
224-
int *dma_buffer_total_bytes);
229+
int *dma_buffer_total_bytes, unsigned int fake_size);
225230

226231
int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer,
227232
int dma_buffer_size, int num_frames);

drivers/soundwire/generic_bandwidth_allocation.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ static void sdw_compute_dp0_port_params(struct sdw_bus *bus)
124124
struct sdw_master_runtime *m_rt;
125125

126126
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
127+
/* DP0 is for BPT only */
128+
if (m_rt->stream->type != SDW_STREAM_BPT)
129+
continue;
127130
sdw_compute_dp0_master_ports(m_rt);
128131
sdw_compute_dp0_slave_ports(m_rt);
129132
}

drivers/soundwire/intel_ace2x.c

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ static int sdw_slave_bpt_stream_add(struct sdw_slave *slave, struct sdw_stream_r
4444
return ret;
4545
}
4646

47+
#define READ_PDI1_MIN_SIZE 12
48+
4749
static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *slave,
4850
struct sdw_bpt_msg *msg)
4951
{
@@ -53,15 +55,23 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
5355
struct sdw_stream_runtime *stream;
5456
struct sdw_stream_config sconfig;
5557
struct sdw_port_config *pconfig;
58+
unsigned int pdi0_buf_size_pre_frame;
59+
unsigned int pdi1_buf_size_pre_frame;
5660
unsigned int pdi0_buffer_size;
5761
unsigned int tx_dma_bandwidth;
5862
unsigned int pdi1_buffer_size;
5963
unsigned int rx_dma_bandwidth;
64+
unsigned int fake_num_frames;
6065
unsigned int data_per_frame;
6166
unsigned int tx_total_bytes;
6267
struct sdw_cdns_pdi *pdi0;
6368
struct sdw_cdns_pdi *pdi1;
69+
unsigned int rx_alignment;
70+
unsigned int tx_alignment;
6471
unsigned int num_frames;
72+
unsigned int fake_size;
73+
unsigned int tx_pad;
74+
unsigned int rx_pad;
6575
int command;
6676
int ret1;
6777
int ret;
@@ -138,6 +148,13 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
138148

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

151+
ret = sdw_cdns_bpt_find_bandwidth(command, cdns->bus.params.row,
152+
cdns->bus.params.col,
153+
prop->default_frame_rate,
154+
&tx_dma_bandwidth, &rx_dma_bandwidth);
155+
if (ret < 0)
156+
goto deprepare_stream;
157+
141158
ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, cdns->bus.params.col,
142159
msg->len, SDW_BPT_MSG_MAX_BYTES, &data_per_frame,
143160
&pdi0_buffer_size, &pdi1_buffer_size, &num_frames);
@@ -148,10 +165,43 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
148165
sdw->bpt_ctx.pdi1_buffer_size = pdi1_buffer_size;
149166
sdw->bpt_ctx.num_frames = num_frames;
150167
sdw->bpt_ctx.data_per_frame = data_per_frame;
151-
tx_dma_bandwidth = div_u64((u64)pdi0_buffer_size * 8 * (u64)prop->default_frame_rate,
152-
num_frames);
153-
rx_dma_bandwidth = div_u64((u64)pdi1_buffer_size * 8 * (u64)prop->default_frame_rate,
154-
num_frames);
168+
169+
rx_alignment = hda_sdw_bpt_get_buf_size_alignment(rx_dma_bandwidth);
170+
tx_alignment = hda_sdw_bpt_get_buf_size_alignment(tx_dma_bandwidth);
171+
172+
if (command) { /* read */
173+
/* Get buffer size of a full frame */
174+
ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row,
175+
cdns->bus.params.col,
176+
data_per_frame, SDW_BPT_MSG_MAX_BYTES,
177+
&data_per_frame, &pdi0_buf_size_pre_frame,
178+
&pdi1_buf_size_pre_frame, &fake_num_frames);
179+
if (ret < 0)
180+
goto deprepare_stream;
181+
182+
/* find fake pdi1 buffer size */
183+
rx_pad = rx_alignment - (pdi1_buffer_size % rx_alignment);
184+
while (rx_pad <= READ_PDI1_MIN_SIZE)
185+
rx_pad += rx_alignment;
186+
187+
pdi1_buffer_size += rx_pad;
188+
/* It is fine if we request more than enough byte to read */
189+
fake_num_frames = DIV_ROUND_UP(rx_pad, pdi1_buf_size_pre_frame);
190+
fake_size = fake_num_frames * data_per_frame;
191+
192+
/* find fake pdi0 buffer size */
193+
pdi0_buffer_size += (fake_num_frames * pdi0_buf_size_pre_frame);
194+
tx_pad = tx_alignment - (pdi0_buffer_size % tx_alignment);
195+
pdi0_buffer_size += tx_pad;
196+
} else { /* write */
197+
/*
198+
* For the write command, the rx data block is 4, and the rx buffer size of a frame
199+
* is 8. So the rx buffer size (pdi0_buffer_size) is always a multiple of rx
200+
* alignment.
201+
*/
202+
tx_pad = tx_alignment - (pdi0_buffer_size % tx_alignment);
203+
pdi0_buffer_size += tx_pad;
204+
}
155205

156206
dev_dbg(cdns->dev, "Message len %d transferred in %d frames (%d per frame)\n",
157207
msg->len, num_frames, data_per_frame);
@@ -177,7 +227,8 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
177227
ret = sdw_cdns_prepare_read_dma_buffer(msg->dev_num, msg->addr, msg->len,
178228
data_per_frame,
179229
sdw->bpt_ctx.dmab_tx_bdl.area,
180-
pdi0_buffer_size, &tx_total_bytes);
230+
pdi0_buffer_size, &tx_total_bytes,
231+
fake_size);
181232
}
182233

183234
if (!ret)

include/sound/hda-sdw-bpt.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ int hda_sdw_bpt_wait(struct device *dev, struct hdac_ext_stream *bpt_tx_stream,
3030
int hda_sdw_bpt_close(struct device *dev, struct hdac_ext_stream *bpt_tx_stream,
3131
struct snd_dma_buffer *dmab_tx_bdl, struct hdac_ext_stream *bpt_rx_stream,
3232
struct snd_dma_buffer *dmab_rx_bdl);
33+
34+
unsigned int hda_sdw_bpt_get_buf_size_alignment(unsigned int dma_bandwidth);
3335
#else
3436
static inline int hda_sdw_bpt_open(struct device *dev, int link_id,
3537
struct hdac_ext_stream **bpt_tx_stream,
@@ -64,6 +66,11 @@ static inline int hda_sdw_bpt_close(struct device *dev, struct hdac_ext_stream *
6466
WARN_ONCE(1, "SoundWire BPT is disabled");
6567
return -EOPNOTSUPP;
6668
}
69+
70+
static inline unsigned int hda_sdw_bpt_get_buf_size_alignment(unsigned int dma_bandwidth)
71+
{
72+
return 0;
73+
}
6774
#endif
6875

6976
#endif /* __HDA_SDW_BPT_H */

sound/soc/sof/intel/hda-sdw-bpt.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* Hardware interface for SoundWire BPT support with HDA DMA
1111
*/
1212

13+
#include <linux/lcm.h>
1314
#include <sound/hdaudio_ext.h>
1415
#include <sound/hda-mlink.h>
1516
#include <sound/hda-sdw-bpt.h>
@@ -236,6 +237,18 @@ static int hda_sdw_bpt_dma_disable(struct device *dev, struct hdac_ext_stream *s
236237
return ret;
237238
}
238239

240+
#define FIFO_ALIGNMENT 64
241+
242+
unsigned int hda_sdw_bpt_get_buf_size_alignment(unsigned int dma_bandwidth)
243+
{
244+
unsigned int num_channels = DIV_ROUND_UP(dma_bandwidth, BPT_FREQUENCY * 32);
245+
unsigned int data_block = num_channels * 4;
246+
unsigned int alignment = lcm(data_block, FIFO_ALIGNMENT);
247+
248+
return alignment;
249+
}
250+
EXPORT_SYMBOL_NS(hda_sdw_bpt_get_buf_size_alignment, "SND_SOC_SOF_INTEL_HDA_SDW_BPT");
251+
239252
int hda_sdw_bpt_open(struct device *dev, int link_id, struct hdac_ext_stream **bpt_tx_stream,
240253
struct snd_dma_buffer *dmab_tx_bdl, u32 bpt_tx_num_bytes,
241254
u32 tx_dma_bandwidth, struct hdac_ext_stream **bpt_rx_stream,

0 commit comments

Comments
 (0)