Commit 018d52e8 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'soundwire-4.20-rc1' of...

Merge tag 'soundwire-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire into char-misc-next

Vinod writes:

soundwire updates for 4.20-rc1

 - support for multi-link streaming
 - updates in intel driver for multi-link streaming
 - Update Vinod's email
 - Fix rst formatting

* tag 'soundwire-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire:
  Documentation: soundwire: fix stream.rst markup warnings
  soundwire: intel: Remove duplicate assignment
  MAINTAINERS: Update Vinod's email
  soundwire: intel: Fix uninitialized adev deref
  soundwire: intel: Add pre/post bank switch ops
  soundwire: keep track of Masters in a stream
  soundwire: Add support for multi link bank switch
  soundwire: Handle multiple master instances in a stream
  soundwire: Add support to lock across bus instances
  soundwire: Initialize completion for defer messages
  Documentation: soundwire: Add documentation for multi link
parents 91c45a7a 502c00d9
......@@ -101,6 +101,34 @@ interface. ::
+--------------------+ | |
+----------------+
Example 5: Stereo Stream with L and R channel is rendered by 2 Masters, each
rendering one channel, and is received by two different Slaves, each
receiving one channel. Both Masters and both Slaves are using single port. ::
+---------------+ Clock Signal +---------------+
| Master +----------------------------------+ Slave |
| Interface | | Interface |
| 1 | | 1 |
| | Data Signal | |
| L +----------------------------------+ L |
| (Data) | Data Direction | (Data) |
+---------------+ +-----------------------> +---------------+
+---------------+ Clock Signal +---------------+
| Master +----------------------------------+ Slave |
| Interface | | Interface |
| 2 | | 2 |
| | Data Signal | |
| R +----------------------------------+ R |
| (Data) | Data Direction | (Data) |
+---------------+ +-----------------------> +---------------+
Note: In multi-link cases like above, to lock, one would acquire a global
lock and then go on locking bus instances. But, in this case the caller
framework(ASoC DPCM) guarantees that stream operations on a card are
always serialized. So, there is no race condition and hence no need for
global lock.
SoundWire Stream Management flow
================================
......@@ -174,6 +202,7 @@ per stream. From ASoC DPCM framework, this stream state maybe linked to
.startup() operation.
.. code-block:: c
int sdw_alloc_stream(char * stream_name);
......@@ -200,6 +229,7 @@ only be invoked once by respective Master(s) and Slave(s). From ASoC DPCM
framework, this stream state is linked to .hw_params() operation.
.. code-block:: c
int sdw_stream_add_master(struct sdw_bus * bus,
struct sdw_stream_config * stream_config,
struct sdw_ports_config * ports_config,
......@@ -245,6 +275,7 @@ stream. From ASoC DPCM framework, this stream state is linked to
.prepare() operation.
.. code-block:: c
int sdw_prepare_stream(struct sdw_stream_runtime * stream);
......@@ -274,6 +305,7 @@ stream. From ASoC DPCM framework, this stream state is linked to
.trigger() start operation.
.. code-block:: c
int sdw_enable_stream(struct sdw_stream_runtime * stream);
SDW_STREAM_DISABLED
......@@ -301,6 +333,7 @@ per stream. From ASoC DPCM framework, this stream state is linked to
.trigger() stop operation.
.. code-block:: c
int sdw_disable_stream(struct sdw_stream_runtime * stream);
......@@ -325,6 +358,7 @@ per stream. From ASoC DPCM framework, this stream state is linked to
.trigger() stop operation.
.. code-block:: c
int sdw_deprepare_stream(struct sdw_stream_runtime * stream);
......@@ -349,6 +383,7 @@ all the Master(s) and Slave(s) associated with stream. From ASoC DPCM
framework, this stream state is linked to .hw_free() operation.
.. code-block:: c
int sdw_stream_remove_master(struct sdw_bus * bus,
struct sdw_stream_runtime * stream);
int sdw_stream_remove_slave(struct sdw_slave * slave,
......@@ -361,6 +396,7 @@ stream assigned as part of ALLOCATED state.
In .shutdown() the data structure maintaining stream state are freed up.
.. code-block:: c
void sdw_release_stream(struct sdw_stream_runtime * stream);
Not Supported
......
......@@ -13619,7 +13619,7 @@ F: sound/soc/
F: include/sound/soc*
SOUNDWIRE SUBSYSTEM
M: Vinod Koul <vinod.koul@intel.com>
M: Vinod Koul <vkoul@kernel.org>
M: Sanyog Kale <sanyog.r.kale@intel.com>
R: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
......
......@@ -35,6 +35,11 @@ int sdw_add_bus_master(struct sdw_bus *bus)
INIT_LIST_HEAD(&bus->slaves);
INIT_LIST_HEAD(&bus->m_rt_list);
/*
* Initialize multi_link flag
* TODO: populate this flag by reading property from FW node
*/
bus->multi_link = false;
if (bus->ops->read_prop) {
ret = bus->ops->read_prop(bus);
if (ret < 0) {
......@@ -175,6 +180,7 @@ static inline int do_transfer_defer(struct sdw_bus *bus,
defer->msg = msg;
defer->length = msg->len;
init_completion(&defer->complete);
for (i = 0; i <= retry; i++) {
resp = bus->ops->xfer_msg_defer(bus, msg, defer);
......
......@@ -4,6 +4,8 @@
#ifndef __SDW_BUS_H
#define __SDW_BUS_H
#define DEFAULT_BANK_SWITCH_TIMEOUT 3000
#if IS_ENABLED(CONFIG_ACPI)
int sdw_acpi_find_slaves(struct sdw_bus *bus);
#else
......@@ -99,6 +101,7 @@ struct sdw_slave_runtime {
* this stream, can be zero.
* @slave_rt_list: Slave runtime list
* @port_list: List of Master Ports configured for this stream, can be zero.
* @stream_node: sdw_stream_runtime master_list node
* @bus_node: sdw_bus m_rt_list node
*/
struct sdw_master_runtime {
......@@ -108,6 +111,7 @@ struct sdw_master_runtime {
unsigned int ch_count;
struct list_head slave_rt_list;
struct list_head port_list;
struct list_head stream_node;
struct list_head bus_node;
};
......
......@@ -397,6 +397,69 @@ static int intel_config_stream(struct sdw_intel *sdw,
return -EIO;
}
/*
* bank switch routines
*/
static int intel_pre_bank_switch(struct sdw_bus *bus)
{
struct sdw_cdns *cdns = bus_to_cdns(bus);
struct sdw_intel *sdw = cdns_to_intel(cdns);
void __iomem *shim = sdw->res->shim;
int sync_reg;
/* Write to register only for multi-link */
if (!bus->multi_link)
return 0;
/* Read SYNC register */
sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
sync_reg |= SDW_SHIM_SYNC_CMDSYNC << sdw->instance;
intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
return 0;
}
static int intel_post_bank_switch(struct sdw_bus *bus)
{
struct sdw_cdns *cdns = bus_to_cdns(bus);
struct sdw_intel *sdw = cdns_to_intel(cdns);
void __iomem *shim = sdw->res->shim;
int sync_reg, ret;
/* Write to register only for multi-link */
if (!bus->multi_link)
return 0;
/* Read SYNC register */
sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
/*
* post_bank_switch() ops is called from the bus in loop for
* all the Masters in the steam with the expectation that
* we trigger the bankswitch for the only first Master in the list
* and do nothing for the other Masters
*
* So, set the SYNCGO bit only if CMDSYNC bit is set for any Master.
*/
if (!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK))
return 0;
/*
* Set SyncGO bit to synchronously trigger a bank switch for
* all the masters. A write to SYNCGO bit clears CMDSYNC bit for all
* the Masters.
*/
sync_reg |= SDW_SHIM_SYNC_SYNCGO;
ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg,
SDW_SHIM_SYNC_SYNCGO);
if (ret < 0)
dev_err(sdw->cdns.dev, "Post bank switch failed: %d", ret);
return ret;
}
/*
* DAI routines
*/
......@@ -750,6 +813,8 @@ static struct sdw_master_ops sdw_intel_ops = {
.xfer_msg_defer = cdns_xfer_msg_defer,
.reset_page_addr = cdns_reset_page_addr,
.set_bus_conf = cdns_bus_conf,
.pre_bank_switch = intel_pre_bank_switch,
.post_bank_switch = intel_post_bank_switch,
};
/*
......@@ -780,9 +845,6 @@ static int intel_probe(struct platform_device *pdev)
sdw_intel_ops.read_prop = intel_prop_read;
sdw->cdns.bus.ops = &sdw_intel_ops;
sdw_intel_ops.read_prop = intel_prop_read;
sdw->cdns.bus.ops = &sdw_intel_ops;
platform_set_drvdata(pdev, sdw);
ret = sdw_add_bus_master(&sdw->cdns.bus);
......
......@@ -151,7 +151,7 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
struct acpi_device *adev;
if (acpi_bus_get_device(handle, &adev)) {
dev_err(&adev->dev, "Couldn't find ACPI handle\n");
pr_err("%s: Couldn't find ACPI handle\n", __func__);
return AE_NOT_FOUND;
}
......
This diff is collapsed.
......@@ -678,6 +678,9 @@ struct sdw_master_ops {
* @defer_msg: Defer message
* @clk_stop_timeout: Clock stop timeout computed
* @bank_switch_timeout: Bank switch timeout computed
* @multi_link: Store bus property that indicates if multi links
* are supported. This flag is populated by drivers after reading
* appropriate firmware (ACPI/DT).
*/
struct sdw_bus {
struct device *dev;
......@@ -694,6 +697,7 @@ struct sdw_bus {
struct sdw_defer defer_msg;
unsigned int clk_stop_timeout;
u32 bank_switch_timeout;
bool multi_link;
};
int sdw_add_bus_master(struct sdw_bus *bus);
......@@ -768,14 +772,18 @@ struct sdw_stream_params {
* @params: Stream parameters
* @state: Current state of the stream
* @type: Stream type PCM or PDM
* @m_rt: Master runtime
* @master_list: List of Master runtime(s) in this stream.
* master_list can contain only one m_rt per Master instance
* for a stream
* @m_rt_count: Count of Master runtime(s) in this stream
*/
struct sdw_stream_runtime {
char *name;
struct sdw_stream_params params;
enum sdw_stream_state state;
enum sdw_stream_type type;
struct sdw_master_runtime *m_rt;
struct list_head master_list;
int m_rt_count;
};
struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment