From patchwork Wed Apr 25 09:39:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vinod Koul X-Patchwork-Id: 141630 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp627062lji; Wed, 25 Apr 2018 02:35:25 -0700 (PDT) X-Google-Smtp-Source: AIpwx48gpg+KMoOt/1BNFo937cGTY/6uFI7xT1OuBqlZefHSX0Nx0Qi4rIy0mZvuucMwlp4X2VTi X-Received: by 2002:adf:e549:: with SMTP id z9-v6mr16656182wrm.186.1524648925541; Wed, 25 Apr 2018 02:35:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1524648925; cv=none; d=google.com; s=arc-20160816; b=zYx8PWemQo3RIuyrXnRvPXB3pBYWZnNlGg2DQV5RZP9K+U6AO+77RlqWNxPIfG7X5B 8DuTduMVmHNc7MfHPhe7FBmrv4JHpuSH6m9ioGsUc256lYrCrg/Y+gYMdbzyR0dcEOl+ RP5+2jrR0jkoBG3MYyp6K6Hcs2LWNWHuvySVBk72dvj9xVAm+x38SLddRXTYFbdsFKjd B2m2Yk6Ko30CtYVCpkd2MHHhIHW5TAUc451rWWzWmHUwTeP4qj7ytwg6rBBtB7h+eRi+ wdTsIsfMKvdSGeEkOag8DkmOQU9aPoWHqpEJZ39r2YqLUvFdwTKyBL4FYlFlz2ZzB0BV 5M0w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:delivered-to:arc-authentication-results; bh=8oTqNxen9OwuM5DxO5f+Z1d+C0Owx6OpxldnQLJIYRs=; b=h7B7b6sYDODNS+bLVUPXhduxnxp6eZbjbS3FjFwC0Dmx5v3/agee4/ejMqR4p3KIKY iuWEF2YRD/Dcoon+02OffAC9cE2mZ+8ZTzRvU9JqDXRxcs0f49Xm1T/h6kxrnVcM5v0J iuu4NfJn6GP60g4Fv7XU0RcZSgxApeqsJKZNXmCrWPsIxSy7WmmtX0UWEiz8K/bhMXhO M4USlXWg5YivbAnCsflqgZuzsoPCyB6Km6Cm3WJtYPf/mnsxhr502yeW6yMqWHn9qoxM 3d/+WxaSEfXbL1xqD8mPlddPsmOaRhnl+I+tNsjK77YChbIoO2ndhxxEPQVqbyE16ZNa eTmA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of alsa-devel-bounces@alsa-project.org designates 77.48.224.243 as permitted sender) smtp.mailfrom=alsa-devel-bounces@alsa-project.org Return-Path: Received: from alsa0.perex.cz (alsa0.perex.cz. [77.48.224.243]) by mx.google.com with ESMTP id t80-v6si13328224wrc.72.2018.04.25.02.35.25; Wed, 25 Apr 2018 02:35:25 -0700 (PDT) Received-SPF: pass (google.com: domain of alsa-devel-bounces@alsa-project.org designates 77.48.224.243 as permitted sender) client-ip=77.48.224.243; Authentication-Results: mx.google.com; spf=pass (google.com: domain of alsa-devel-bounces@alsa-project.org designates 77.48.224.243 as permitted sender) smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id B344C267761; Wed, 25 Apr 2018 11:35:00 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id ADAE526776A; Wed, 25 Apr 2018 11:34:56 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail1.perex.cz X-Spam-Level: X-Spam-Status: No, score=-5.0 required=5.0 tests=RCVD_IN_DNSWL_HI autolearn=disabled version=3.4.0 Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by alsa0.perex.cz (Postfix) with ESMTP id 1CAE726775F for ; Wed, 25 Apr 2018 11:34:53 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 25 Apr 2018 02:34:53 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.49,325,1520924400"; d="scan'208";a="34503797" Received: from vkoul-udesk7.iind.intel.com ([10.223.84.143]) by fmsmga007.fm.intel.com with ESMTP; 25 Apr 2018 02:34:50 -0700 From: Vinod Koul To: Greg KH Date: Wed, 25 Apr 2018 15:09:13 +0530 Message-Id: <1524649163-12088-4-git-send-email-vkoul@kernel.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1524649163-12088-1-git-send-email-vkoul@kernel.org> References: <1524649163-12088-1-git-send-email-vkoul@kernel.org> Cc: ALSA , tiwai@suse.de, Pierre-Louis Bossart , liam.r.girdwood@linux.intel.com, patches.audio@intel.com, Vinod Koul , broonie@kernel.org, Sanyog Kale Subject: [alsa-devel] [PATCH v5 03/13] soundwire: Add support for port management X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org From: Sanyog Kale Add Soundwire port data structures and APIS for initialization and release of ports. Signed-off-by: Sanyog Kale Signed-off-by: Shreyas NC Signed-off-by: Vinod Koul --- drivers/soundwire/bus.h | 25 +++++++ drivers/soundwire/stream.c | 149 +++++++++++++++++++++++++++++++++++++++++- include/linux/soundwire/sdw.h | 67 +++++++++++++++++++ 3 files changed, 239 insertions(+), 2 deletions(-) -- 2.7.4 _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index 2e5043de9a4b..39e6811e435c 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -46,6 +46,27 @@ struct sdw_msg { }; /** + * sdw_port_runtime: Runtime port parameters for Master or Slave + * + * @num: Port number. For audio streams, valid port number ranges from + * [1,14] + * @ch_mask: Channel mask + * @transport_params: Transport parameters + * @port_params: Port parameters + * @port_node: List node for Master or Slave port_list + * + * SoundWire spec has no mention of ports for Master interface but the + * concept is logically extended. + */ +struct sdw_port_runtime { + int num; + int ch_mask; + struct sdw_transport_params transport_params; + struct sdw_port_params port_params; + struct list_head port_node; +}; + +/** * sdw_slave_runtime: Runtime Stream parameters for Slave * * @slave: Slave handle @@ -53,12 +74,14 @@ struct sdw_msg { * @ch_count: Number of channels handled by the Slave for * this stream * @m_rt_node: sdw_master_runtime list node + * @port_list: List of Slave Ports configured for this stream */ struct sdw_slave_runtime { struct sdw_slave *slave; enum sdw_data_direction direction; unsigned int ch_count; struct list_head m_rt_node; + struct list_head port_list; }; /** @@ -70,6 +93,7 @@ struct sdw_slave_runtime { * @ch_count: Number of channels handled by the Master for * this stream, can be zero. * @slave_rt_list: Slave runtime list + * @port_list: List of Master Ports configured for this stream, can be zero. * @bus_node: sdw_bus m_rt_list node */ struct sdw_master_runtime { @@ -78,6 +102,7 @@ struct sdw_master_runtime { enum sdw_data_direction direction; unsigned int ch_count; struct list_head slave_rt_list; + struct list_head port_list; struct list_head bus_node; }; diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 15537c39185d..5e97eea6f7c4 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -81,6 +81,7 @@ static struct sdw_master_runtime return NULL; /* Initialization of Master runtime handle */ + INIT_LIST_HEAD(&m_rt->port_list); INIT_LIST_HEAD(&m_rt->slave_rt_list); stream->m_rt = m_rt; @@ -115,6 +116,7 @@ static struct sdw_slave_runtime if (!s_rt) return NULL; + INIT_LIST_HEAD(&s_rt->port_list); s_rt->ch_count = stream_config->ch_count; s_rt->direction = stream_config->direction; s_rt->slave = slave; @@ -122,6 +124,41 @@ static struct sdw_slave_runtime return s_rt; } +static void sdw_master_port_release(struct sdw_bus *bus, + struct sdw_master_runtime *m_rt) +{ + struct sdw_port_runtime *p_rt, *_p_rt; + + list_for_each_entry_safe(p_rt, _p_rt, + &m_rt->port_list, port_node) { + + list_del(&p_rt->port_node); + kfree(p_rt); + } +} + +static void sdw_slave_port_release(struct sdw_bus *bus, + struct sdw_slave *slave, + struct sdw_stream_runtime *stream) +{ + struct sdw_port_runtime *p_rt, *_p_rt; + struct sdw_master_runtime *m_rt = stream->m_rt; + struct sdw_slave_runtime *s_rt; + + list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { + + if (s_rt->slave != slave) + continue; + + list_for_each_entry_safe(p_rt, _p_rt, + &s_rt->port_list, port_node) { + + list_del(&p_rt->port_node); + kfree(p_rt); + } + } +} + /** * sdw_release_slave_stream() - Free Slave(s) runtime handle * @@ -176,7 +213,7 @@ static void sdw_release_master_stream(struct sdw_stream_runtime *stream) * @bus: SDW Bus instance * @stream: SoundWire stream * - * This removes and frees master_rt from a stream + * This removes and frees port_rt and master_rt from a stream */ int sdw_stream_remove_master(struct sdw_bus *bus, struct sdw_stream_runtime *stream) @@ -184,6 +221,7 @@ int sdw_stream_remove_master(struct sdw_bus *bus, mutex_lock(&bus->bus_lock); sdw_release_master_stream(stream); + sdw_master_port_release(bus, stream->m_rt); stream->state = SDW_STREAM_RELEASED; kfree(stream->m_rt); stream->m_rt = NULL; @@ -200,13 +238,14 @@ EXPORT_SYMBOL(sdw_stream_remove_master); * @slave: SDW Slave instance * @stream: SoundWire stream * - * This removes and frees slave_rt from a stream + * This removes and frees port_rt and slave_rt from a stream */ int sdw_stream_remove_slave(struct sdw_slave *slave, struct sdw_stream_runtime *stream) { mutex_lock(&slave->bus->bus_lock); + sdw_slave_port_release(slave->bus, slave, stream); sdw_release_slave_stream(slave, stream); mutex_unlock(&slave->bus->bus_lock); @@ -261,15 +300,109 @@ static int sdw_config_stream(struct device *dev, return 0; } +static int sdw_is_valid_port_range(struct device *dev, + struct sdw_port_runtime *p_rt) +{ + if (!SDW_VALID_PORT_RANGE(p_rt->num)) { + dev_err(dev, + "SoundWire: Invalid port number :%d", p_rt->num); + return -EINVAL; + } + + return 0; +} + +static struct sdw_port_runtime *sdw_port_alloc(struct device *dev, + struct sdw_port_config *port_config, + int port_index) +{ + struct sdw_port_runtime *p_rt; + + p_rt = kzalloc(sizeof(*p_rt), GFP_KERNEL); + if (!p_rt) + return NULL; + + p_rt->ch_mask = port_config[port_index].ch_mask; + p_rt->num = port_config[port_index].num; + + return p_rt; +} + +static int sdw_master_port_config(struct sdw_bus *bus, + struct sdw_master_runtime *m_rt, + struct sdw_port_config *port_config, + unsigned int num_ports) +{ + struct sdw_port_runtime *p_rt; + int i; + + /* Iterate for number of ports to perform initialization */ + for (i = 0; i < num_ports; i++) { + + p_rt = sdw_port_alloc(bus->dev, port_config, i); + if (!p_rt) + return -ENOMEM; + + /* + * TODO: Check port capabilities for requested + * configuration (audio mode support) + */ + + list_add_tail(&p_rt->port_node, &m_rt->port_list); + } + + return 0; +} + +static int sdw_slave_port_config(struct sdw_slave *slave, + struct sdw_slave_runtime *s_rt, + struct sdw_port_config *port_config, + unsigned int num_config) +{ + struct sdw_port_runtime *p_rt; + int i, ret; + + /* Iterate for number of ports to perform initialization */ + for (i = 0; i < num_config; i++) { + + p_rt = sdw_port_alloc(&slave->dev, port_config, i); + if (!p_rt) + return -ENOMEM; + + /* + * TODO: Check valid port range as defined by DisCo/ + * slave + */ + ret = sdw_is_valid_port_range(&slave->dev, p_rt); + if (ret < 0) { + kfree(p_rt); + return ret; + } + + /* + * TODO: Check port capabilities for requested + * configuration (audio mode support) + */ + + list_add_tail(&p_rt->port_node, &s_rt->port_list); + } + + return 0; +} + /** * sdw_stream_add_master() - Allocate and add master runtime to a stream * * @bus: SDW Bus instance * @stream_config: Stream configuration for audio stream + * @port_config: Port configuration for audio stream + * @num_ports: Number of ports * @stream: SoundWire stream */ int sdw_stream_add_master(struct sdw_bus *bus, struct sdw_stream_config *stream_config, + struct sdw_port_config *port_config, + unsigned int num_ports, struct sdw_stream_runtime *stream) { struct sdw_master_runtime *m_rt = NULL; @@ -290,6 +423,10 @@ int sdw_stream_add_master(struct sdw_bus *bus, if (ret) goto stream_error; + ret = sdw_master_port_config(bus, m_rt, port_config, num_ports); + if (ret) + goto stream_error; + stream->state = SDW_STREAM_CONFIGURED; stream_error: @@ -307,9 +444,13 @@ EXPORT_SYMBOL(sdw_stream_add_master); * @slave: SDW Slave instance * @stream_config: Stream configuration for audio stream * @stream: SoundWire stream + * @port_config: Port configuration for audio stream + * @num_ports: Number of ports */ int sdw_stream_add_slave(struct sdw_slave *slave, struct sdw_stream_config *stream_config, + struct sdw_port_config *port_config, + unsigned int num_ports, struct sdw_stream_runtime *stream) { struct sdw_slave_runtime *s_rt; @@ -346,6 +487,10 @@ int sdw_stream_add_slave(struct sdw_slave *slave, list_add_tail(&s_rt->m_rt_node, &m_rt->slave_rt_list); + ret = sdw_slave_port_config(slave, s_rt, port_config, num_ports); + if (ret) + goto stream_error; + stream->state = SDW_STREAM_CONFIGURED; goto error; diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 7a41e3860efc..e7567c28e630 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -26,6 +26,8 @@ struct sdw_slave; #define SDW_MAX_DEVICES 11 +#define SDW_VALID_PORT_RANGE(n) (n <= 14 && n >= 1) + /** * enum sdw_slave_status - Slave status * @SDW_SLAVE_UNATTACHED: Slave is not attached with the bus. @@ -430,6 +432,56 @@ int sdw_handle_slave_status(struct sdw_bus *bus, * SDW master structures and APIs */ +/** + * struct sdw_port_params: Data Port parameters + * + * @num: Port number + * @bps: Word length of the Port + * @flow_mode: Port Data flow mode + * @data_mode: Test modes or normal mode + * + * This is used to program the Data Port based on Data Port stream + * parameters. + */ +struct sdw_port_params { + unsigned int num; + unsigned int bps; + unsigned int flow_mode; + unsigned int data_mode; +}; + +/** + * struct sdw_transport_params: Data Port Transport Parameters + * + * @blk_grp_ctrl_valid: Port implements block group control + * @num: Port number + * @blk_grp_ctrl: Block group control value + * @sample_interval: Sample interval + * @offset1: Blockoffset of the payload data + * @offset2: Blockoffset of the payload data + * @hstart: Horizontal start of the payload data + * @hstop: Horizontal stop of the payload data + * @blk_pkg_mode: Block per channel or block per port + * @lane_ctrl: Data lane Port uses for Data transfer. Currently only single + * data lane is supported in bus + * + * This is used to program the Data Port based on Data Port transport + * parameters. All these parameters are banked and can be modified + * during a bank switch without any artifacts in audio stream. + */ +struct sdw_transport_params { + bool blk_grp_ctrl_valid; + unsigned int port_num; + unsigned int blk_grp_ctrl; + unsigned int sample_interval; + unsigned int offset1; + unsigned int offset2; + unsigned int hstart; + unsigned int hstop; + unsigned int blk_pkg_mode; + unsigned int lane_ctrl; +}; + struct sdw_msg; /** @@ -498,6 +550,17 @@ int sdw_add_bus_master(struct sdw_bus *bus); void sdw_delete_bus_master(struct sdw_bus *bus); /** + * sdw_port_config: Master or Slave Port configuration + * + * @num: Port number + * @ch_mask: channels mask for port + */ +struct sdw_port_config { + unsigned int num; + unsigned int ch_mask; +}; + +/** * sdw_stream_config: Master or Slave stream configuration * * @frame_rate: Audio frame rate of the stream, in Hz @@ -569,9 +632,13 @@ struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name); void sdw_release_stream(struct sdw_stream_runtime *stream); int sdw_stream_add_master(struct sdw_bus *bus, struct sdw_stream_config *stream_config, + struct sdw_port_config *port_config, + unsigned int num_ports, struct sdw_stream_runtime *stream); int sdw_stream_add_slave(struct sdw_slave *slave, struct sdw_stream_config *stream_config, + struct sdw_port_config *port_config, + unsigned int num_ports, struct sdw_stream_runtime *stream); int sdw_stream_remove_master(struct sdw_bus *bus, struct sdw_stream_runtime *stream);