From patchwork Mon Oct 7 15:31:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Dooks X-Patchwork-Id: 1172856 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=codethink.co.uk Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46n4G86gxMz9sP7 for ; Tue, 8 Oct 2019 02:31:44 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728874AbfJGPbm (ORCPT ); Mon, 7 Oct 2019 11:31:42 -0400 Received: from imap1.codethink.co.uk ([176.9.8.82]:56072 "EHLO imap1.codethink.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728868AbfJGPbl (ORCPT ); Mon, 7 Oct 2019 11:31:41 -0400 Received: from [167.98.27.226] (helo=rainbowdash.codethink.co.uk) by imap1.codethink.co.uk with esmtpsa (Exim 4.84_2 #1 (Debian)) id 1iHUz4-0003mh-QW; Mon, 07 Oct 2019 16:31:38 +0100 Received: from ben by rainbowdash.codethink.co.uk with local (Exim 4.92.2) (envelope-from ) id 1iHUz4-0001IU-Ea; Mon, 07 Oct 2019 16:31:38 +0100 From: Ben Dooks To: linux-tegra@vger.kernel.org, alsa-devel@alsa-project.org, Jaroslav Kysela , Takashi Iwai , Liam Girdwood , Mark Brown , Thierry Reding , Jonathan Hunter Cc: linux-kernel@lists.codethink.co.uk, Ben Dooks Subject: [PATCH v4 6/7] ASoC: tegra: config fifos on hw_param changes Date: Mon, 7 Oct 2019 16:31:35 +0100 Message-Id: <20191007153136.4920-7-ben.dooks@codethink.co.uk> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191007153136.4920-1-ben.dooks@codethink.co.uk> References: <20191007153136.4920-1-ben.dooks@codethink.co.uk> MIME-Version: 1.0 Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org If the hw_params uses a different bit or channel count, then we need to change both the I2S unit's CIF configuration as well as the APBIF one. To allow changing the APBIF, add a call to reconfigure the RX or TX FIFO without changing the DMA or allocation, and get the I2S driver to call it once the hw params have been calculate. Signed-off-by: Ben Dooks --- sound/soc/tegra/tegra30_ahub.c | 115 ++++++++++++++++++--------------- sound/soc/tegra/tegra30_ahub.h | 5 ++ sound/soc/tegra/tegra30_i2s.c | 2 + 3 files changed, 69 insertions(+), 53 deletions(-) diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index 952381260dc3..24bc03428b45 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -84,12 +84,40 @@ static int tegra30_ahub_runtime_resume(struct device *dev) return 0; } +int tegra30_ahub_setup_rx_fifo(enum tegra30_ahub_rxcif rxcif, + struct tegra30_ahub_cif_conf *cif_conf) +{ + int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; + u32 reg, val; + + pm_runtime_get_sync(ahub->dev); + + reg = TEGRA30_AHUB_CHANNEL_CTRL + + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK | + TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK); + val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) | + TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN | + TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16; + tegra30_apbif_write(reg, val); + + cif_conf->direction = TEGRA30_AUDIOCIF_DIRECTION_RX; + + reg = TEGRA30_AHUB_CIF_RX_CTRL + + (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); + ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, cif_conf); + + pm_runtime_put(ahub->dev); + return 0; +} +EXPORT_SYMBOL_GPL(tegra30_ahub_setup_rx_fifo); + int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, char *dmachan, int dmachan_len, dma_addr_t *fiforeg) { int channel; - u32 reg, val; struct tegra30_ahub_cif_conf cif_conf; channel = find_first_zero_bit(ahub->rx_usage, @@ -104,37 +132,14 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO + (channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE); - pm_runtime_get_sync(ahub->dev); + memset(&cif_conf, 0, sizeof(cif_conf)); - reg = TEGRA30_AHUB_CHANNEL_CTRL + - (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); - val = tegra30_apbif_read(reg); - val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK | - TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK); - val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) | - TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN | - TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16; - tegra30_apbif_write(reg, val); - - cif_conf.threshold = 0; cif_conf.audio_channels = 2; cif_conf.client_channels = 2; cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16; cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16; - cif_conf.expand = 0; - cif_conf.stereo_conv = 0; - cif_conf.replicate = 0; - cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_RX; - cif_conf.truncate = 0; - cif_conf.mono_conv = 0; - - reg = TEGRA30_AHUB_CIF_RX_CTRL + - (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); - ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf); - - pm_runtime_put(ahub->dev); - return 0; + return tegra30_ahub_setup_rx_fifo(*rxcif, &cif_conf); } EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo); @@ -186,12 +191,40 @@ int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif) } EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo); +int tegra30_ahub_setup_tx_fifo(enum tegra30_ahub_txcif txcif, + struct tegra30_ahub_cif_conf *cif_conf) +{ + int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; + u32 reg, val; + + pm_runtime_get_sync(ahub->dev); + + reg = TEGRA30_AHUB_CHANNEL_CTRL + + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); + val = tegra30_apbif_read(reg); + val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK | + TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK); + val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) | + TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN | + TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16; + tegra30_apbif_write(reg, val); + + cif_conf->direction = TEGRA30_AUDIOCIF_DIRECTION_TX; + + reg = TEGRA30_AHUB_CIF_TX_CTRL + + (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); + ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, cif_conf); + + pm_runtime_put(ahub->dev); + return 0; +} +EXPORT_SYMBOL_GPL(tegra30_ahub_setup_tx_fifo); + int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, char *dmachan, int dmachan_len, dma_addr_t *fiforeg) { int channel; - u32 reg, val; struct tegra30_ahub_cif_conf cif_conf; channel = find_first_zero_bit(ahub->tx_usage, @@ -206,37 +239,13 @@ int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO + (channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE); - pm_runtime_get_sync(ahub->dev); - - reg = TEGRA30_AHUB_CHANNEL_CTRL + - (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); - val = tegra30_apbif_read(reg); - val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK | - TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK); - val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) | - TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN | - TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16; - tegra30_apbif_write(reg, val); - - cif_conf.threshold = 0; + memset(&cif_conf, 0, sizeof(cif_conf)); cif_conf.audio_channels = 2; cif_conf.client_channels = 2; cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16; cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16; - cif_conf.expand = 0; - cif_conf.stereo_conv = 0; - cif_conf.replicate = 0; - cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_TX; - cif_conf.truncate = 0; - cif_conf.mono_conv = 0; - - reg = TEGRA30_AHUB_CIF_TX_CTRL + - (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); - ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf); - pm_runtime_put(ahub->dev); - - return 0; + return tegra30_ahub_setup_tx_fifo(*txcif, &cif_conf); } EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo); diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h index 6889c5f23d02..26120aee64b3 100644 --- a/sound/soc/tegra/tegra30_ahub.h +++ b/sound/soc/tegra/tegra30_ahub.h @@ -490,6 +490,11 @@ void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg, void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg, struct tegra30_ahub_cif_conf *conf); +extern int tegra30_ahub_setup_tx_fifo(enum tegra30_ahub_txcif txcif, + struct tegra30_ahub_cif_conf *cif_conf); +extern int tegra30_ahub_setup_rx_fifo(enum tegra30_ahub_rxcif, + struct tegra30_ahub_cif_conf *cif_conf); + struct tegra30_ahub_soc_data { u32 mod_list_mask; void (*set_audio_cif)(struct regmap *regmap, diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 76fa3a086e56..a625b5c06789 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -201,9 +201,11 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_RX; + tegra30_ahub_setup_tx_fifo(i2s->playback_fifo_cif, &cif_conf); reg = TEGRA30_I2S_CIF_RX_CTRL; } else { cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_TX; + tegra30_ahub_setup_rx_fifo(i2s->capture_fifo_cif, &cif_conf); reg = TEGRA30_I2S_CIF_TX_CTRL; }