From patchwork Wed Feb 1 20:07:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liam Breck X-Patchwork-Id: 9550633 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 C2EE660236 for ; Wed, 1 Feb 2017 20:08:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B33AC2840E for ; Wed, 1 Feb 2017 20:08:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A7A502846F; Wed, 1 Feb 2017 20:08:09 +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=-6.3 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DC4422840E for ; Wed, 1 Feb 2017 20:08:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750971AbdBAUIH (ORCPT ); Wed, 1 Feb 2017 15:08:07 -0500 Received: from mail-pg0-f68.google.com ([74.125.83.68]:35310 "EHLO mail-pg0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750858AbdBAUIG (ORCPT ); Wed, 1 Feb 2017 15:08:06 -0500 Received: by mail-pg0-f68.google.com with SMTP id 204so35073842pge.2 for ; Wed, 01 Feb 2017 12:08:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=Z5/f8hS61nhc6iogBeg4sezbDsvOOBAuRHnzdFTnd9A=; b=ui16CeGGOrkhkDtqLvdk349OXbg4KbnUtsjgYDy2XpkCuDn/e/Z3TytFmcVmsuilrH 0IVxlzMzeQbpEyL1YX3RUjIQt73TXwnr/nx5Z9Tg2TL794Z6A2ssPkA8ptFLl7A6TBmS Wlj+8ysA6cGBuQR1rMO5aoi6FU0FrmHC06fJ5ahYlq3/3bSSoE39S4yTw1FW86Kd5ReA nLhx69M6cHowXCP7ryDYMIJcI3gxWPdzB94NDoEysjnXNZNjCwo8R1Q+GztOlh4m1K7B zOW0TGlFJMjVUAKTm8yEOCFNV7wVObZkMMEM13eqbbU2TPrVfkay2B1hi3NJnzkMkBKs xjcA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=Z5/f8hS61nhc6iogBeg4sezbDsvOOBAuRHnzdFTnd9A=; b=clD51t3Xrl65p8/sRma3EFexWi+ve7T19re2TefmqQT9DzBggfUwREnIt6FkUi3IRu Hmf9ukjM1GOwTw7pEy0Rd+ycfjP8KeL4F3vKZ+wdWvo04JgiFrNL6jQd099sSBK5jFci yKHmyFioJlK+ihlV9cPLhGptE2xGFX4a0TKkzU1SimAxu7yUTRBEG46ouZarrnQ99IuK Nmg9RaoDqRpoUxztqSG0uc0nrsxgm0YZ3PErsN6YhQ0ODjvmpENvmLsw5rhw0XVr5s+d AGufs3ntRKzZInGnilbnSWl1llxuYhMUIkZ7Xqd4gR0kNFRGWONGiuVtotB7kUfTvPSn 7kUQ== X-Gm-Message-State: AIkVDXLAoycZqz9EAQD3tBlmu8xtLjOjBqgVzDfCariqcxg67Z0pbiKbzD74nqor2+rncw== X-Received: by 10.84.197.131 with SMTP id n3mr6890364pld.69.1485979685624; Wed, 01 Feb 2017 12:08:05 -0800 (PST) Received: from localhost.localdomain (c-73-223-93-234.hsd1.ca.comcast.net. [73.223.93.234]) by smtp.gmail.com with ESMTPSA id c64sm51796034pfa.45.2017.02.01.12.08.04 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 01 Feb 2017 12:08:04 -0800 (PST) From: Liam Breck To: Mark Brown Cc: alsa-devel@alsa-project.org, linux-omap@vger.kernel.org, Tony Lindgren , Peter Ujfalusi , Matt Ranostay , Liam Breck Subject: [PATCH v8.2 1/1] ASoC: omap-mcbsp: Add PM QoS support for McBSP to prevent glitches Date: Wed, 1 Feb 2017 12:07:42 -0800 Message-Id: <20170201200742.28977-1-liam@networkimprov.net> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170127225337.17830-1-liam@networkimprov.net> References: <20170127225337.17830-1-liam@networkimprov.net> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Matt Ranostay We can get audio errors if hitting deeper idle states on omaps: [alsa.c:230] error: Fatal problem with alsa output, error -5. [audio.c:614] error: Error in writing audio (Input/output error?)! This seems to happen with off mode idle enabled as power for the whole SoC may get cut off between filling the McBSP fifo using DMA. While active DMA blocks deeper idle states in hardware, McBSP activity does not seem to do so. Basing the QoS latency calculation on the FIFO size, threshold, sample rate, and channels. Based on the original patch by Tony Lindgren Link: https://patchwork.kernel.org/patch/9305867/ Cc: Tony Lindgren Cc: Peter Ujfalusi Signed-off-by: Matt Ranostay Signed-off-by: Liam Breck Tested-by: Tony Lindgren Acked-by: Peter Ujfalusi --- Changes from v1: * add calculations for latency per number of FIFO locations Changes from v2: * add missing mcbsp.h header change Changes from v3: * base the latency calculations on threshold, buffer size, sample rate, and channels Changes from v4: * using Peter Ujfalusi's suggestions for restoring a higher latency on audio stream completion, or if not applicable remove the QoS request Changes from v5: * clean up latency checking logic * move logic to .prepare and .shutdown to avoid functions that can sleep Changes from v6: * move QoS removal to asoc_mcbsp_remove from omap_mcbsp_cleanup * also remove header include that is unneeded Changes from v7: * fix issue reported by Tony Lindgreen that a player application could close the card after hw_params, and cause an invalid pm_qos_remove_request() Changes from v8: 1 add Liam Signed-off-by 2 move From line sound/soc/omap/mcbsp.h | 3 +++ sound/soc/omap/omap-mcbsp.c | 48 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h index 61e93b1c185d..46ae1269a698 100644 --- a/sound/soc/omap/mcbsp.h +++ b/sound/soc/omap/mcbsp.h @@ -323,8 +323,11 @@ struct omap_mcbsp { unsigned int fmt; unsigned int in_freq; + unsigned int latency[2]; int clk_div; int wlen; + + struct pm_qos_request pm_qos_req; }; void omap_mcbsp_config(struct omap_mcbsp *mcbsp, diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index d018e966e533..6b40bdbef336 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -157,6 +157,17 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); + int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; + int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; + + if (mcbsp->latency[stream2]) + pm_qos_update_request(&mcbsp->pm_qos_req, + mcbsp->latency[stream2]); + else if (mcbsp->latency[stream1]) + pm_qos_remove_request(&mcbsp->pm_qos_req); + + mcbsp->latency[stream1] = 0; if (!cpu_dai->active) { omap_mcbsp_free(mcbsp); @@ -164,6 +175,28 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, } } +static int omap_mcbsp_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); + struct pm_qos_request *pm_qos_req = &mcbsp->pm_qos_req; + int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; + int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; + int latency = mcbsp->latency[stream2]; + + /* Prevent omap hardware from hitting off between FIFO fills */ + if (!latency || mcbsp->latency[stream1] < latency) + latency = mcbsp->latency[stream1]; + + if (pm_qos_request_active(pm_qos_req)) + pm_qos_update_request(pm_qos_req, latency); + else if (latency) + pm_qos_add_request(pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency); + + return 0; +} + static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) { @@ -226,6 +259,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, int wlen, channels, wpf; int pkt_size = 0; unsigned int format, div, framesize, master; + unsigned int buffer_size = mcbsp->pdata->buffer_size; dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream); channels = params_channels(params); @@ -240,7 +274,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, default: return -EINVAL; } - if (mcbsp->pdata->buffer_size) { + if (buffer_size) { + int latency; + if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { int period_words, max_thrsh; int divider = 0; @@ -271,6 +307,12 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, /* Use packet mode for non mono streams */ pkt_size = channels; } + + latency = ((((buffer_size - pkt_size) / channels) * 1000) + / (params->rate_num / params->rate_den)); + + mcbsp->latency[substream->stream] = latency; + omap_mcbsp_set_threshold(substream, pkt_size); } @@ -554,6 +596,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, static const struct snd_soc_dai_ops mcbsp_dai_ops = { .startup = omap_mcbsp_dai_startup, .shutdown = omap_mcbsp_dai_shutdown, + .prepare = omap_mcbsp_dai_prepare, .trigger = omap_mcbsp_dai_trigger, .delay = omap_mcbsp_dai_delay, .hw_params = omap_mcbsp_dai_hw_params, @@ -835,6 +878,9 @@ static int asoc_mcbsp_remove(struct platform_device *pdev) if (mcbsp->pdata->ops && mcbsp->pdata->ops->free) mcbsp->pdata->ops->free(mcbsp->id); + if (pm_qos_request_active(&mcbsp->pm_qos_req)) + pm_qos_remove_request(&mcbsp->pm_qos_req); + omap_mcbsp_cleanup(mcbsp); clk_put(mcbsp->fclk);