diff options
Diffstat (limited to 'drivers/soundwire')
| -rw-r--r-- | drivers/soundwire/bus.c | 10 | ||||
| -rw-r--r-- | drivers/soundwire/bus.h | 22 | ||||
| -rw-r--r-- | drivers/soundwire/cadence_master.c | 239 | ||||
| -rw-r--r-- | drivers/soundwire/cadence_master.h | 19 | ||||
| -rw-r--r-- | drivers/soundwire/debugfs.c | 14 | ||||
| -rw-r--r-- | drivers/soundwire/generic_bandwidth_allocation.c | 3 | ||||
| -rw-r--r-- | drivers/soundwire/intel_ace2x.c | 104 | ||||
| -rw-r--r-- | drivers/soundwire/qcom.c | 257 |
8 files changed, 466 insertions, 202 deletions
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 55c1db816534..fb68738dfb9b 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -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) { - if (msg->len > SDW_BPT_MSG_MAX_BYTES) { - dev_err(bus->dev, "Invalid BPT message length %d\n", msg->len); + int len = 0; + 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; } diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index 02651fbb683a..8115c64dd48e 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -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 * @len: number of bytes to transfer. More than 64Kb can be transferred * but a practical limit of SDW_BPT_MSG_MAX_BYTES is enforced. - * @dev_num: Slave device number - * @flags: transfer flags, indicate if xfer is read or write - * @buf: message data buffer (filled by host for write, filled + * @buf: section data buffer (filled by host for write, filled * by Peripheral hardware for reads) */ -struct sdw_bpt_msg { +struct sdw_bpt_section { u32 addr; 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 flags; - u8 *buf; }; #define SDW_DOUBLE_RATE_FACTOR 2 diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 21bb491d026b..a106e5e482c8 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -2094,6 +2094,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, @@ -2114,9 +2144,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 @@ -2126,6 +2153,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, @@ -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 -int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data, int data_size, - int data_per_frame, u8 *dma_buffer, int dma_buffer_size, - int *dma_buffer_total_bytes) +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 *dma_buffer_total_bytes) { int total_dma_data_written = 0; u8 *p_dma_buffer = dma_buffer; u8 header[SDW_CDNS_BRA_HDR]; + unsigned int start_register; + unsigned int section_size; int dma_data_written; - u8 *p_data = data; + u8 *p_data; u8 counter; int ret; + int i; 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] |= (dev_num << 2); - while (data_size >= data_per_frame) { - header[1] = data_per_frame; - 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, - p_data, data_per_frame, - p_dma_buffer, dma_buffer_size, - &dma_data_written, counter); - if (ret < 0) - return ret; + for (i = 0; i < num_sec; i++) { + start_register = sec[i].addr; + section_size = sec[i].len; + p_data = sec[i].buf; - counter++; + while (section_size >= data_per_frame) { + header[1] = data_per_frame; + header[2] = start_register >> 24 & 0xFF; + header[3] = start_register >> 16 & 0xFF; + header[4] = start_register >> 8 & 0xFF; + header[5] = start_register >> 0 & 0xFF; - p_data += data_per_frame; - data_size -= data_per_frame; + 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_dma_buffer += dma_data_written; - dma_buffer_size -= dma_data_written; - total_dma_data_written += dma_data_written; + counter++; - start_register += data_per_frame; - } + p_data += data_per_frame; + section_size -= 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; + p_dma_buffer += dma_data_written; + dma_buffer_size -= dma_data_written; + total_dma_data_written += dma_data_written; - ret = sdw_cdns_prepare_write_pd0_buffer(header, SDW_CDNS_BRA_HDR, - p_data, data_size, - p_dma_buffer, dma_buffer_size, - &dma_data_written, counter); - if (ret < 0) - return ret; + start_register += data_per_frame; + } - total_dma_data_written += dma_data_written; + if (section_size) { + header[1] = section_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, + 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; @@ -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); -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 *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; u8 header[SDW_CDNS_BRA_HDR]; + unsigned int start_register; + unsigned int data_size; int dma_data_written; u8 counter; int ret; + int i; 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] |= (dev_num << 2); - while (data_size >= data_per_frame) { - header[1] = data_per_frame; - header[2] = start_register >> 24 & 0xFF; - header[3] = start_register >> 16 & 0xFF; - header[4] = start_register >> 8 & 0xFF; - header[5] = start_register >> 0 & 0xFF; + for (i = 0; i < num_sec; i++) { + start_register = sec[i].addr; + data_size = sec[i].len; + while (data_size >= data_per_frame) { + header[1] = data_per_frame; + 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, dma_buffer_size, &dma_data_written, counter); @@ -2393,28 +2484,24 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si counter++; - data_size -= data_per_frame; - + fake_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; - + 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; } @@ -2495,14 +2582,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; } @@ -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, - 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 buffer_size = 0; + int sec_index; u32 *p_data; u8 *p_buf; 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; 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++) { 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); 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; } @@ -2588,7 +2681,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; } @@ -2599,12 +2692,24 @@ 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; } counter++; 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; } diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index 9373426c7f63..668f807cff4b 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ /* Copyright(c) 2015-17 Intel Corporation. */ #include <sound/soc.h> +#include "bus.h" #ifndef __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); /* 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, unsigned int *data_per_frame, unsigned int *pdi0_buffer_size, 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 data_per_frame, u8 *dma_buffer, int dma_buffer_size, - int *dma_buffer_total_bytes); +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 *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 *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); 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 */ diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c index 1e0f9318b616..6068011dd0d9 100644 --- a/drivers/soundwire/debugfs.c +++ b/drivers/soundwire/debugfs.c @@ -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) { struct sdw_bpt_msg msg = {0}; + struct sdw_bpt_section *sec; - msg.addr = start_addr; - msg.len = num_bytes; + sec = kcalloc(1, sizeof(*sec), GFP_KERNEL); + 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; if (write) msg.flags = SDW_MSG_FLAG_WRITE; else msg.flags = SDW_MSG_FLAG_READ; - msg.buf = buffer; + sec[0].buf = buffer; return sdw_bpt_send_sync(slave->bus, slave, &msg); } diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index c18f0c16f929..530ac66ac6fa 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -124,6 +124,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); } diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 5d08364ad6d1..1ed0251d2592 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -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) { @@ -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_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 pdi1_buffer_size_; 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 num_frames; + unsigned int fake_size; + unsigned int tx_pad; + unsigned int rx_pad; int command; int ret1; int ret; int dir; + int len; int i; 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; - 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); + 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; + 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.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 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", - 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", 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) { - ret = sdw_cdns_prepare_write_dma_buffer(msg->dev_num, msg->addr, msg->buf, - msg->len, data_per_frame, + ret = sdw_cdns_prepare_write_dma_buffer(msg->dev_num, msg->sec, msg->sections, + data_per_frame, sdw->bpt_ctx.dmab_tx_bdl.area, pdi0_buffer_size, &tx_total_bytes); } 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, sdw->bpt_ctx.dmab_tx_bdl.area, - pdi0_buffer_size, &tx_total_bytes); + pdi0_buffer_size, &tx_total_bytes, + fake_size); } 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_cdns *cdns = &sdw->cdns; + int len = 0; int ret; + int i; + + for (i = 0; i < msg->sections; i++) + len += msg->sec[i].len; - if (msg->len < INTEL_BPT_MSG_BYTE_MIN) { + if (len < INTEL_BPT_MSG_BYTE_MIN) { 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; } @@ -316,7 +390,7 @@ static int intel_ace2x_bpt_wait(struct sdw_intel *sdw, struct sdw_slave *slave, } else { ret = sdw_cdns_check_read_response(cdns->dev, sdw->bpt_ctx.dmab_rx_bdl.area, 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); if (ret < 0) dev_err(cdns->dev, "%s: BPT Read failed %d\n", __func__, ret); diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 5b3078220189..17afc5aa8b44 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -31,6 +31,7 @@ #define SWRM_VERSION_1_5_1 0x01050001 #define SWRM_VERSION_1_7_0 0x01070000 #define SWRM_VERSION_2_0_0 0x02000000 +#define SWRM_VERSION_3_1_0 0x03010000 #define SWRM_COMP_HW_VERSION 0x00 #define SWRM_COMP_CFG_ADDR 0x04 #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_DOUT_PORTS_MASK GENMASK(4, 0) #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_V1_3_INTERRUPT_STATUS 0x200 #define SWRM_V2_0_INTERRUPT_STATUS 0x5000 @@ -99,14 +103,15 @@ #define SWRM_MCP_SLV_STATUS 0x1090 #define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0) #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_DP_BLOCK_CTRL_1(n) (0x112C + 0x100 * (n - 1)) -#define SWRM_DP_BLOCK_CTRL2_BANK(n, m) (0x1130 + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DP_PORT_HCTRL_BANK(n, m) (0x1134 + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DP_SAMPLECTRL2_BANK(n, m) (0x113C + 0x100 * (n - 1) + 0x40 * m) -#define SWRM_DIN_DPn_PCM_PORT_CTRL(n) (0x1054 + 0x100 * (n - 1)) + +#define SWRM_DPn_PORT_CTRL_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DPn_PORT_CTRL_2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DPn_BLOCK_CTRL_1(offset, n) (offset + 0x100 * (n - 1)) +#define SWRM_DPn_BLOCK_CTRL2_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DPn_PORT_HCTRL_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#define SWRM_DPn_BLOCK_CTRL3_BANK(offset, n, m) (offset + 0x100 * (n - 1) + 0x40 * m) +#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_V2_0_MSTR_MAX_REG_ADDR 0x50ac @@ -128,7 +133,6 @@ #define MAX_FREQ_NUM 1 #define TIMEOUT_MS 100 #define QCOM_SWRM_MAX_RD_LEN 0x1 -#define QCOM_SDW_MAX_PORTS 14 #define DEFAULT_CLK_FREQ 9600000 #define SWRM_MAX_DAIS 0xF #define SWR_INVALID_PARAM 0xFF @@ -172,6 +176,13 @@ enum { SWRM_REG_CMD_FIFO_RD_CMD, SWRM_REG_CMD_FIFO_STATUS, 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 { @@ -195,6 +206,7 @@ struct qcom_swrm_ctrl { int wake_irq; int num_din_ports; int num_dout_ports; + int nports; int cols_index; int rows_index; unsigned long port_mask; @@ -202,14 +214,13 @@ struct qcom_swrm_ctrl { u8 rcmd_id; u8 wcmd_id; /* 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]; enum sdw_slave_status status[SDW_MAX_DEVICES + 1]; int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val); int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); u32 slave_status; u32 wr_fifo_depth; - u32 rd_fifo_depth; 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_STATUS] = SWRM_V1_3_CMD_FIFO_STATUS, [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 = { @@ -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_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] = 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 = { @@ -275,6 +300,32 @@ static const struct qcom_swrm_data swrm_v2_0_data = { .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) 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); ctrl->slave_status = 0; 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; } @@ -966,10 +1020,10 @@ static int qcom_swrm_port_params(struct sdw_bus *bus, unsigned int bank) { 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), - p_params->bps - 1); - + return ctrl->reg_write(ctrl, SWRM_DPn_BLOCK_CTRL_1(offset, p_params->num), + p_params->bps - 1); } 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_port_config *pcfg; 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; + reg = SWRM_DPn_PORT_CTRL_BANK(offset, params->port_num, bank); + pcfg = &ctrl->pconfig[params->port_num]; 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; if (pcfg->si > 0xff) { + offset = ctrl->reg_layout[SWRM_OFFSET_DP_SAMPLECTRL2_BANK]; 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); if (ret) goto err; } 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; ret = ctrl->reg_write(ctrl, reg, value); if (ret) @@ -1009,20 +1069,23 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, } 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; ret = ctrl->reg_write(ctrl, reg, value); if (ret) goto err; } - if (pcfg->hstart != SWR_INVALID_PARAM - && pcfg->hstop != SWR_INVALID_PARAM) { - reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank); + offset = ctrl->reg_layout[SWRM_OFFSET_DP_PORT_HCTRL_BANK]; + reg = SWRM_DPn_PORT_HCTRL_BANK(offset, params->port_num, bank); + + if (pcfg->hstart != SWR_INVALID_PARAM && pcfg->hstop != SWR_INVALID_PARAM) { value = (pcfg->hstop << 4) | pcfg->hstart; ret = ctrl->reg_write(ctrl, reg, value); } else { - reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank); value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL; ret = ctrl->reg_write(ctrl, reg, value); } @@ -1031,7 +1094,8 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, goto err; 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); } @@ -1043,9 +1107,12 @@ static int qcom_swrm_port_enable(struct sdw_bus *bus, struct sdw_enable_ch *enable_ch, 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); 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); @@ -1155,7 +1222,6 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, struct snd_pcm_hw_params *params, int direction) { - struct sdw_port_config pconfig[QCOM_SDW_MAX_PORTS]; struct sdw_stream_config sconfig; struct sdw_master_runtime *m_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; int maxport, pn, nports = 0, ret = 0; 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) sconfig.direction = SDW_DATA_DIR_TX; @@ -1188,8 +1258,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, continue; 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) { 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) { struct device_node *np = ctrl->dev->of_node; - u8 off1[QCOM_SDW_MAX_PORTS]; - u8 off2[QCOM_SDW_MAX_PORTS]; - 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; + struct qcom_swrm_port_config *pcfg; + int i, ret, 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); ret = of_property_read_u32(np, "qcom,din-ports", &val); - if (ret) - return ret; - - if (val > ctrl->num_din_ports) - return -EINVAL; + if (!ret) { /* only if present */ + if (val != ctrl->num_din_ports) { + dev_err(ctrl->dev, "din-ports (%d) mismatch with controller (%d)", + val, ctrl->num_din_ports); + } - ctrl->num_din_ports = val; + ctrl->num_din_ports = val; + } ret = of_property_read_u32(np, "qcom,dout-ports", &val); - if (ret) - return ret; + if (!ret) { /* only if present */ + 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) - return -EINVAL; + ctrl->num_dout_ports = val; + } - ctrl->num_dout_ports = val; + ctrl->nports = ctrl->num_dout_ports + ctrl->num_din_ports; - nports = ctrl->num_dout_ports + ctrl->num_din_ports; - if (nports > QCOM_SDW_MAX_PORTS) - return -EINVAL; + ctrl->pconfig = devm_kcalloc(ctrl->dev, ctrl->nports + 1, + sizeof(*ctrl->pconfig), GFP_KERNEL); + if (!ctrl->pconfig) + return -ENOMEM; - /* Valid port numbers are from 1-14, so mask out port 0 explicitly */ 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", - 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); + ret = of_property_read_u8_index(np, "qcom,ports-offset1", i, &pcfg->off1); if (ret) return ret; - si_16 = true; - } - ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode", - bp_mode, nports); - if (ret) { - if (ctrl->version <= SWRM_VERSION_1_3_0) - memset(bp_mode, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - else + ret = of_property_read_u8_index(np, "qcom,ports-offset2", i, &pcfg->off2); + if (ret) return ret; - } - memset(hstart, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-hstart", hstart, nports); + ret = of_property_read_u8_index(np, "qcom,ports-sinterval-low", i, (u8 *)&pcfg->si); + if (ret) { + ret = of_property_read_u16_index(np, "qcom,ports-sinterval", i, &pcfg->si); + if (ret) + return ret; + } + + ret = of_property_read_u8_index(np, "qcom,ports-block-pack-mode", + i, &pcfg->bp_mode); + if (ret) { + if (ctrl->version <= SWRM_VERSION_1_3_0) + pcfg->bp_mode = SWR_INVALID_PARAM; + else + return ret; + } + + /* Optional properties */ + 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(hstop, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-hstop", hstop, nports); + of_property_read_u8_index(np, "qcom,ports-hstart", i, &pcfg->hstart); - memset(word_length, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-word-length", word_length, nports); + of_property_read_u8_index(np, "qcom,ports-hstop", i, &pcfg->hstop); - memset(blk_group_count, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-block-group-count", blk_group_count, nports); + of_property_read_u8_index(np, "qcom,ports-word-length", i, &pcfg->word_length); - memset(lane_control, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS); - of_property_read_u8_array(np, "qcom,ports-lane-control", lane_control, nports); + of_property_read_u8_index(np, "qcom,ports-block-group-count", + i, &pcfg->blk_group_count); - for (i = 0; i < nports; i++) { - /* Valid port number range is from 1-14 */ - if (si_16) - ctrl->pconfig[i + 1].si = si[i]; - else - ctrl->pconfig[i + 1].si = ((u8 *)si)[i]; - 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]; + of_property_read_u8_index(np, "qcom,ports-lane-control", i, &pcfg->lane_control); } 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.7.0", .data = &swrm_v1_5_data }, { .compatible = "qcom,soundwire-v2.0.0", .data = &swrm_v2_0_data }, + { .compatible = "qcom,soundwire-v3.1.0", .data = &swrm_v3_0_data }, {/* sentinel */}, }; |
