soundwire updates for 6.19

- Support for multiple sections in a BPT stream
  - Aligning DMA frame with BPT frames
  - Qualcomm: support for v3.1.0 controllers
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmk8DksACgkQfBQHDyUj
 g0eK1g/6Awba2J+ME+ZJ/Narqh7qwQRk0/Q9HcnPCxeXGc8peDtuhIxatmqHM+Eg
 ReoZTIIDA+/ysa1oFrdhi0MBRoZSC1eQpvL9mAQEZ5MxG368flnLncP26rYwyJHT
 rzBy0Ca/feRMddBbeTqR7OehyDsj4CiBeInRy1aY/UvaFypIgnCagyHWO6TZzYDF
 gCEVvsGaa7I3qcc1yhi+hP6jvTPMd5FtH2pKKVgL8aNvNgWSv664WX+zz2KY9KSV
 vcjA5z1rIJ3hohuGx+cqZeQGVS2PBxUyHWjvGlp3wtSVzMRGyb2TDWYsJy8+xKkM
 2Raz1uDMJPz+mDsCYlbU2h5I6SJBBhPa7fYJpuFs5KG4GY4p/ndsdh0LRStf5QtE
 pQmxOiisvbwKgKFlzOLM10zVdRL44VLldwevBt5G7uozpH8FDJ7CTCdSVRAzk2yf
 poB5zRVh1fewWi8I23T29t+GXXMq59s+Yre5lpvIp5+UO6ZDeSqcNhL6YCT6xJaZ
 ze7pkVSRY7V3lcLGP2tM19785XZr9SPZxbNojF+X/FlQbhkAp6QvMQe6v67ouoKK
 K9/9LRMyFYvDq0D19pOdbhCcEUvXWKFgyuUXdfWCpjzkHnpDQZws38FhFhYWeBzm
 LJKkTlAzI1DPEvpFc5YQf2jx4V4OH5W8lPUzunA9MmXN7MWprJ4=
 =tDi0
 -----END PGP SIGNATURE-----

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

Pull soundwire updates from Vinod Koul:

 - Support for multiple sections in a BPT stream

 - Align DMA frame with BPT frames

 - Qualcomm support for v3.1.0 controllers

* tag 'soundwire-6.19-rc1_updated' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire:
  soundwire: intel_ace2x: handle multi BPT sections
  soundwire: pass sdw_bpt_section to cdns BPT helpers
  soundwire: introduce BPT section
  soundwire: intel_ace2x: add fake frame to BRA read command
  soundwire: cadence_master: add fake_size parameter to sdw_cdns_prepare_read_dma_buffer
  ASoC: SOF: Intel: export hda_sdw_bpt_get_buf_size_aligment
  soundwire: cadence: export sdw_cdns_bpt_find_bandwidth
  soundwire: cadence_master: set data_per_frame as frame capability
  soundwire: only compute BPT stream in sdw_compute_dp0_port_params
  soundwire: cadence_master: make frame index trace more readable
  soundwire: qcom: adding support for v3.1.0
  dt-bindings: soundwire: qcom: Document v3.1.0 version of IP block
  soundwire: qcom: prepare for v3.x
  soundwire: qcom: deprecate qcom,din/out-ports
  dt-bindings: soundwire: qcom: deprecate qcom,din/out-ports
  soundwire: qcom: remove unused rd_fifo_depth
  of: base: Add of_property_read_u8_index
master
Linus Torvalds 2025-12-13 16:26:55 +12:00
commit db9c438739
13 changed files with 530 additions and 206 deletions

View File

@ -23,6 +23,7 @@ properties:
- qcom,soundwire-v1.6.0 - qcom,soundwire-v1.6.0
- qcom,soundwire-v1.7.0 - qcom,soundwire-v1.7.0
- qcom,soundwire-v2.0.0 - qcom,soundwire-v2.0.0
- qcom,soundwire-v3.1.0
- items: - items:
- enum: - enum:
- qcom,soundwire-v2.1.0 - qcom,soundwire-v2.1.0
@ -73,10 +74,12 @@ properties:
qcom,din-ports: qcom,din-ports:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
description: count of data in ports description: count of data in ports
deprecated: true
qcom,dout-ports: qcom,dout-ports:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
description: count of data out ports description: count of data out ports
deprecated: true
qcom,ports-word-length: qcom,ports-word-length:
$ref: /schemas/types.yaml#/definitions/uint8-array $ref: /schemas/types.yaml#/definitions/uint8-array
@ -223,8 +226,6 @@ required:
- '#sound-dai-cells' - '#sound-dai-cells'
- '#address-cells' - '#address-cells'
- '#size-cells' - '#size-cells'
- qcom,dout-ports
- qcom,din-ports
- qcom,ports-offset1 - qcom,ports-offset1
- qcom,ports-offset2 - qcom,ports-offset2
@ -257,9 +258,6 @@ examples:
clocks = <&lpass_rx_macro>; clocks = <&lpass_rx_macro>;
clock-names = "iface"; clock-names = "iface";
qcom,din-ports = <0>;
qcom,dout-ports = <5>;
resets = <&lpass_audiocc LPASS_AUDIO_SWR_RX_CGCR>; resets = <&lpass_audiocc LPASS_AUDIO_SWR_RX_CGCR>;
reset-names = "swr_audio_cgcr"; reset-names = "swr_audio_cgcr";

View File

@ -147,6 +147,39 @@ static void *of_find_property_value_of_size(const struct device_node *np,
return prop->value; return prop->value;
} }
/**
* of_property_read_u8_index - Find and read a u8 from a multi-value property.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @index: index of the u8 in the list of values
* @out_value: pointer to return value, modified only if no error.
*
* Search for a property in a device node and read nth 8-bit value from
* it.
*
* Return: 0 on success, -EINVAL if the property does not exist,
* -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data isn't large enough.
*
* The out_value is modified only if a valid u8 value can be decoded.
*/
int of_property_read_u8_index(const struct device_node *np,
const char *propname,
u32 index, u8 *out_value)
{
const u8 *val = of_find_property_value_of_size(np, propname,
((index + 1) * sizeof(*out_value)),
0, NULL);
if (IS_ERR(val))
return PTR_ERR(val);
*out_value = val[index];
return 0;
}
EXPORT_SYMBOL_GPL(of_property_read_u8_index);
/** /**
* of_property_read_u16_index - Find and read a u16 from a multi-value property. * of_property_read_u16_index - Find and read a u16 from a multi-value property.
* *

View File

@ -2052,8 +2052,14 @@ EXPORT_SYMBOL(sdw_clear_slave_status);
int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg) int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg)
{ {
if (msg->len > SDW_BPT_MSG_MAX_BYTES) { int len = 0;
dev_err(bus->dev, "Invalid BPT message length %d\n", msg->len); int i;
for (i = 0; i < msg->sections; i++)
len += msg->sec[i].len;
if (len > SDW_BPT_MSG_MAX_BYTES) {
dev_err(bus->dev, "Invalid BPT message length %d\n", len);
return -EINVAL; return -EINVAL;
} }

View File

@ -73,21 +73,31 @@ struct sdw_msg {
}; };
/** /**
* struct sdw_btp_msg - Message structure * struct sdw_btp_section - Message section structure
* @addr: Start Register address accessed in the Slave * @addr: Start Register address accessed in the Slave
* @len: number of bytes to transfer. More than 64Kb can be transferred * @len: number of bytes to transfer. More than 64Kb can be transferred
* but a practical limit of SDW_BPT_MSG_MAX_BYTES is enforced. * but a practical limit of SDW_BPT_MSG_MAX_BYTES is enforced.
* @dev_num: Slave device number * @buf: section data buffer (filled by host for write, filled
* @flags: transfer flags, indicate if xfer is read or write
* @buf: message data buffer (filled by host for write, filled
* by Peripheral hardware for reads) * by Peripheral hardware for reads)
*/ */
struct sdw_bpt_msg { struct sdw_bpt_section {
u32 addr; u32 addr;
u32 len; u32 len;
u8 *buf;
};
/**
* struct sdw_btp_msg - Message structure
* @sec: Pointer to array of sections
* @sections: Number of sections in the array
* @dev_num: Slave device number
* @flags: transfer flags, indicate if xfer is read or write
*/
struct sdw_bpt_msg {
struct sdw_bpt_section *sec;
int sections;
u8 dev_num; u8 dev_num;
u8 flags; u8 flags;
u8 *buf;
}; };
#define SDW_DOUBLE_RATE_FACTOR 2 #define SDW_DOUBLE_RATE_FACTOR 2

View File

@ -2094,6 +2094,36 @@ static unsigned int sdw_cdns_read_pdi1_buffer_size(unsigned int actual_data_size
return total * 2; 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 sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
int row, int col, unsigned int data_bytes, int row, int col, unsigned int data_bytes,
unsigned int requested_bytes_per_frame, unsigned int requested_bytes_per_frame,
@ -2114,9 +2144,6 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
if (!actual_bpt_bytes) if (!actual_bpt_bytes)
return -EINVAL; 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, * the caller may want to set the number of bytes per frame,
* allow when possible * allow when possible
@ -2126,6 +2153,9 @@ int sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
*data_per_frame = actual_bpt_bytes; *data_per_frame = actual_bpt_bytes;
if (data_bytes < actual_bpt_bytes)
actual_bpt_bytes = data_bytes;
if (command == 0) { if (command == 0) {
/* /*
* for writes we need to send all the data_bytes per frame, * for writes we need to send all the data_bytes per frame,
@ -2294,17 +2324,20 @@ static int sdw_cdns_prepare_read_pd0_buffer(u8 *header, unsigned int header_size
#define CDNS_BPT_ROLLING_COUNTER_START 1 #define CDNS_BPT_ROLLING_COUNTER_START 1
int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, int data_size, int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec,
int data_per_frame, u8 *dma_buffer, int dma_buffer_size, int data_per_frame, u8 *dma_buffer,
int *dma_buffer_total_bytes) int dma_buffer_size, int *dma_buffer_total_bytes)
{ {
int total_dma_data_written = 0; int total_dma_data_written = 0;
u8 *p_dma_buffer = dma_buffer; u8 *p_dma_buffer = dma_buffer;
u8 header[SDW_CDNS_BRA_HDR]; u8 header[SDW_CDNS_BRA_HDR];
unsigned int start_register;
unsigned int section_size;
int dma_data_written; int dma_data_written;
u8 *p_data = data; u8 *p_data;
u8 counter; u8 counter;
int ret; int ret;
int i;
counter = CDNS_BPT_ROLLING_COUNTER_START; counter = CDNS_BPT_ROLLING_COUNTER_START;
@ -2312,47 +2345,57 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data,
header[0] |= GENMASK(7, 6); /* header is active */ header[0] |= GENMASK(7, 6); /* header is active */
header[0] |= (dev_num << 2); header[0] |= (dev_num << 2);
while (data_size >= data_per_frame) { for (i = 0; i < num_sec; i++) {
header[1] = data_per_frame; start_register = sec[i].addr;
header[2] = start_register >> 24 & 0xFF; section_size = sec[i].len;
header[3] = start_register >> 16 & 0xFF; p_data = sec[i].buf;
header[4] = start_register >> 8 & 0xFF;
header[5] = start_register >> 0 & 0xFF;
ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR, while (section_size >= data_per_frame) {
p_data, data_per_frame, header[1] = data_per_frame;
p_dma_buffer, dma_buffer_size, header[2] = start_register >> 24 & 0xFF;
&dma_data_written, counter); header[3] = start_register >> 16 & 0xFF;
if (ret < 0) header[4] = start_register >> 8 & 0xFF;
return ret; header[5] = start_register >> 0 & 0xFF;
counter++; ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR,
p_data, data_per_frame,
p_dma_buffer, dma_buffer_size,
&dma_data_written, counter);
if (ret < 0)
return ret;
p_data += data_per_frame; counter++;
data_size -= data_per_frame;
p_dma_buffer += dma_data_written; p_data += data_per_frame;
dma_buffer_size -= dma_data_written; section_size -= data_per_frame;
total_dma_data_written += dma_data_written;
start_register += data_per_frame; p_dma_buffer += dma_data_written;
} dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written;
if (data_size) { start_register += data_per_frame;
header[1] = data_size; }
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
header[5] = start_register >> 0 & 0xFF;
ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR, if (section_size) {
p_data, data_size, header[1] = section_size;
p_dma_buffer, dma_buffer_size, header[2] = start_register >> 24 & 0xFF;
&dma_data_written, counter); header[3] = start_register >> 16 & 0xFF;
if (ret < 0) header[4] = start_register >> 8 & 0xFF;
return ret; header[5] = start_register >> 0 & 0xFF;
total_dma_data_written += dma_data_written; ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR,
p_data, section_size,
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;
}
} }
*dma_buffer_total_bytes = total_dma_data_written; *dma_buffer_total_bytes = total_dma_data_written;
@ -2361,16 +2404,19 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data,
} }
EXPORT_SYMBOL(sdw_cdns_prepare_write_dma_buffer); 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 sdw_cdns_prepare_read_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec,
int data_per_frame, u8 *dma_buffer, int dma_buffer_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; int total_dma_data_written = 0;
u8 *p_dma_buffer = dma_buffer; u8 *p_dma_buffer = dma_buffer;
u8 header[SDW_CDNS_BRA_HDR]; u8 header[SDW_CDNS_BRA_HDR];
unsigned int start_register;
unsigned int data_size;
int dma_data_written; int dma_data_written;
u8 counter; u8 counter;
int ret; int ret;
int i;
counter = CDNS_BPT_ROLLING_COUNTER_START; counter = CDNS_BPT_ROLLING_COUNTER_START;
@ -2378,13 +2424,58 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si
header[0] |= GENMASK(7, 6); /* header is active */ header[0] |= GENMASK(7, 6); /* header is active */
header[0] |= (dev_num << 2); header[0] |= (dev_num << 2);
while (data_size >= data_per_frame) { for (i = 0; i < num_sec; i++) {
header[1] = data_per_frame; start_register = sec[i].addr;
header[2] = start_register >> 24 & 0xFF; data_size = sec[i].len;
header[3] = start_register >> 16 & 0xFF; while (data_size >= data_per_frame) {
header[4] = start_register >> 8 & 0xFF; header[1] = data_per_frame;
header[5] = start_register >> 0 & 0xFF; header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
header[5] = start_register >> 0 & 0xFF;
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++;
data_size -= data_per_frame;
p_dma_buffer += dma_data_written;
dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written;
start_register += data_per_frame;
}
if (data_size) {
header[1] = data_size;
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
header[5] = start_register >> 0 & 0xFF;
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;
}
}
/* 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, ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer,
dma_buffer_size, &dma_data_written, dma_buffer_size, &dma_data_written,
counter); counter);
@ -2393,28 +2484,24 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si
counter++; counter++;
data_size -= data_per_frame; fake_size -= data_per_frame;
p_dma_buffer += dma_data_written; p_dma_buffer += dma_data_written;
dma_buffer_size -= dma_data_written; dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written; total_dma_data_written += dma_data_written;
start_register += data_per_frame;
} }
if (data_size) { if (fake_size) {
header[1] = data_size; header[1] = fake_size;
header[2] = start_register >> 24 & 0xFF;
header[3] = start_register >> 16 & 0xFF;
header[4] = start_register >> 8 & 0xFF;
header[5] = start_register >> 0 & 0xFF;
ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer, ret = sdw_cdns_prepare_read_pd0_buffer(header, SDW_CDNS_BRA_HDR, p_dma_buffer,
dma_buffer_size, &dma_data_written, dma_buffer_size, &dma_data_written,
counter); counter);
if (ret < 0) if (ret < 0)
return ret; return ret;
counter++;
p_dma_buffer += dma_data_written;
dma_buffer_size -= dma_data_written;
total_dma_data_written += dma_data_written; total_dma_data_written += dma_data_written;
} }
@ -2495,14 +2582,14 @@ int sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer,
ret = check_frame_start(header, counter); ret = check_frame_start(header, counter);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d start header %x\n", 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; return ret;
} }
ret = check_frame_end(footer); ret = check_frame_end(footer);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d end footer %x\n", 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; return ret;
} }
@ -2549,9 +2636,12 @@ static u8 extract_read_data(u32 *data, int num_bytes, u8 *buffer)
} }
int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size, int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size,
u8 *buffer, int buffer_size, int num_frames, int data_per_frame) struct sdw_bpt_section *sec, int num_sec, int num_frames,
int data_per_frame)
{ {
int total_num_bytes = 0; int total_num_bytes = 0;
int buffer_size = 0;
int sec_index;
u32 *p_data; u32 *p_data;
u8 *p_buf; u8 *p_buf;
int counter; int counter;
@ -2565,7 +2655,10 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
counter = CDNS_BPT_ROLLING_COUNTER_START; counter = CDNS_BPT_ROLLING_COUNTER_START;
p_data = (u32 *)dma_buffer; p_data = (u32 *)dma_buffer;
p_buf = buffer;
sec_index = 0;
p_buf = sec[sec_index].buf;
buffer_size = sec[sec_index].len;
for (i = 0; i < num_frames; i++) { for (i = 0; i < num_frames; i++) {
header = *p_data++; header = *p_data++;
@ -2573,7 +2666,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
ret = check_frame_start(header, counter); ret = check_frame_start(header, counter);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d start header %x\n", 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; return ret;
} }
@ -2588,7 +2681,7 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
if (crc != expected_crc) { if (crc != expected_crc) {
dev_err(dev, "%s: bad frame %d/%d crc %#x expected %#x\n", 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; return -EIO;
} }
@ -2599,12 +2692,24 @@ int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buf
ret = check_frame_end(footer); ret = check_frame_end(footer);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s: bad frame %d/%d end footer %x\n", 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; return ret;
} }
counter++; counter++;
counter &= GENMASK(3, 0); counter &= GENMASK(3, 0);
if (buffer_size == total_num_bytes && (i + 1) < num_frames) {
sec_index++;
if (sec_index >= num_sec) {
dev_err(dev, "%s: incorrect section index %d i %d\n",
__func__, sec_index, i);
return -EINVAL;
}
p_buf = sec[sec_index].buf;
buffer_size = sec[sec_index].len;
total_num_bytes = 0;
}
} }
return 0; return 0;
} }

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ /* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
/* Copyright(c) 2015-17 Intel Corporation. */ /* Copyright(c) 2015-17 Intel Corporation. */
#include <sound/soc.h> #include <sound/soc.h>
#include "bus.h"
#ifndef __SDW_CADENCE_H #ifndef __SDW_CADENCE_H
#define __SDW_CADENCE_H #define __SDW_CADENCE_H
@ -209,23 +210,29 @@ void sdw_cdns_config_update(struct sdw_cdns *cdns);
int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns); int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns);
/* SoundWire BPT/BRA helpers to format data */ /* 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 sdw_cdns_bpt_find_buffer_sizes(int command, /* 0: write, 1: read */
int row, int col, unsigned int data_bytes, int row, int col, unsigned int data_bytes,
unsigned int requested_bytes_per_frame, unsigned int requested_bytes_per_frame,
unsigned int *data_per_frame, unsigned int *pdi0_buffer_size, unsigned int *data_per_frame, unsigned int *pdi0_buffer_size,
unsigned int *pdi1_buffer_size, unsigned int *num_frames); unsigned int *pdi1_buffer_size, unsigned int *num_frames);
int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, int data_size, int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec,
int data_per_frame, u8 *dma_buffer, int dma_buffer_size, int data_per_frame, u8 *dma_buffer,
int *dma_buffer_total_bytes); int dma_buffer_size, int *dma_buffer_total_bytes);
int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_size, int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, struct sdw_bpt_section *sec, int num_sec,
int data_per_frame, u8 *dma_buffer, int dma_buffer_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 sdw_cdns_check_write_response(struct device *dev, u8 *dma_buffer,
int dma_buffer_size, int num_frames); int dma_buffer_size, int num_frames);
int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size, int sdw_cdns_check_read_response(struct device *dev, u8 *dma_buffer, int dma_buffer_size,
u8 *buffer, int buffer_size, int num_frames, int data_per_frame); struct sdw_bpt_section *sec, int num_sec, int num_frames,
int data_per_frame);
#endif /* __SDW_CADENCE_H */ #endif /* __SDW_CADENCE_H */

View File

@ -222,15 +222,23 @@ DEFINE_DEBUGFS_ATTRIBUTE(set_num_bytes_fops, NULL,
static int do_bpt_sequence(struct sdw_slave *slave, bool write, u8 *buffer) static int do_bpt_sequence(struct sdw_slave *slave, bool write, u8 *buffer)
{ {
struct sdw_bpt_msg msg = {0}; struct sdw_bpt_msg msg = {0};
struct sdw_bpt_section *sec;
msg.addr = start_addr; sec = kcalloc(1, sizeof(*sec), GFP_KERNEL);
msg.len = num_bytes; if (!sec)
return -ENOMEM;
msg.sections = 1;
sec[0].addr = start_addr;
sec[0].len = num_bytes;
msg.sec = sec;
msg.dev_num = slave->dev_num; msg.dev_num = slave->dev_num;
if (write) if (write)
msg.flags = SDW_MSG_FLAG_WRITE; msg.flags = SDW_MSG_FLAG_WRITE;
else else
msg.flags = SDW_MSG_FLAG_READ; msg.flags = SDW_MSG_FLAG_READ;
msg.buf = buffer; sec[0].buf = buffer;
return sdw_bpt_send_sync(slave->bus, slave, &msg); return sdw_bpt_send_sync(slave->bus, slave, &msg);
} }

View File

@ -124,6 +124,9 @@ static void sdw_compute_dp0_port_params(struct sdw_bus *bus)
struct sdw_master_runtime *m_rt; struct sdw_master_runtime *m_rt;
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { 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_master_ports(m_rt);
sdw_compute_dp0_slave_ports(m_rt); sdw_compute_dp0_slave_ports(m_rt);
} }

View File

@ -44,6 +44,8 @@ static int sdw_slave_bpt_stream_add(struct sdw_slave *slave, struct sdw_stream_r
return ret; return ret;
} }
#define READ_PDI1_MIN_SIZE 12
static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *slave, static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *slave,
struct sdw_bpt_msg *msg) struct sdw_bpt_msg *msg)
{ {
@ -53,19 +55,31 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
struct sdw_stream_runtime *stream; struct sdw_stream_runtime *stream;
struct sdw_stream_config sconfig; struct sdw_stream_config sconfig;
struct sdw_port_config *pconfig; 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 pdi1_buffer_size_;
unsigned int pdi0_buffer_size; unsigned int pdi0_buffer_size;
unsigned int tx_dma_bandwidth; unsigned int tx_dma_bandwidth;
unsigned int pdi1_buffer_size; unsigned int pdi1_buffer_size;
unsigned int rx_dma_bandwidth; unsigned int rx_dma_bandwidth;
unsigned int fake_num_frames;
unsigned int data_per_frame; unsigned int data_per_frame;
unsigned int tx_total_bytes; unsigned int tx_total_bytes;
struct sdw_cdns_pdi *pdi0; struct sdw_cdns_pdi *pdi0;
struct sdw_cdns_pdi *pdi1; struct sdw_cdns_pdi *pdi1;
unsigned int rx_alignment;
unsigned int tx_alignment;
unsigned int num_frames_;
unsigned int num_frames; unsigned int num_frames;
unsigned int fake_size;
unsigned int tx_pad;
unsigned int rx_pad;
int command; int command;
int ret1; int ret1;
int ret; int ret;
int dir; int dir;
int len;
int i; int i;
stream = sdw_alloc_stream("BPT", SDW_STREAM_BPT); stream = sdw_alloc_stream("BPT", SDW_STREAM_BPT);
@ -138,23 +152,77 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
command = (msg->flags & SDW_MSG_FLAG_WRITE) ? 0 : 1; command = (msg->flags & SDW_MSG_FLAG_WRITE) ? 0 : 1;
ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, cdns->bus.params.col, ret = sdw_cdns_bpt_find_bandwidth(command, cdns->bus.params.row,
msg->len, SDW_BPT_MSG_MAX_BYTES, &data_per_frame, cdns->bus.params.col,
&pdi0_buffer_size, &pdi1_buffer_size, &num_frames); prop->default_frame_rate,
&tx_dma_bandwidth, &rx_dma_bandwidth);
if (ret < 0) if (ret < 0)
goto deprepare_stream; goto deprepare_stream;
len = 0;
pdi0_buffer_size = 0;
pdi1_buffer_size = 0;
num_frames = 0;
/* 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,
&data_per_frame, &pdi0_buffer_size_,
&pdi1_buffer_size_, &num_frames_);
if (ret < 0)
goto deprepare_stream;
len += msg->sec[i].len;
pdi0_buffer_size += pdi0_buffer_size_;
pdi1_buffer_size += pdi1_buffer_size_;
num_frames += num_frames_;
}
sdw->bpt_ctx.pdi0_buffer_size = pdi0_buffer_size; sdw->bpt_ctx.pdi0_buffer_size = pdi0_buffer_size;
sdw->bpt_ctx.pdi1_buffer_size = pdi1_buffer_size; sdw->bpt_ctx.pdi1_buffer_size = pdi1_buffer_size;
sdw->bpt_ctx.num_frames = num_frames; sdw->bpt_ctx.num_frames = num_frames;
sdw->bpt_ctx.data_per_frame = data_per_frame; 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_alignment = hda_sdw_bpt_get_buf_size_alignment(rx_dma_bandwidth);
rx_dma_bandwidth = div_u64((u64)pdi1_buffer_size * 8 * (u64)prop->default_frame_rate, tx_alignment = hda_sdw_bpt_get_buf_size_alignment(tx_dma_bandwidth);
num_frames);
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 multiple 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", dev_dbg(cdns->dev, "Message len %d transferred in %d frames (%d per frame)\n",
msg->len, num_frames, data_per_frame); len, num_frames, data_per_frame);
dev_dbg(cdns->dev, "sizes pdi0 %d pdi1 %d tx_bandwidth %d rx_bandwidth %d\n", dev_dbg(cdns->dev, "sizes pdi0 %d pdi1 %d tx_bandwidth %d rx_bandwidth %d\n",
pdi0_buffer_size, pdi1_buffer_size, tx_dma_bandwidth, rx_dma_bandwidth); pdi0_buffer_size, pdi1_buffer_size, tx_dma_bandwidth, rx_dma_bandwidth);
@ -169,15 +237,16 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
} }
if (!command) { if (!command) {
ret = sdw_cdns_prepare_write_dma_buffer(msg->dev_num, msg->addr, msg->buf, ret = sdw_cdns_prepare_write_dma_buffer(msg->dev_num, msg->sec, msg->sections,
msg->len, data_per_frame, data_per_frame,
sdw->bpt_ctx.dmab_tx_bdl.area, sdw->bpt_ctx.dmab_tx_bdl.area,
pdi0_buffer_size, &tx_total_bytes); pdi0_buffer_size, &tx_total_bytes);
} else { } else {
ret = sdw_cdns_prepare_read_dma_buffer(msg->dev_num, msg->addr, msg->len, ret = sdw_cdns_prepare_read_dma_buffer(msg->dev_num, msg->sec, msg->sections,
data_per_frame, data_per_frame,
sdw->bpt_ctx.dmab_tx_bdl.area, sdw->bpt_ctx.dmab_tx_bdl.area,
pdi0_buffer_size, &tx_total_bytes); pdi0_buffer_size, &tx_total_bytes,
fake_size);
} }
if (!ret) if (!ret)
@ -252,11 +321,16 @@ static int intel_ace2x_bpt_send_async(struct sdw_intel *sdw, struct sdw_slave *s
struct sdw_bpt_msg *msg) struct sdw_bpt_msg *msg)
{ {
struct sdw_cdns *cdns = &sdw->cdns; struct sdw_cdns *cdns = &sdw->cdns;
int len = 0;
int ret; int ret;
int i;
if (msg->len < INTEL_BPT_MSG_BYTE_MIN) { for (i = 0; i < msg->sections; i++)
len += msg->sec[i].len;
if (len < INTEL_BPT_MSG_BYTE_MIN) {
dev_err(cdns->dev, "BPT message length %d is less than the minimum bytes %d\n", dev_err(cdns->dev, "BPT message length %d is less than the minimum bytes %d\n",
msg->len, INTEL_BPT_MSG_BYTE_MIN); len, INTEL_BPT_MSG_BYTE_MIN);
return -EINVAL; return -EINVAL;
} }
@ -316,7 +390,7 @@ static int intel_ace2x_bpt_wait(struct sdw_intel *sdw, struct sdw_slave *slave,
} else { } else {
ret = sdw_cdns_check_read_response(cdns->dev, sdw->bpt_ctx.dmab_rx_bdl.area, ret = sdw_cdns_check_read_response(cdns->dev, sdw->bpt_ctx.dmab_rx_bdl.area,
sdw->bpt_ctx.pdi1_buffer_size, sdw->bpt_ctx.pdi1_buffer_size,
msg->buf, msg->len, sdw->bpt_ctx.num_frames, msg->sec, msg->sections, sdw->bpt_ctx.num_frames,
sdw->bpt_ctx.data_per_frame); sdw->bpt_ctx.data_per_frame);
if (ret < 0) if (ret < 0)
dev_err(cdns->dev, "%s: BPT Read failed %d\n", __func__, ret); dev_err(cdns->dev, "%s: BPT Read failed %d\n", __func__, ret);

View File

@ -31,6 +31,7 @@
#define SWRM_VERSION_1_5_1 0x01050001 #define SWRM_VERSION_1_5_1 0x01050001
#define SWRM_VERSION_1_7_0 0x01070000 #define SWRM_VERSION_1_7_0 0x01070000
#define SWRM_VERSION_2_0_0 0x02000000 #define SWRM_VERSION_2_0_0 0x02000000
#define SWRM_VERSION_3_1_0 0x03010000
#define SWRM_COMP_HW_VERSION 0x00 #define SWRM_COMP_HW_VERSION 0x00
#define SWRM_COMP_CFG_ADDR 0x04 #define SWRM_COMP_CFG_ADDR 0x04
#define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1) #define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1)
@ -40,6 +41,9 @@
#define SWRM_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(19, 15) #define SWRM_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(19, 15)
#define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0) #define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0)
#define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5) #define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5)
#define SWRM_V3_COMP_PARAMS_WR_FIFO_DEPTH GENMASK(17, 10)
#define SWRM_V3_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(23, 18)
#define SWRM_COMP_MASTER_ID 0x104 #define SWRM_COMP_MASTER_ID 0x104
#define SWRM_V1_3_INTERRUPT_STATUS 0x200 #define SWRM_V1_3_INTERRUPT_STATUS 0x200
#define SWRM_V2_0_INTERRUPT_STATUS 0x5000 #define SWRM_V2_0_INTERRUPT_STATUS 0x5000
@ -99,14 +103,15 @@
#define SWRM_MCP_SLV_STATUS 0x1090 #define SWRM_MCP_SLV_STATUS 0x1090
#define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0) #define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0)
#define SWRM_MCP_SLV_STATUS_SZ 2 #define SWRM_MCP_SLV_STATUS_SZ 2
#define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m) #define SWRM_DPn_PORT_CTRL_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_BLOCK_CTRL_1(n) (0x112C + 0x100 * (n - 1)) #define SWRM_DPn_PORT_CTRL_2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_BLOCK_CTRL2_BANK(n, m) (0x1130 + 0x100 * (n - 1) + 0x40 * m) #define SWRM_DPn_BLOCK_CTRL_1(offset, n) (offset + 0x100 * (n - 1))
#define SWRM_DP_PORT_HCTRL_BANK(n, m) (0x1134 + 0x100 * (n - 1) + 0x40 * m) #define SWRM_DPn_BLOCK_CTRL2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m) #define SWRM_DPn_PORT_HCTRL_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_SAMPLECTRL2_BANK(n, m) (0x113C + 0x100 * (n - 1) + 0x40 * m) #define SWRM_DPn_BLOCK_CTRL3_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DIN_DPn_PCM_PORT_CTRL(n) (0x1054 + 0x100 * (n - 1)) #define SWRM_DPn_SAMPLECTRL2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m)
#define SWR_V1_3_MSTR_MAX_REG_ADDR 0x1740 #define SWR_V1_3_MSTR_MAX_REG_ADDR 0x1740
#define SWR_V2_0_MSTR_MAX_REG_ADDR 0x50ac #define SWR_V2_0_MSTR_MAX_REG_ADDR 0x50ac
@ -128,7 +133,6 @@
#define MAX_FREQ_NUM 1 #define MAX_FREQ_NUM 1
#define TIMEOUT_MS 100 #define TIMEOUT_MS 100
#define QCOM_SWRM_MAX_RD_LEN 0x1 #define QCOM_SWRM_MAX_RD_LEN 0x1
#define QCOM_SDW_MAX_PORTS 14
#define DEFAULT_CLK_FREQ 9600000 #define DEFAULT_CLK_FREQ 9600000
#define SWRM_MAX_DAIS 0xF #define SWRM_MAX_DAIS 0xF
#define SWR_INVALID_PARAM 0xFF #define SWR_INVALID_PARAM 0xFF
@ -172,6 +176,13 @@ enum {
SWRM_REG_CMD_FIFO_RD_CMD, SWRM_REG_CMD_FIFO_RD_CMD,
SWRM_REG_CMD_FIFO_STATUS, SWRM_REG_CMD_FIFO_STATUS,
SWRM_REG_CMD_FIFO_RD_FIFO_ADDR, SWRM_REG_CMD_FIFO_RD_FIFO_ADDR,
SWRM_OFFSET_DP_PORT_CTRL_BANK,
SWRM_OFFSET_DP_PORT_CTRL_2_BANK,
SWRM_OFFSET_DP_BLOCK_CTRL_1,
SWRM_OFFSET_DP_BLOCK_CTRL2_BANK,
SWRM_OFFSET_DP_PORT_HCTRL_BANK,
SWRM_OFFSET_DP_BLOCK_CTRL3_BANK,
SWRM_OFFSET_DP_SAMPLECTRL2_BANK,
}; };
struct qcom_swrm_ctrl { struct qcom_swrm_ctrl {
@ -195,6 +206,7 @@ struct qcom_swrm_ctrl {
int wake_irq; int wake_irq;
int num_din_ports; int num_din_ports;
int num_dout_ports; int num_dout_ports;
int nports;
int cols_index; int cols_index;
int rows_index; int rows_index;
unsigned long port_mask; unsigned long port_mask;
@ -202,14 +214,13 @@ struct qcom_swrm_ctrl {
u8 rcmd_id; u8 rcmd_id;
u8 wcmd_id; u8 wcmd_id;
/* Port numbers are 1 - 14 */ /* Port numbers are 1 - 14 */
struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS + 1]; struct qcom_swrm_port_config *pconfig;
struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS]; struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS];
enum sdw_slave_status status[SDW_MAX_DEVICES + 1]; enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val); int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val);
int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val);
u32 slave_status; u32 slave_status;
u32 wr_fifo_depth; u32 wr_fifo_depth;
u32 rd_fifo_depth;
bool clock_stop_not_supported; bool clock_stop_not_supported;
}; };
@ -231,6 +242,13 @@ static const unsigned int swrm_v1_3_reg_layout[] = {
[SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V1_3_CMD_FIFO_RD_CMD, [SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V1_3_CMD_FIFO_RD_CMD,
[SWRM_REG_CMD_FIFO_STATUS] = SWRM_V1_3_CMD_FIFO_STATUS, [SWRM_REG_CMD_FIFO_STATUS] = SWRM_V1_3_CMD_FIFO_STATUS,
[SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V1_3_CMD_FIFO_RD_FIFO_ADDR, [SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V1_3_CMD_FIFO_RD_FIFO_ADDR,
[SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1124,
[SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1128,
[SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x112c,
[SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1130,
[SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1134,
[SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1138,
[SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x113c,
}; };
static const struct qcom_swrm_data swrm_v1_3_data = { static const struct qcom_swrm_data swrm_v1_3_data = {
@ -265,6 +283,13 @@ static const unsigned int swrm_v2_0_reg_layout[] = {
[SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V2_0_CMD_FIFO_RD_CMD, [SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V2_0_CMD_FIFO_RD_CMD,
[SWRM_REG_CMD_FIFO_STATUS] = SWRM_V2_0_CMD_FIFO_STATUS, [SWRM_REG_CMD_FIFO_STATUS] = SWRM_V2_0_CMD_FIFO_STATUS,
[SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V2_0_CMD_FIFO_RD_FIFO_ADDR, [SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V2_0_CMD_FIFO_RD_FIFO_ADDR,
[SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1124,
[SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1128,
[SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x112c,
[SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1130,
[SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1134,
[SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1138,
[SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x113c,
}; };
static const struct qcom_swrm_data swrm_v2_0_data = { static const struct qcom_swrm_data swrm_v2_0_data = {
@ -275,6 +300,32 @@ static const struct qcom_swrm_data swrm_v2_0_data = {
.reg_layout = swrm_v2_0_reg_layout, .reg_layout = swrm_v2_0_reg_layout,
}; };
static const unsigned int swrm_v3_0_reg_layout[] = {
[SWRM_REG_FRAME_GEN_ENABLED] = SWRM_V2_0_LINK_STATUS,
[SWRM_REG_INTERRUPT_STATUS] = SWRM_V2_0_INTERRUPT_STATUS,
[SWRM_REG_INTERRUPT_MASK_ADDR] = 0, /* Not present */
[SWRM_REG_INTERRUPT_CLEAR] = SWRM_V2_0_INTERRUPT_CLEAR,
[SWRM_REG_INTERRUPT_CPU_EN] = SWRM_V2_0_INTERRUPT_CPU_EN,
[SWRM_REG_CMD_FIFO_WR_CMD] = SWRM_V2_0_CMD_FIFO_WR_CMD,
[SWRM_REG_CMD_FIFO_RD_CMD] = SWRM_V2_0_CMD_FIFO_RD_CMD,
[SWRM_REG_CMD_FIFO_STATUS] = SWRM_V2_0_CMD_FIFO_STATUS,
[SWRM_REG_CMD_FIFO_RD_FIFO_ADDR] = SWRM_V2_0_CMD_FIFO_RD_FIFO_ADDR,
[SWRM_OFFSET_DP_PORT_CTRL_BANK] = 0x1224,
[SWRM_OFFSET_DP_PORT_CTRL_2_BANK] = 0x1228,
[SWRM_OFFSET_DP_BLOCK_CTRL_1] = 0x122c,
[SWRM_OFFSET_DP_BLOCK_CTRL2_BANK] = 0x1230,
[SWRM_OFFSET_DP_PORT_HCTRL_BANK] = 0x1234,
[SWRM_OFFSET_DP_BLOCK_CTRL3_BANK] = 0x1238,
[SWRM_OFFSET_DP_SAMPLECTRL2_BANK] = 0x123c,
};
static const struct qcom_swrm_data swrm_v3_0_data = {
.default_rows = 50,
.default_cols = 16,
.sw_clk_gate_required = true,
.max_reg = SWR_V2_0_MSTR_MAX_REG_ADDR,
.reg_layout = swrm_v3_0_reg_layout,
};
#define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus) #define to_qcom_sdw(b) container_of(b, struct qcom_swrm_ctrl, bus)
static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg, static int qcom_swrm_ahb_reg_read(struct qcom_swrm_ctrl *ctrl, int reg,
@ -898,8 +949,11 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
swrm_wait_for_frame_gen_enabled(ctrl); swrm_wait_for_frame_gen_enabled(ctrl);
ctrl->slave_status = 0; ctrl->slave_status = 0;
ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val);
ctrl->rd_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_RD_FIFO_DEPTH, val);
ctrl->wr_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_WR_FIFO_DEPTH, val); if (ctrl->version >= SWRM_VERSION_3_1_0)
ctrl->wr_fifo_depth = FIELD_GET(SWRM_V3_COMP_PARAMS_WR_FIFO_DEPTH, val);
else
ctrl->wr_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_WR_FIFO_DEPTH, val);
return 0; return 0;
} }
@ -966,10 +1020,10 @@ static int qcom_swrm_port_params(struct sdw_bus *bus,
unsigned int bank) unsigned int bank)
{ {
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
u32 offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL_1];
return ctrl->reg_write(ctrl, SWRM_DP_BLOCK_CTRL_1(p_params->num), return ctrl->reg_write(ctrl, SWRM_DPn_BLOCK_CTRL_1(offset, p_params->num),
p_params->bps - 1); p_params->bps - 1);
} }
static int qcom_swrm_transport_params(struct sdw_bus *bus, static int qcom_swrm_transport_params(struct sdw_bus *bus,
@ -979,9 +1033,11 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
struct qcom_swrm_port_config *pcfg; struct qcom_swrm_port_config *pcfg;
u32 value; u32 value;
int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank); int reg, offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_BANK];
int ret; int ret;
reg = SWRM_DPn_PORT_CTRL_BANK(offset, params->port_num, bank);
pcfg = &ctrl->pconfig[params->port_num]; pcfg = &ctrl->pconfig[params->port_num];
value = pcfg->off1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT; value = pcfg->off1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT;
@ -993,15 +1049,19 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
goto err; goto err;
if (pcfg->si > 0xff) { if (pcfg->si > 0xff) {
offset = ctrl->reg_layout[SWRM_OFFSET_DP_SAMPLECTRL2_BANK];
value = (pcfg->si >> 8) & 0xff; value = (pcfg->si >> 8) & 0xff;
reg = SWRM_DP_SAMPLECTRL2_BANK(params->port_num, bank); reg = SWRM_DPn_SAMPLECTRL2_BANK(offset, params->port_num, bank);
ret = ctrl->reg_write(ctrl, reg, value); ret = ctrl->reg_write(ctrl, reg, value);
if (ret) if (ret)
goto err; goto err;
} }
if (pcfg->lane_control != SWR_INVALID_PARAM) { if (pcfg->lane_control != SWR_INVALID_PARAM) {
reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank); offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_2_BANK];
reg = SWRM_DPn_PORT_CTRL_2_BANK(offset, params->port_num, bank);
value = pcfg->lane_control; value = pcfg->lane_control;
ret = ctrl->reg_write(ctrl, reg, value); ret = ctrl->reg_write(ctrl, reg, value);
if (ret) if (ret)
@ -1009,20 +1069,23 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
} }
if (pcfg->blk_group_count != SWR_INVALID_PARAM) { if (pcfg->blk_group_count != SWR_INVALID_PARAM) {
reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank); offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL2_BANK];
reg = SWRM_DPn_BLOCK_CTRL2_BANK(offset, params->port_num, bank);
value = pcfg->blk_group_count; value = pcfg->blk_group_count;
ret = ctrl->reg_write(ctrl, reg, value); ret = ctrl->reg_write(ctrl, reg, value);
if (ret) if (ret)
goto err; goto err;
} }
if (pcfg->hstart != SWR_INVALID_PARAM offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_HCTRL_BANK];
&& pcfg->hstop != SWR_INVALID_PARAM) { reg = SWRM_DPn_PORT_HCTRL_BANK(offset, params->port_num, bank);
reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
if (pcfg->hstart != SWR_INVALID_PARAM && pcfg->hstop != SWR_INVALID_PARAM) {
value = (pcfg->hstop << 4) | pcfg->hstart; value = (pcfg->hstop << 4) | pcfg->hstart;
ret = ctrl->reg_write(ctrl, reg, value); ret = ctrl->reg_write(ctrl, reg, value);
} else { } else {
reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL; value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL;
ret = ctrl->reg_write(ctrl, reg, value); ret = ctrl->reg_write(ctrl, reg, value);
} }
@ -1031,7 +1094,8 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
goto err; goto err;
if (pcfg->bp_mode != SWR_INVALID_PARAM) { if (pcfg->bp_mode != SWR_INVALID_PARAM) {
reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank); offset = ctrl->reg_layout[SWRM_OFFSET_DP_BLOCK_CTRL3_BANK];
reg = SWRM_DPn_BLOCK_CTRL3_BANK(offset, params->port_num, bank);
ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode); ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode);
} }
@ -1043,9 +1107,12 @@ static int qcom_swrm_port_enable(struct sdw_bus *bus,
struct sdw_enable_ch *enable_ch, struct sdw_enable_ch *enable_ch,
unsigned int bank) unsigned int bank)
{ {
u32 reg = SWRM_DP_PORT_CTRL_BANK(enable_ch->port_num, bank); u32 reg;
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
u32 val; u32 val;
u32 offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_CTRL_BANK];
reg = SWRM_DPn_PORT_CTRL_BANK(offset, enable_ch->port_num, bank);
ctrl->reg_read(ctrl, reg, &val); ctrl->reg_read(ctrl, reg, &val);
@ -1155,7 +1222,6 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
struct snd_pcm_hw_params *params, struct snd_pcm_hw_params *params,
int direction) int direction)
{ {
struct sdw_port_config pconfig[QCOM_SDW_MAX_PORTS];
struct sdw_stream_config sconfig; struct sdw_stream_config sconfig;
struct sdw_master_runtime *m_rt; struct sdw_master_runtime *m_rt;
struct sdw_slave_runtime *s_rt; struct sdw_slave_runtime *s_rt;
@ -1164,6 +1230,10 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
unsigned long *port_mask; unsigned long *port_mask;
int maxport, pn, nports = 0, ret = 0; int maxport, pn, nports = 0, ret = 0;
unsigned int m_port; unsigned int m_port;
struct sdw_port_config *pconfig __free(kfree) = kcalloc(ctrl->nports,
sizeof(*pconfig), GFP_KERNEL);
if (!pconfig)
return -ENOMEM;
if (direction == SNDRV_PCM_STREAM_CAPTURE) if (direction == SNDRV_PCM_STREAM_CAPTURE)
sconfig.direction = SDW_DATA_DIR_TX; sconfig.direction = SDW_DATA_DIR_TX;
@ -1188,8 +1258,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
continue; continue;
port_mask = &ctrl->port_mask; port_mask = &ctrl->port_mask;
maxport = ctrl->num_dout_ports + ctrl->num_din_ports; maxport = ctrl->nports;
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
slave = s_rt->slave; slave = s_rt->slave;
@ -1349,17 +1418,8 @@ static int qcom_swrm_register_dais(struct qcom_swrm_ctrl *ctrl)
static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
{ {
struct device_node *np = ctrl->dev->of_node; struct device_node *np = ctrl->dev->of_node;
u8 off1[QCOM_SDW_MAX_PORTS]; struct qcom_swrm_port_config *pcfg;
u8 off2[QCOM_SDW_MAX_PORTS]; int i, ret, val;
u16 si[QCOM_SDW_MAX_PORTS];
u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, };
u8 hstart[QCOM_SDW_MAX_PORTS];
u8 hstop[QCOM_SDW_MAX_PORTS];
u8 word_length[QCOM_SDW_MAX_PORTS];
u8 blk_group_count[QCOM_SDW_MAX_PORTS];
u8 lane_control[QCOM_SDW_MAX_PORTS];
int i, ret, nports, val;
bool si_16 = false;
ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val);
@ -1367,88 +1427,78 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
ctrl->num_din_ports = FIELD_GET(SWRM_COMP_PARAMS_DIN_PORTS_MASK, val); ctrl->num_din_ports = FIELD_GET(SWRM_COMP_PARAMS_DIN_PORTS_MASK, val);
ret = of_property_read_u32(np, "qcom,din-ports", &val); ret = of_property_read_u32(np, "qcom,din-ports", &val);
if (ret) if (!ret) { /* only if present */
return ret; if (val != ctrl->num_din_ports) {
dev_err(ctrl->dev, "din-ports (%d) mismatch with controller (%d)",
val, ctrl->num_din_ports);
}
if (val > ctrl->num_din_ports) ctrl->num_din_ports = val;
return -EINVAL; }
ctrl->num_din_ports = val;
ret = of_property_read_u32(np, "qcom,dout-ports", &val); ret = of_property_read_u32(np, "qcom,dout-ports", &val);
if (ret) if (!ret) { /* only if present */
return ret; if (val != ctrl->num_dout_ports) {
dev_err(ctrl->dev, "dout-ports (%d) mismatch with controller (%d)",
val, ctrl->num_dout_ports);
}
if (val > ctrl->num_dout_ports) ctrl->num_dout_ports = val;
return -EINVAL; }
ctrl->num_dout_ports = val; ctrl->nports = ctrl->num_dout_ports + ctrl->num_din_ports;
nports = ctrl->num_dout_ports + ctrl->num_din_ports; ctrl->pconfig = devm_kcalloc(ctrl->dev, ctrl->nports + 1,
if (nports > QCOM_SDW_MAX_PORTS) sizeof(*ctrl->pconfig), GFP_KERNEL);
return -EINVAL; if (!ctrl->pconfig)
return -ENOMEM;
/* Valid port numbers are from 1-14, so mask out port 0 explicitly */
set_bit(0, &ctrl->port_mask); set_bit(0, &ctrl->port_mask);
/* Valid port numbers are from 1, so mask out port 0 explicitly */
for (i = 0; i < ctrl->nports; i++) {
pcfg = &ctrl->pconfig[i + 1];
ret = of_property_read_u8_array(np, "qcom,ports-offset1", ret = of_property_read_u8_index(np, "qcom,ports-offset1", i, &pcfg->off1);
off1, nports);
if (ret)
return ret;
ret = of_property_read_u8_array(np, "qcom,ports-offset2",
off2, nports);
if (ret)
return ret;
ret = of_property_read_u8_array(np, "qcom,ports-sinterval-low",
(u8 *)si, nports);
if (ret) {
ret = of_property_read_u16_array(np, "qcom,ports-sinterval",
si, nports);
if (ret) if (ret)
return ret; return ret;
si_16 = true;
}
ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode", ret = of_property_read_u8_index(np, "qcom,ports-offset2", i, &pcfg->off2);
bp_mode, nports); if (ret)
if (ret) {
if (ctrl->version <= SWRM_VERSION_1_3_0)
memset(bp_mode, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
else
return ret; return ret;
}
memset(hstart, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); ret = of_property_read_u8_index(np, "qcom,ports-sinterval-low", i, (u8 *)&pcfg->si);
of_property_read_u8_array(np, "qcom,ports-hstart", hstart, nports); if (ret) {
ret = of_property_read_u16_index(np, "qcom,ports-sinterval", i, &pcfg->si);
if (ret)
return ret;
}
memset(hstop, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); ret = of_property_read_u8_index(np, "qcom,ports-block-pack-mode",
of_property_read_u8_array(np, "qcom,ports-hstop", hstop, nports); i, &pcfg->bp_mode);
if (ret) {
if (ctrl->version <= SWRM_VERSION_1_3_0)
pcfg->bp_mode = SWR_INVALID_PARAM;
else
return ret;
}
memset(word_length, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); /* Optional properties */
of_property_read_u8_array(np, "qcom,ports-word-length", word_length, nports); pcfg->hstart = SWR_INVALID_PARAM;
pcfg->hstop = SWR_INVALID_PARAM;
pcfg->word_length = SWR_INVALID_PARAM;
pcfg->blk_group_count = SWR_INVALID_PARAM;
pcfg->lane_control = SWR_INVALID_PARAM;
memset(blk_group_count, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); of_property_read_u8_index(np, "qcom,ports-hstart", i, &pcfg->hstart);
of_property_read_u8_array(np, "qcom,ports-block-group-count", blk_group_count, nports);
memset(lane_control, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); of_property_read_u8_index(np, "qcom,ports-hstop", i, &pcfg->hstop);
of_property_read_u8_array(np, "qcom,ports-lane-control", lane_control, nports);
for (i = 0; i < nports; i++) { of_property_read_u8_index(np, "qcom,ports-word-length", i, &pcfg->word_length);
/* Valid port number range is from 1-14 */
if (si_16) of_property_read_u8_index(np, "qcom,ports-block-group-count",
ctrl->pconfig[i + 1].si = si[i]; i, &pcfg->blk_group_count);
else
ctrl->pconfig[i + 1].si = ((u8 *)si)[i]; of_property_read_u8_index(np, "qcom,ports-lane-control", i, &pcfg->lane_control);
ctrl->pconfig[i + 1].off1 = off1[i];
ctrl->pconfig[i + 1].off2 = off2[i];
ctrl->pconfig[i + 1].bp_mode = bp_mode[i];
ctrl->pconfig[i + 1].hstart = hstart[i];
ctrl->pconfig[i + 1].hstop = hstop[i];
ctrl->pconfig[i + 1].word_length = word_length[i];
ctrl->pconfig[i + 1].blk_group_count = blk_group_count[i];
ctrl->pconfig[i + 1].lane_control = lane_control[i];
} }
return 0; return 0;
@ -1769,6 +1819,7 @@ static const struct of_device_id qcom_swrm_of_match[] = {
{ .compatible = "qcom,soundwire-v1.6.0", .data = &swrm_v1_6_data }, { .compatible = "qcom,soundwire-v1.6.0", .data = &swrm_v1_6_data },
{ .compatible = "qcom,soundwire-v1.7.0", .data = &swrm_v1_5_data }, { .compatible = "qcom,soundwire-v1.7.0", .data = &swrm_v1_5_data },
{ .compatible = "qcom,soundwire-v2.0.0", .data = &swrm_v2_0_data }, { .compatible = "qcom,soundwire-v2.0.0", .data = &swrm_v2_0_data },
{ .compatible = "qcom,soundwire-v3.1.0", .data = &swrm_v3_0_data },
{/* sentinel */}, {/* sentinel */},
}; };

View File

@ -316,6 +316,9 @@ extern struct property *of_find_property(const struct device_node *np,
extern bool of_property_read_bool(const struct device_node *np, const char *propname); extern bool of_property_read_bool(const struct device_node *np, const char *propname);
extern int of_property_count_elems_of_size(const struct device_node *np, extern int of_property_count_elems_of_size(const struct device_node *np,
const char *propname, int elem_size); const char *propname, int elem_size);
extern int of_property_read_u8_index(const struct device_node *np,
const char *propname,
u32 index, u8 *out_value);
extern int of_property_read_u16_index(const struct device_node *np, extern int of_property_read_u16_index(const struct device_node *np,
const char *propname, const char *propname,
u32 index, u16 *out_value); u32 index, u16 *out_value);
@ -648,6 +651,12 @@ static inline int of_property_count_elems_of_size(const struct device_node *np,
return -ENOSYS; return -ENOSYS;
} }
static inline int of_property_read_u8_index(const struct device_node *np,
const char *propname, u32 index, u8 *out_value)
{
return -ENOSYS;
}
static inline int of_property_read_u16_index(const struct device_node *np, static inline int of_property_read_u16_index(const struct device_node *np,
const char *propname, u32 index, u16 *out_value) const char *propname, u32 index, u16 *out_value)
{ {

View File

@ -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, 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_tx_bdl, struct hdac_ext_stream *bpt_rx_stream,
struct snd_dma_buffer *dmab_rx_bdl); struct snd_dma_buffer *dmab_rx_bdl);
unsigned int hda_sdw_bpt_get_buf_size_alignment(unsigned int dma_bandwidth);
#else #else
static inline int hda_sdw_bpt_open(struct device *dev, int link_id, static inline int hda_sdw_bpt_open(struct device *dev, int link_id,
struct hdac_ext_stream **bpt_tx_stream, 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 *
WARN_ONCE(1, "SoundWire BPT is disabled"); WARN_ONCE(1, "SoundWire BPT is disabled");
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline unsigned int hda_sdw_bpt_get_buf_size_alignment(unsigned int dma_bandwidth)
{
return 0;
}
#endif #endif
#endif /* __HDA_SDW_BPT_H */ #endif /* __HDA_SDW_BPT_H */

View File

@ -10,6 +10,7 @@
* Hardware interface for SoundWire BPT support with HDA DMA * Hardware interface for SoundWire BPT support with HDA DMA
*/ */
#include <linux/lcm.h>
#include <sound/hdaudio_ext.h> #include <sound/hdaudio_ext.h>
#include <sound/hda-mlink.h> #include <sound/hda-mlink.h>
#include <sound/hda-sdw-bpt.h> #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
return ret; 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, 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, struct snd_dma_buffer *dmab_tx_bdl, u32 bpt_tx_num_bytes,
u32 tx_dma_bandwidth, struct hdac_ext_stream **bpt_rx_stream, u32 tx_dma_bandwidth, struct hdac_ext_stream **bpt_rx_stream,