From patchwork Thu Jan 11 06:43:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolin Chen X-Patchwork-Id: 10157303 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id B0B52601A1 for ; Thu, 11 Jan 2018 06:46:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A148D286AE for ; Thu, 11 Jan 2018 06:46:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 93F93286B5; Thu, 11 Jan 2018 06:46:06 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, T_DKIM_INVALID autolearn=no version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 42DD1286AE for ; Thu, 11 Jan 2018 06:46:05 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id C97B8267899; Thu, 11 Jan 2018 07:44:22 +0100 (CET) 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 C34E0267832; Thu, 11 Jan 2018 07:44:13 +0100 (CET) Received: from mail-pf0-f194.google.com (mail-pf0-f194.google.com [209.85.192.194]) by alsa0.perex.cz (Postfix) with ESMTP id 61CDC266E70 for ; Thu, 11 Jan 2018 07:44:11 +0100 (CET) Received: by mail-pf0-f194.google.com with SMTP id y89so869151pfk.0 for ; Wed, 10 Jan 2018 22:44:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=U6l9ZF6y0RPeqCI4LUJ5gNvGGz6uC7cXXazNMTt4rUA=; b=fnpmC+LPJ+6yYx1k8Ym8T2KiHIAAo2Qa0PyHoxycWIWoHLXDl56Nv9S6XmAJanm1zx rt1iomipq/UUFh1n+FiCIyExuIu0cZXefTYcIwXm5hQzYpdvB1IhxItJt8PY3T/D4LjV eYaCaeTwNpiFfFhwm7enjIZtPAHLENnK8pEo0Me89Nr3Oowe1zVZ6ByFxsavykW560Bd /FzrX7J1N6c/mWWgtT6pBel4vE74sb2P/VzFE8/2YrRtfGGVDbH/erYdb49wo5EI3f0u oYvJd8i3K6FGvbO9INuSFnEE+EdFV6aUHUZM5VDxzcc3Qye6v1+8nCq2RVdc4xhK9Bx4 ZY0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=U6l9ZF6y0RPeqCI4LUJ5gNvGGz6uC7cXXazNMTt4rUA=; b=Ybcnzaj91Tp/6aZbBkGRdezDj+r3102XAIV8JfmRKat5ZyXnKFDLDcJONESH45R9gR qG8u2ovsF2hhtppMBWMMHOVM3y9lUw0l+B2FcnJ4QSG0PpkDiGps0QdGSkKEAgC30CSA rA4A69SwaAHBVDiwbr36hSaFmo6dQth+k+KSwGg0IeKobqxs/WdmGXeS3OzNlDYDdU55 u45d1CJtfvQJxXFMitQ3luiw7Q/IBCeqSwkLcBE+l3wp48Nrk6ujgY2ebZscfRqmzjGZ CS7rSWXLf4+q3jLXgFLfSPrhsHckX7yVL9Dt2JafNCrdSGyaKqFFnpKfexV65m6WVt3J XgRg== X-Gm-Message-State: AKGB3mI/38b/JglYiyXZbG3zIBP5XLryQFoI5A6u+xHA8qSR49SAU1TW PJ/KhrHTeq7IXq6/C79rI3A= X-Google-Smtp-Source: ACJfBovF9qAiINinLWgXxrk8Y14yEYrBwLAPFtQ9n+wp2nSiJDPablb4kce/M+/AK60J/XYQXGHVdw== X-Received: by 10.84.130.75 with SMTP id 69mr21620075plc.409.1515653050183; Wed, 10 Jan 2018 22:44:10 -0800 (PST) Received: from Asurada-CZ80.localdomain (c-73-231-2-134.hsd1.ca.comcast.net. [73.231.2.134]) by smtp.gmail.com with ESMTPSA id b69sm27959666pfk.128.2018.01.10.22.44.09 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 10 Jan 2018 22:44:09 -0800 (PST) From: Nicolin Chen To: timur@tabi.org, broonie@kernel.org, mail@maciej.szmigiero.name Date: Wed, 10 Jan 2018 22:43:05 -0800 Message-Id: <1515652995-15996-7-git-send-email-nicoleotsuka@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1515652995-15996-1-git-send-email-nicoleotsuka@gmail.com> References: <1515652995-15996-1-git-send-email-nicoleotsuka@gmail.com> Cc: alsa-devel@alsa-project.org, kernel@pengutronix.de, linux-kernel@vger.kernel.org, caleb@crome.org, lgirdwood@gmail.com, arnaud.mouiche@invoxia.com, lukma@denx.de, fabio.estevam@nxp.com, linuxppc-dev@lists.ozlabs.org Subject: [alsa-devel] [PATCH v2 06/16] ASoC: fsl_ssi: Clean up helper functions of trigger() 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 X-Virus-Scanned: ClamAV using ClamSMTP The trigger() calls fsl_ssi_tx_config() and fsl_ssi_rx_config(), and both of them jump to fsl_ssi_config(). And fsl_ssi_config() later calls another fsl_ssi_rxtx_config(). However, the whole routine, especially fsl_ssi_config() function, is too complicated because of the folowing reasons: 1) It has to handle the concern of the opposite stream. 2) It has to handle cases of offline configurations support. 3) It has to handle enable and disable operations while they're mostly different. Since the enable and disable routines have more differences than TX and RX rountines, this patch simplifies these helper functions with the following changes: - Changing to two helper functions of enable and disable instead of TX and RX. - Removing fsl_ssi_rxtx_config() by separately integrating it to two newly introduced enable & disable functions. Signed-off-by: Nicolin Chen Tested-by: Caleb Crome --- sound/soc/fsl/fsl_ssi.c | 256 +++++++++++++++++++++++------------------------- 1 file changed, 122 insertions(+), 134 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 263c067..09a571a 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -378,31 +378,83 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) } /** - * Enable or disable all rx/tx config flags at once + * Set SCR, SIER, STCR and SRCR registers with cached values in regvals + * + * Notes: + * 1) For offline_config SoCs, enable all necessary bits of both streams + * when 1st stream starts, even if the opposite stream will not start + * 2) It also clears FIFO before setting regvals; SOR is safe to set online */ -static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) +static void fsl_ssi_config_enable(struct fsl_ssi *ssi, bool tx) { - struct regmap *regs = ssi->regs; struct fsl_ssi_regvals *vals = ssi->regvals; + bool dir = tx ? TX : RX; + u32 sier, srcr, stcr; - if (enable) { - regmap_update_bits(regs, REG_SSI_SIER, - vals[RX].sier | vals[TX].sier, - vals[RX].sier | vals[TX].sier); - regmap_update_bits(regs, REG_SSI_SRCR, - vals[RX].srcr | vals[TX].srcr, - vals[RX].srcr | vals[TX].srcr); - regmap_update_bits(regs, REG_SSI_STCR, - vals[RX].stcr | vals[TX].stcr, - vals[RX].stcr | vals[TX].stcr); + /* Clear dirty data in the FIFO; It also prevents channel slipping */ + regmap_update_bits(ssi->regs, REG_SSI_SOR, + SSI_SOR_xX_CLR(tx), SSI_SOR_xX_CLR(tx)); + + /* + * On offline_config SoCs, SxCR and SIER are already configured when + * the previous stream started. So skip all SxCR and SIER settings + * to prevent online reconfigurations, then jump to set SCR directly + */ + if (ssi->soc->offline_config && ssi->streams) + goto enable_scr; + + if (ssi->soc->offline_config) { + /* + * Online reconfiguration not supported, so enable all bits for + * both streams at once to avoid necessity of reconfigurations + */ + srcr = vals[RX].srcr | vals[TX].srcr; + stcr = vals[RX].stcr | vals[TX].stcr; + sier = vals[RX].sier | vals[TX].sier; } else { - regmap_update_bits(regs, REG_SSI_SRCR, - vals[RX].srcr | vals[TX].srcr, 0); - regmap_update_bits(regs, REG_SSI_STCR, - vals[RX].stcr | vals[TX].stcr, 0); - regmap_update_bits(regs, REG_SSI_SIER, - vals[RX].sier | vals[TX].sier, 0); + /* Otherwise, only set bits for the current stream */ + srcr = vals[dir].srcr; + stcr = vals[dir].stcr; + sier = vals[dir].sier; } + + /* Configure SRCR, STCR and SIER at once */ + regmap_update_bits(ssi->regs, REG_SSI_SRCR, srcr, srcr); + regmap_update_bits(ssi->regs, REG_SSI_STCR, stcr, stcr); + regmap_update_bits(ssi->regs, REG_SSI_SIER, sier, sier); + +enable_scr: + /* + * Start DMA before setting TE to avoid FIFO underrun + * which may cause a channel slip or a channel swap + * + * TODO: FIQ cases might also need this upon testing + */ + if (ssi->use_dma && tx) { + int try = 100; + u32 sfcsr; + + /* Enable SSI first to send TX DMA request */ + regmap_update_bits(ssi->regs, REG_SSI_SCR, + SSI_SCR_SSIEN, SSI_SCR_SSIEN); + + /* Busy wait until TX FIFO not empty -- DMA working */ + do { + regmap_read(ssi->regs, REG_SSI_SFCSR, &sfcsr); + if (SSI_SFCSR_TFCNT0(sfcsr)) + break; + } while (--try); + + /* FIFO still empty -- something might be wrong */ + if (!SSI_SFCSR_TFCNT0(sfcsr)) + dev_warn(ssi->dev, "Timeout waiting TX FIFO filling\n"); + } + /* Enable all remaining bits in SCR */ + regmap_update_bits(ssi->regs, REG_SSI_SCR, + vals[dir].scr, vals[dir].scr); + + /* Log the enabled stream to the mask */ + ssi->streams |= BIT(dir); } /** @@ -426,66 +478,53 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) ((vals) & _ssi_xor_shared_bits(vals, avals, aactive)) /** - * Enable or disable SSI configuration. + * Unset SCR, SIER, STCR and SRCR registers with cached values in regvals + * + * Notes: + * 1) For offline_config SoCs, to avoid online reconfigurations, disable all + * bits of both streams at once when the last stream is abort to end + * 2) It also clears FIFO after unsetting regvals; SOR is safe to set online */ -static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, - struct fsl_ssi_regvals *vals) +static void fsl_ssi_config_disable(struct fsl_ssi *ssi, bool tx) { - bool tx = &ssi->regvals[TX] == vals; + struct fsl_ssi_regvals *vals, *avals; + u32 sier, srcr, stcr, scr; bool dir = tx ? TX : RX; - struct regmap *regs = ssi->regs; - struct fsl_ssi_regvals *avals; bool aactive; /* Check if the opposite stream is active */ aactive = ssi->streams & BIT(!dir); - /* Get the opposite direction to keep its values untouched */ - if (&ssi->regvals[RX] == vals) - avals = &ssi->regvals[TX]; - else - avals = &ssi->regvals[RX]; + vals = &ssi->regvals[dir]; - if (!enable) { - /* - * To keep the other stream safe, exclude shared bits between - * both streams, and get safe bits to disable current stream - */ - u32 scr = ssi_excl_shared_bits(vals->scr, avals->scr, aactive); - /* Safely disable SCR register for the stream */ - regmap_update_bits(regs, REG_SSI_SCR, scr, 0); - - /* Log the disabled stream to the mask */ - ssi->streams &= ~BIT(dir); - } + /* Get regvals of the opposite stream to keep opposite stream safe */ + avals = &ssi->regvals[!dir]; /* - * For cases where online configuration is not supported, - * 1) Enable all necessary bits of both streams when 1st stream starts - * even if the opposite stream will not start - * 2) Disable all remaining bits of both streams when last stream ends + * To keep the other stream safe, exclude shared bits between + * both streams, and get safe bits to disable current stream */ - if (ssi->soc->offline_config) { - if ((enable && !ssi->streams) || (!enable && !aactive)) - fsl_ssi_rxtx_config(ssi, enable); + scr = ssi_excl_shared_bits(vals->scr, avals->scr, aactive); - goto config_done; - } + /* Disable safe bits of SCR register for the current stream */ + regmap_update_bits(ssi->regs, REG_SSI_SCR, scr, 0); - /* Online configure single direction while SSI is running */ - if (enable) { - /* Clear FIFO to prevent dirty data or channel slipping */ - regmap_update_bits(ssi->regs, REG_SSI_SOR, - SSI_SOR_xX_CLR(tx), SSI_SOR_xX_CLR(tx)); + /* Log the disabled stream to the mask */ + ssi->streams &= ~BIT(dir); - regmap_update_bits(regs, REG_SSI_SRCR, vals->srcr, vals->srcr); - regmap_update_bits(regs, REG_SSI_STCR, vals->stcr, vals->stcr); - regmap_update_bits(regs, REG_SSI_SIER, vals->sier, vals->sier); - } else { - u32 sier; - u32 srcr; - u32 stcr; + /* + * On offline_config SoCs, if the other stream is active, skip + * SxCR and SIER settings to prevent online reconfigurations + */ + if (ssi->soc->offline_config && aactive) + goto fifo_clear; + if (ssi->soc->offline_config) { + /* Now there is only current stream active, disable all bits */ + srcr = vals->srcr | avals->srcr; + stcr = vals->stcr | avals->stcr; + sier = vals->sier | avals->sier; + } else { /* * To keep the other stream safe, exclude shared bits between * both streams, and get safe bits to disable current stream @@ -493,57 +532,17 @@ static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, sier = ssi_excl_shared_bits(vals->sier, avals->sier, aactive); srcr = ssi_excl_shared_bits(vals->srcr, avals->srcr, aactive); stcr = ssi_excl_shared_bits(vals->stcr, avals->stcr, aactive); - - /* Safely disable other control registers for the stream */ - regmap_update_bits(regs, REG_SSI_SRCR, srcr, 0); - regmap_update_bits(regs, REG_SSI_STCR, stcr, 0); - regmap_update_bits(regs, REG_SSI_SIER, sier, 0); - - /* Clear FIFO to prevent dirty data or channel slipping */ - regmap_update_bits(ssi->regs, REG_SSI_SOR, - SSI_SOR_xX_CLR(tx), SSI_SOR_xX_CLR(tx)); } -config_done: - /* Enabling of subunits is done after configuration */ - if (enable) { - /* - * Start DMA before setting TE to avoid FIFO underrun - * which may cause a channel slip or a channel swap - * - * TODO: FIQ cases might also need this upon testing - */ - if (ssi->use_dma && (vals->scr & SSI_SCR_TE)) { - int i; - int max_loop = 100; - - /* Enable SSI first to send TX DMA request */ - regmap_update_bits(regs, REG_SSI_SCR, - SSI_SCR_SSIEN, SSI_SCR_SSIEN); - - /* Busy wait until TX FIFO not empty -- DMA working */ - for (i = 0; i < max_loop; i++) { - u32 sfcsr; - regmap_read(regs, REG_SSI_SFCSR, &sfcsr); - if (SSI_SFCSR_TFCNT0(sfcsr)) - break; - } - if (i == max_loop) { - dev_err(ssi->dev, - "Timeout waiting TX FIFO filling\n"); - } - } - /* Enable all remaining bits */ - regmap_update_bits(regs, REG_SSI_SCR, vals->scr, vals->scr); - - /* Log the enabled stream to the mask */ - ssi->streams |= BIT(dir); - } -} + /* Clear configurations of SRCR, STCR and SIER at once */ + regmap_update_bits(ssi->regs, REG_SSI_SRCR, srcr, 0); + regmap_update_bits(ssi->regs, REG_SSI_STCR, stcr, 0); + regmap_update_bits(ssi->regs, REG_SSI_SIER, sier, 0); -static void fsl_ssi_rx_config(struct fsl_ssi *ssi, bool enable) -{ - fsl_ssi_config(ssi, enable, &ssi->regvals[RX]); +fifo_clear: + /* Clear remaining data in the FIFO */ + regmap_update_bits(ssi->regs, REG_SSI_SOR, + SSI_SOR_xX_CLR(tx), SSI_SOR_xX_CLR(tx)); } static void fsl_ssi_tx_ac97_saccst_setup(struct fsl_ssi *ssi) @@ -559,21 +558,6 @@ static void fsl_ssi_tx_ac97_saccst_setup(struct fsl_ssi *ssi) } } -static void fsl_ssi_tx_config(struct fsl_ssi *ssi, bool enable) -{ - /* - * SACCST might be modified via AC Link by a CODEC if it sends - * extra bits in their SLOTREQ requests, which'll accidentally - * send valid data to slots other than normal playback slots. - * - * To be safe, configure SACCST right before TX starts. - */ - if (enable && fsl_ssi_is_ac97(ssi)) - fsl_ssi_tx_ac97_saccst_setup(ssi); - - fsl_ssi_config(ssi, enable, &ssi->regvals[TX]); -} - /** * Cache critical bits of SIER, SRCR, STCR and SCR to later set them safely */ @@ -1082,24 +1066,28 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - fsl_ssi_tx_config(ssi, true); - else - fsl_ssi_rx_config(ssi, true); + /* + * SACCST might be modified via AC Link by a CODEC if it sends + * extra bits in their SLOTREQ requests, which'll accidentally + * send valid data to slots other than normal playback slots. + * + * To be safe, configure SACCST right before TX starts. + */ + if (tx && fsl_ssi_is_ac97(ssi)) + fsl_ssi_tx_ac97_saccst_setup(ssi); + fsl_ssi_config_enable(ssi, tx); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - fsl_ssi_tx_config(ssi, false); - else - fsl_ssi_rx_config(ssi, false); + fsl_ssi_config_disable(ssi, tx); break; default: