Commit db9c4387 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'soundwire-6.19-rc1_updated' of...

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
parents 7f3c8f91 188d194b
Loading
Loading
Loading
Loading
+3 −5
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ properties:
          - qcom,soundwire-v1.6.0
          - qcom,soundwire-v1.7.0
          - qcom,soundwire-v2.0.0
          - qcom,soundwire-v3.1.0
      - items:
          - enum:
              - qcom,soundwire-v2.1.0
@@ -73,10 +74,12 @@ properties:
  qcom,din-ports:
    $ref: /schemas/types.yaml#/definitions/uint32
    description: count of data in ports
    deprecated: true

  qcom,dout-ports:
    $ref: /schemas/types.yaml#/definitions/uint32
    description: count of data out ports
    deprecated: true

  qcom,ports-word-length:
    $ref: /schemas/types.yaml#/definitions/uint8-array
@@ -223,8 +226,6 @@ required:
  - '#sound-dai-cells'
  - '#address-cells'
  - '#size-cells'
  - qcom,dout-ports
  - qcom,din-ports
  - qcom,ports-offset1
  - qcom,ports-offset2

@@ -257,9 +258,6 @@ examples:
        clocks = <&lpass_rx_macro>;
        clock-names = "iface";

        qcom,din-ports = <0>;
        qcom,dout-ports = <5>;

        resets = <&lpass_audiocc LPASS_AUDIO_SWR_RX_CGCR>;
        reset-names = "swr_audio_cgcr";

+33 −0
Original line number Diff line number Diff line
@@ -147,6 +147,39 @@ static void *of_find_property_value_of_size(const struct device_node *np,
	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.
 *
+8 −2
Original line number Diff line number Diff line
@@ -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;
	}

+16 −6
Original line number Diff line number Diff line
@@ -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
+172 −67
Original line number Diff line number Diff line
@@ -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,7 +2345,12 @@ 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) {
	for (i = 0; i < num_sec; i++) {
		start_register = sec[i].addr;
		section_size = sec[i].len;
		p_data = sec[i].buf;

		while (section_size >= data_per_frame) {
			header[1] = data_per_frame;
			header[2] = start_register >> 24 & 0xFF;
			header[3] = start_register >> 16 & 0xFF;
@@ -2329,7 +2367,7 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data,
			counter++;

			p_data += data_per_frame;
		data_size -= data_per_frame;
			section_size -= data_per_frame;

			p_dma_buffer += dma_data_written;
			dma_buffer_size -= dma_data_written;
@@ -2338,22 +2376,27 @@ int sdw_cdns_prepare_write_dma_buffer(u8 dev_num, u32 start_register, u8 *data,
			start_register += data_per_frame;
		}

	if (data_size) {
		header[1] = data_size;
		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, data_size,
								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,6 +2424,9 @@ 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);

	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;
@@ -2385,9 +2434,9 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si
			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);
			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;

@@ -2409,12 +2458,50 @@ int sdw_cdns_prepare_read_dma_buffer(u8 dev_num, u32 start_register, int data_si
			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);
		if (ret < 0)
			return ret;

		counter++;

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

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

		counter++;

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

@@ -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;
}
Loading