diff mbox

[v4,07/13] soundwire: Add stream configuration APIs

Message ID 1524049146-8725-8-git-send-email-vinod.koul@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Vinod Koul April 18, 2018, 10:59 a.m. UTC
From: Sanyog Kale <sanyog.r.kale@intel.com>

Add APIs for prepare, enable, disable and de-prepare stream.

Signed-off-by: Sanyog Kale <sanyog.r.kale@intel.com>
Signed-off-by: Shreyas NC <shreyas.nc@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 drivers/soundwire/bus.c       |   9 ++
 drivers/soundwire/stream.c    | 252 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/soundwire/sdw.h |   4 +
 3 files changed, 265 insertions(+)

Comments

Pierre-Louis Bossart April 21, 2018, 1:56 p.m. UTC | #1
> +static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
> +{
> +	struct sdw_master_runtime *m_rt = stream->m_rt;
> +	struct sdw_bus *bus = m_rt->bus;
> +	struct sdw_master_prop *prop = NULL;
> +	struct sdw_bus_params params;
> +	int ret;
> +
> +	prop = &bus->prop;
> +	memcpy(&params, &bus->params, sizeof(params));
> +
> +	/* TODO: Support Asynchronous mode */
> +	if ((prop->max_freq % stream->params.rate) != 0) {
> +		dev_err(bus->dev, "Async mode not supported");
> +		return -EINVAL;
> +	}
> +
> +	/* Increment cumulative bus bandwidth */
> +	bus->params.bandwidth += m_rt->stream->params.rate *
> +		m_rt->ch_count * m_rt->stream->params.bps;

This also does not work for device-to-device communication, see e.g.
the earlier documentation.

ch_count: Number of channels handled by the Master for
+ * this stream, can be zero.

should it be m_rt->stream->params->ch_count?


> +static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
> +{
> +	struct sdw_master_runtime *m_rt = stream->m_rt;
> +	struct sdw_bus *bus = m_rt->bus;
> +	int ret = 0;
> +
> +	/* De-prepare port(s) */
> +	ret = sdw_prep_deprep_ports(m_rt, false);
> +	if (ret < 0) {
> +		dev_err(bus->dev, "De-prepare port(s) failed: %d", ret);
> +		return ret;
> +	}
> +
> +	bus->params.bandwidth -= m_rt->stream->params.rate *
> +		m_rt->ch_count * m_rt->stream->params.bps;

And same here, the ch_count can be zero.

> +
> +	if (!bus->params.bandwidth) {
> +		bus->params.row = 0;
> +		bus->params.col = 0;
> +		goto exit;

What is the intent with this test+goto? Shouldn't you program the 
parameters if you want to change the frame shape?

> +	}
> +
> +	/* Program params */
> +	ret = sdw_program_params(bus);
> +	if (ret < 0) {
> +		dev_err(bus->dev, "Program params failed: %d", ret);
> +		return ret;
> +	}
> +
> +	return do_bank_switch(stream);
> +
> +exit:
> +	stream->state = SDW_STREAM_DEPREPARED;
> +
> +	return ret;
> +}
Vinod Koul April 21, 2018, 4:13 p.m. UTC | #2
On Sat, Apr 21, 2018 at 06:56:26AM -0700, Pierre-Louis Bossart wrote:
> 
> >+static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
> >+{
> >+	struct sdw_master_runtime *m_rt = stream->m_rt;
> >+	struct sdw_bus *bus = m_rt->bus;
> >+	struct sdw_master_prop *prop = NULL;
> >+	struct sdw_bus_params params;
> >+	int ret;
> >+
> >+	prop = &bus->prop;
> >+	memcpy(&params, &bus->params, sizeof(params));
> >+
> >+	/* TODO: Support Asynchronous mode */
> >+	if ((prop->max_freq % stream->params.rate) != 0) {
> >+		dev_err(bus->dev, "Async mode not supported");
> >+		return -EINVAL;
> >+	}
> >+
> >+	/* Increment cumulative bus bandwidth */
> >+	bus->params.bandwidth += m_rt->stream->params.rate *
> >+		m_rt->ch_count * m_rt->stream->params.bps;
> 
> This also does not work for device-to-device communication, see e.g.
> the earlier documentation.

Sure it doesn't work for a feature which is **NOT** supported. So I am not
going to do anything here

> ch_count: Number of channels handled by the Master for
> + * this stream, can be zero.
> 
> should it be m_rt->stream->params->ch_count?

Not for this case. In future when we support multi-link then yes.

> >+static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
> >+{
> >+	struct sdw_master_runtime *m_rt = stream->m_rt;
> >+	struct sdw_bus *bus = m_rt->bus;
> >+	int ret = 0;
> >+
> >+	/* De-prepare port(s) */
> >+	ret = sdw_prep_deprep_ports(m_rt, false);
> >+	if (ret < 0) {
> >+		dev_err(bus->dev, "De-prepare port(s) failed: %d", ret);
> >+		return ret;
> >+	}
> >+
> >+	bus->params.bandwidth -= m_rt->stream->params.rate *
> >+		m_rt->ch_count * m_rt->stream->params.bps;
> 
> And same here, the ch_count can be zero.

Same as above..

> 
> >+
> >+	if (!bus->params.bandwidth) {
> >+		bus->params.row = 0;
> >+		bus->params.col = 0;
> >+		goto exit;
> 
> What is the intent with this test+goto? Shouldn't you program the parameters
> if you want to change the frame shape?

hmmm that seems correct point to me, but then we are going idle and should
ideally power down. Let me check again if that is the reason.

> 
> >+	}
> >+
> >+	/* Program params */
> >+	ret = sdw_program_params(bus);
> >+	if (ret < 0) {
> >+		dev_err(bus->dev, "Program params failed: %d", ret);
> >+		return ret;
> >+	}
> >+
> >+	return do_bank_switch(stream);
> >+
> >+exit:
> >+	stream->state = SDW_STREAM_DEPREPARED;
> >+
> >+	return ret;
> >+}
Sanyog Kale April 23, 2018, 3:45 a.m. UTC | #3
On Sat, Apr 21, 2018 at 09:43:15PM +0530, Vinod Koul wrote:
> On Sat, Apr 21, 2018 at 06:56:26AM -0700, Pierre-Louis Bossart wrote:
> > 
> > >+static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
> > >+{
> > >+	struct sdw_master_runtime *m_rt = stream->m_rt;
> > >+	struct sdw_bus *bus = m_rt->bus;
> > >+	int ret = 0;
> > >+
> > >+	/* De-prepare port(s) */
> > >+	ret = sdw_prep_deprep_ports(m_rt, false);
> > >+	if (ret < 0) {
> > >+		dev_err(bus->dev, "De-prepare port(s) failed: %d", ret);
> > >+		return ret;
> > >+	}
> > >+
> > >+	bus->params.bandwidth -= m_rt->stream->params.rate *
> > >+		m_rt->ch_count * m_rt->stream->params.bps;
> > 
> > And same here, the ch_count can be zero.
> 
> Same as above..
> 
> > 
> > >+
> > >+	if (!bus->params.bandwidth) {
> > >+		bus->params.row = 0;
> > >+		bus->params.col = 0;
> > >+		goto exit;
> > 
> > What is the intent with this test+goto? Shouldn't you program the parameters
> > if you want to change the frame shape?
> 
> hmmm that seems correct point to me, but then we are going idle and should
> ideally power down. Let me check again if that is the reason.
>

We do not want to program parameters or change frame shape in case of bandwidth
required is 0 on bus (ie. no stream running). The row and col values are reset
to 0 and will be re-computed again in prepare_stream of next stream based
on stream requirement.

> > 
> > >+	}
> > >+
> > >+	/* Program params */
> > >+	ret = sdw_program_params(bus);
> > >+	if (ret < 0) {
> > >+		dev_err(bus->dev, "Program params failed: %d", ret);
> > >+		return ret;
> > >+	}
> > >+
> > >+	return do_bank_switch(stream);
> > >+
> > >+exit:
> > >+	stream->state = SDW_STREAM_DEPREPARED;
> > >+
> > >+	return ret;
> > >+}
> 
> -- 
> ~Vinod
Pierre-Louis Bossart April 23, 2018, 1:30 p.m. UTC | #4
>>> +
>>> +	if (!bus->params.bandwidth) {
>>> +		bus->params.row = 0;
>>> +		bus->params.col = 0;
>>> +		goto exit;
>>
>> What is the intent with this test+goto? Shouldn't you program the parameters
>> if you want to change the frame shape?
> 
> hmmm that seems correct point to me, but then we are going idle and should
> ideally power down. Let me check again if that is the reason.

what about clock stop? what about the default frame shape specified in 
the DisCo spec? I don't see the reason why we'd go to 48x2 - especially 
on Intel platforms where we'll typically use  50x2 to remain aligned 
with a 48kHz frame rate.
diff mbox

Patch

diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 084bf71b2b87..dcc0ff9f0c22 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -17,6 +17,7 @@ 
  */
 int sdw_add_bus_master(struct sdw_bus *bus)
 {
+	struct sdw_master_prop *prop = NULL;
 	int ret;
 
 	if (!bus->dev) {
@@ -79,9 +80,17 @@  int sdw_add_bus_master(struct sdw_bus *bus)
 	}
 
 	/*
+	 * Initialize clock values based on Master properties. The max
+	 * frequency is read from max_freq property. Current assumption
+	 * is that the bus will start at highest clock frequency when
+	 * powered on.
+	 *
 	 * Default active bank will be 0 as out of reset the Slaves have
 	 * to start with bank 0 (Table 40 of Spec)
 	 */
+	prop = &bus->prop;
+	bus->params.max_dr_freq = prop->max_freq * SDW_DOUBLE_RATE_FACTOR;
+	bus->params.curr_dr_freq = bus->params.max_dr_freq;
 	bus->params.curr_bank = SDW_BANK0;
 	bus->params.next_bank = SDW_BANK1;
 
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index c1bfceee5b73..6664ea83bcee 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -1226,3 +1226,255 @@  struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
 
 	return NULL;
 }
+
+static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
+{
+	struct sdw_master_runtime *m_rt = stream->m_rt;
+	struct sdw_bus *bus = m_rt->bus;
+	struct sdw_master_prop *prop = NULL;
+	struct sdw_bus_params params;
+	int ret;
+
+	prop = &bus->prop;
+	memcpy(&params, &bus->params, sizeof(params));
+
+	/* TODO: Support Asynchronous mode */
+	if ((prop->max_freq % stream->params.rate) != 0) {
+		dev_err(bus->dev, "Async mode not supported");
+		return -EINVAL;
+	}
+
+	/* Increment cumulative bus bandwidth */
+	bus->params.bandwidth += m_rt->stream->params.rate *
+		m_rt->ch_count * m_rt->stream->params.bps;
+
+	/* Program params */
+	ret = sdw_program_params(bus);
+	if (ret < 0) {
+		dev_err(bus->dev, "Program params failed: %d", ret);
+		goto restore_params;
+	}
+
+	ret = do_bank_switch(stream);
+	if (ret < 0) {
+		dev_err(bus->dev, "Bank switch failed: %d", ret);
+		goto restore_params;
+	}
+
+	/* Prepare port(s) on the new clock configuration */
+	ret = sdw_prep_deprep_ports(m_rt, true);
+	if (ret < 0) {
+		dev_err(bus->dev, "Prepare port(s) failed ret = %d",
+				ret);
+		return ret;
+	}
+
+	stream->state = SDW_STREAM_PREPARED;
+
+	return ret;
+
+restore_params:
+	memcpy(&bus->params, &params, sizeof(params));
+	return ret;
+}
+
+/**
+ * sdw_prepare_stream() - Prepare SoundWire stream
+ *
+ * @stream: Soundwire stream
+ *
+ * Documentation/soundwire/stream.txt explains this API in detail
+ */
+int sdw_prepare_stream(struct sdw_stream_runtime *stream)
+{
+	int ret = 0;
+
+	if (!stream) {
+		pr_err("SoundWire: Handle not found for stream");
+		return -EINVAL;
+	}
+
+	mutex_lock(&stream->m_rt->bus->bus_lock);
+
+	ret = _sdw_prepare_stream(stream);
+	if (ret < 0)
+		pr_err("Prepare for stream:%s failed: %d", stream->name, ret);
+
+	mutex_unlock(&stream->m_rt->bus->bus_lock);
+	return ret;
+}
+EXPORT_SYMBOL(sdw_prepare_stream);
+
+static int _sdw_enable_stream(struct sdw_stream_runtime *stream)
+{
+	struct sdw_master_runtime *m_rt = stream->m_rt;
+	struct sdw_bus *bus = m_rt->bus;
+	int ret;
+
+	/* Program params */
+	ret = sdw_program_params(bus);
+	if (ret < 0) {
+		dev_err(bus->dev, "Program params failed: %d", ret);
+		return ret;
+	}
+
+	/* Enable port(s) */
+	ret = sdw_enable_disable_ports(m_rt, true);
+	if (ret < 0) {
+		dev_err(bus->dev, "Enable port(s) failed ret: %d", ret);
+		return ret;
+	}
+
+	ret = do_bank_switch(stream);
+	if (ret < 0) {
+		dev_err(bus->dev, "Bank switch failed: %d", ret);
+		return ret;
+	}
+
+	stream->state = SDW_STREAM_ENABLED;
+	return 0;
+}
+
+/**
+ * sdw_enable_stream() - Enable SoundWire stream
+ *
+ * @stream: Soundwire stream
+ *
+ * Documentation/soundwire/stream.txt explains this API in detail
+ */
+int sdw_enable_stream(struct sdw_stream_runtime *stream)
+{
+	int ret = 0;
+
+	if (!stream) {
+		pr_err("SoundWire: Handle not found for stream");
+		return -EINVAL;
+	}
+
+	mutex_lock(&stream->m_rt->bus->bus_lock);
+
+	ret = _sdw_enable_stream(stream);
+	if (ret < 0)
+		pr_err("Enable for stream:%s failed: %d", stream->name, ret);
+
+	mutex_unlock(&stream->m_rt->bus->bus_lock);
+	return ret;
+}
+EXPORT_SYMBOL(sdw_enable_stream);
+
+static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
+{
+	struct sdw_master_runtime *m_rt = stream->m_rt;
+	struct sdw_bus *bus = m_rt->bus;
+	int ret;
+
+	/* Disable port(s) */
+	ret = sdw_enable_disable_ports(m_rt, false);
+	if (ret < 0) {
+		dev_err(bus->dev, "Disable port(s) failed: %d", ret);
+		return ret;
+	}
+
+	stream->state = SDW_STREAM_DISABLED;
+
+	/* Program params */
+	ret = sdw_program_params(bus);
+	if (ret < 0) {
+		dev_err(bus->dev, "Program params failed: %d", ret);
+		return ret;
+	}
+
+	return do_bank_switch(stream);
+}
+
+/**
+ * sdw_disable_stream() - Disable SoundWire stream
+ *
+ * @stream: Soundwire stream
+ *
+ * Documentation/soundwire/stream.txt explains this API in detail
+ */
+int sdw_disable_stream(struct sdw_stream_runtime *stream)
+{
+	int ret = 0;
+
+	if (!stream) {
+		pr_err("SoundWire: Handle not found for stream");
+		return -EINVAL;
+	}
+
+	mutex_lock(&stream->m_rt->bus->bus_lock);
+
+	ret = _sdw_disable_stream(stream);
+	if (ret < 0)
+		pr_err("Disable for stream:%s failed: %d", stream->name, ret);
+
+	mutex_unlock(&stream->m_rt->bus->bus_lock);
+	return ret;
+}
+EXPORT_SYMBOL(sdw_disable_stream);
+
+static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
+{
+	struct sdw_master_runtime *m_rt = stream->m_rt;
+	struct sdw_bus *bus = m_rt->bus;
+	int ret = 0;
+
+	/* De-prepare port(s) */
+	ret = sdw_prep_deprep_ports(m_rt, false);
+	if (ret < 0) {
+		dev_err(bus->dev, "De-prepare port(s) failed: %d", ret);
+		return ret;
+	}
+
+	bus->params.bandwidth -= m_rt->stream->params.rate *
+		m_rt->ch_count * m_rt->stream->params.bps;
+
+	if (!bus->params.bandwidth) {
+		bus->params.row = 0;
+		bus->params.col = 0;
+		goto exit;
+
+	}
+
+	/* Program params */
+	ret = sdw_program_params(bus);
+	if (ret < 0) {
+		dev_err(bus->dev, "Program params failed: %d", ret);
+		return ret;
+	}
+
+	return do_bank_switch(stream);
+
+exit:
+	stream->state = SDW_STREAM_DEPREPARED;
+
+	return ret;
+}
+
+/**
+ * sdw_deprepare_stream() - Deprepare SoundWire stream
+ *
+ * @stream: Soundwire stream
+ *
+ * Documentation/soundwire/stream.txt explains this API in detail
+ */
+int sdw_deprepare_stream(struct sdw_stream_runtime *stream)
+{
+	int ret = 0;
+
+	if (!stream) {
+		pr_err("SoundWire: Handle not found for stream");
+		return -EINVAL;
+	}
+
+	mutex_lock(&stream->m_rt->bus->bus_lock);
+
+	ret = _sdw_deprepare_stream(stream);
+	if (ret < 0)
+		pr_err("De-prepare for stream:%d failed: %d", ret, ret);
+
+	mutex_unlock(&stream->m_rt->bus->bus_lock);
+	return ret;
+}
+EXPORT_SYMBOL(sdw_deprepare_stream);
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index ff4b0134897e..7cebb7da1a8c 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -791,6 +791,10 @@  int sdw_stream_remove_master(struct sdw_bus *bus,
 		struct sdw_stream_runtime *stream);
 int sdw_stream_remove_slave(struct sdw_slave *slave,
 		struct sdw_stream_runtime *stream);
+int sdw_prepare_stream(struct sdw_stream_runtime *stream);
+int sdw_enable_stream(struct sdw_stream_runtime *stream);
+int sdw_disable_stream(struct sdw_stream_runtime *stream);
+int sdw_deprepare_stream(struct sdw_stream_runtime *stream);
 
 /* messaging and data APIs */