ASoC: qcom: q6dsp and lpass codec stablity fixes
Merge series from Srinivas Kandagatla <srinivas.kandagatla@linaro.org> From q6dsp side issues are around locking of position pointer and handle From LPASS codec side most of the staiblity issues were around runtime pm,: While testing X13s audio, we found multiple stablity issues this patchset fixes these issues. From q6dsp side issues are around locking of position pointer and handle multiple prepare cases along with pulse audio timerbased scheduling workaround. From LPASS codec side most of the staiblity issues were around runtime pm, hitting various issues as the codec was firstly resetting the soundwire block for every clk disable/enable which is taking the slaves out of sync and resulting in re-enumerating. Second issue was around fsgen clk is not brining up the codec out of suspend as it was not added after runtime pm enabled. Final issue was with codec mclk rate which should have been 192KHz same as npl instead of 96KHz. We were getting lucky as wsa drivers are setting the same clk to 192KHz. With this patches, x13s audio is pretty stable.
This commit is contained in:
commit
906b6f7b20
|
@ -366,7 +366,7 @@
|
|||
#define CDC_RX_DSD1_CFG2 (0x0F8C)
|
||||
#define RX_MAX_OFFSET (0x0F8C)
|
||||
|
||||
#define MCLK_FREQ 9600000
|
||||
#define MCLK_FREQ 19200000
|
||||
|
||||
#define RX_MACRO_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
|
||||
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
|
||||
|
@ -2296,10 +2296,8 @@ static int rx_macro_mux_put(struct snd_kcontrol *kcontrol,
|
|||
|
||||
aif_rst = rx->rx_port_value[widget->shift];
|
||||
if (!rx_port_value) {
|
||||
if (aif_rst == 0) {
|
||||
dev_err(component->dev, "%s:AIF reset already\n", __func__);
|
||||
if (aif_rst == 0)
|
||||
return 0;
|
||||
}
|
||||
if (aif_rst > RX_MACRO_AIF4_PB) {
|
||||
dev_err(component->dev, "%s: Invalid AIF reset\n", __func__);
|
||||
return 0;
|
||||
|
@ -3441,16 +3439,10 @@ static int swclk_gate_enable(struct clk_hw *hw)
|
|||
}
|
||||
|
||||
rx_macro_mclk_enable(rx, true);
|
||||
regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_RX_SWR_RESET_MASK,
|
||||
CDC_RX_SWR_RESET);
|
||||
|
||||
regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_RX_SWR_CLK_EN_MASK, 1);
|
||||
|
||||
regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_RX_SWR_RESET_MASK, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3579,7 +3571,7 @@ static int rx_macro_probe(struct platform_device *pdev)
|
|||
|
||||
/* set MCLK and NPL rates */
|
||||
clk_set_rate(rx->mclk, MCLK_FREQ);
|
||||
clk_set_rate(rx->npl, 2 * MCLK_FREQ);
|
||||
clk_set_rate(rx->npl, MCLK_FREQ);
|
||||
|
||||
ret = clk_prepare_enable(rx->macro);
|
||||
if (ret)
|
||||
|
@ -3601,9 +3593,16 @@ static int rx_macro_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_fsgen;
|
||||
|
||||
ret = rx_macro_register_mclk_output(rx);
|
||||
if (ret)
|
||||
goto err_clkout;
|
||||
/* reset swr block */
|
||||
regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_RX_SWR_RESET_MASK,
|
||||
CDC_RX_SWR_RESET);
|
||||
|
||||
regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_RX_SWR_CLK_EN_MASK, 1);
|
||||
|
||||
regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_RX_SWR_RESET_MASK, 0);
|
||||
|
||||
ret = devm_snd_soc_register_component(dev, &rx_macro_component_drv,
|
||||
rx_macro_dai,
|
||||
|
@ -3618,6 +3617,10 @@ static int rx_macro_probe(struct platform_device *pdev)
|
|||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = rx_macro_register_mclk_output(rx);
|
||||
if (ret)
|
||||
goto err_clkout;
|
||||
|
||||
return 0;
|
||||
|
||||
err_clkout:
|
||||
|
|
|
@ -203,7 +203,7 @@
|
|||
#define TX_MACRO_AMIC_UNMUTE_DELAY_MS 100
|
||||
#define TX_MACRO_DMIC_HPF_DELAY_MS 300
|
||||
#define TX_MACRO_AMIC_HPF_DELAY_MS 300
|
||||
#define MCLK_FREQ 9600000
|
||||
#define MCLK_FREQ 19200000
|
||||
|
||||
enum {
|
||||
TX_MACRO_AIF_INVALID = 0,
|
||||
|
@ -1861,15 +1861,10 @@ static int swclk_gate_enable(struct clk_hw *hw)
|
|||
}
|
||||
|
||||
tx_macro_mclk_enable(tx, true);
|
||||
regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_TX_SWR_RESET_MASK, CDC_TX_SWR_RESET_ENABLE);
|
||||
|
||||
regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_TX_SWR_CLK_EN_MASK,
|
||||
CDC_TX_SWR_CLK_ENABLE);
|
||||
regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_TX_SWR_RESET_MASK, 0x0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2014,7 +2009,7 @@ static int tx_macro_probe(struct platform_device *pdev)
|
|||
|
||||
/* set MCLK and NPL rates */
|
||||
clk_set_rate(tx->mclk, MCLK_FREQ);
|
||||
clk_set_rate(tx->npl, 2 * MCLK_FREQ);
|
||||
clk_set_rate(tx->npl, MCLK_FREQ);
|
||||
|
||||
ret = clk_prepare_enable(tx->macro);
|
||||
if (ret)
|
||||
|
@ -2036,9 +2031,15 @@ static int tx_macro_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_fsgen;
|
||||
|
||||
ret = tx_macro_register_mclk_output(tx);
|
||||
if (ret)
|
||||
goto err_clkout;
|
||||
/* reset soundwire block */
|
||||
regmap_update_bits(tx->regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_TX_SWR_RESET_MASK, CDC_TX_SWR_RESET_ENABLE);
|
||||
|
||||
regmap_update_bits(tx->regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_TX_SWR_CLK_EN_MASK,
|
||||
CDC_TX_SWR_CLK_ENABLE);
|
||||
regmap_update_bits(tx->regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_TX_SWR_RESET_MASK, 0x0);
|
||||
|
||||
ret = devm_snd_soc_register_component(dev, &tx_macro_component_drv,
|
||||
tx_macro_dai,
|
||||
|
@ -2052,6 +2053,10 @@ static int tx_macro_probe(struct platform_device *pdev)
|
|||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = tx_macro_register_mclk_output(tx);
|
||||
if (ret)
|
||||
goto err_clkout;
|
||||
|
||||
return 0;
|
||||
|
||||
err_clkout:
|
||||
|
|
|
@ -1333,17 +1333,9 @@ static int fsgen_gate_enable(struct clk_hw *hw)
|
|||
int ret;
|
||||
|
||||
ret = va_macro_mclk_enable(va, true);
|
||||
if (!va->has_swr_master)
|
||||
return ret;
|
||||
|
||||
if (va->has_swr_master)
|
||||
regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_VA_SWR_RESET_MASK, CDC_VA_SWR_RESET_ENABLE);
|
||||
|
||||
regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_VA_SWR_CLK_EN_MASK,
|
||||
CDC_VA_SWR_CLK_ENABLE);
|
||||
regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_VA_SWR_RESET_MASK, 0x0);
|
||||
CDC_VA_SWR_CLK_EN_MASK, CDC_VA_SWR_CLK_ENABLE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1524,16 +1516,6 @@ static int va_macro_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_mclk;
|
||||
|
||||
ret = va_macro_register_fsgen_output(va);
|
||||
if (ret)
|
||||
goto err_clkout;
|
||||
|
||||
va->fsgen = clk_hw_get_clk(&va->hw, "fsgen");
|
||||
if (IS_ERR(va->fsgen)) {
|
||||
ret = PTR_ERR(va->fsgen);
|
||||
goto err_clkout;
|
||||
}
|
||||
|
||||
if (va->has_swr_master) {
|
||||
/* Set default CLK div to 1 */
|
||||
regmap_update_bits(va->regmap, CDC_VA_TOP_CSR_SWR_MIC_CTL0,
|
||||
|
@ -1548,6 +1530,15 @@ static int va_macro_probe(struct platform_device *pdev)
|
|||
|
||||
}
|
||||
|
||||
if (va->has_swr_master) {
|
||||
regmap_update_bits(va->regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_VA_SWR_RESET_MASK, CDC_VA_SWR_RESET_ENABLE);
|
||||
regmap_update_bits(va->regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_VA_SWR_CLK_EN_MASK, CDC_VA_SWR_CLK_ENABLE);
|
||||
regmap_update_bits(va->regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_VA_SWR_RESET_MASK, 0x0);
|
||||
}
|
||||
|
||||
ret = devm_snd_soc_register_component(dev, &va_macro_component_drv,
|
||||
va_macro_dais,
|
||||
ARRAY_SIZE(va_macro_dais));
|
||||
|
@ -1560,6 +1551,16 @@ static int va_macro_probe(struct platform_device *pdev)
|
|||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = va_macro_register_fsgen_output(va);
|
||||
if (ret)
|
||||
goto err_clkout;
|
||||
|
||||
va->fsgen = clk_hw_get_clk(&va->hw, "fsgen");
|
||||
if (IS_ERR(va->fsgen)) {
|
||||
ret = PTR_ERR(va->fsgen);
|
||||
goto err_clkout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_clkout:
|
||||
|
|
|
@ -1856,10 +1856,8 @@ static int wsa_macro_rx_mux_put(struct snd_kcontrol *kcontrol,
|
|||
|
||||
aif_rst = wsa->rx_port_value[widget->shift];
|
||||
if (!rx_port_value) {
|
||||
if (aif_rst == 0) {
|
||||
dev_err(component->dev, "%s: AIF reset already\n", __func__);
|
||||
if (aif_rst == 0)
|
||||
return 0;
|
||||
}
|
||||
if (aif_rst >= WSA_MACRO_RX_MAX) {
|
||||
dev_err(component->dev, "%s: Invalid AIF reset\n", __func__);
|
||||
return 0;
|
||||
|
@ -2270,17 +2268,10 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
|
|||
}
|
||||
wsa_macro_mclk_enable(wsa, true);
|
||||
|
||||
/* reset swr ip */
|
||||
regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_WSA_SWR_RST_EN_MASK, CDC_WSA_SWR_RST_ENABLE);
|
||||
|
||||
regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_WSA_SWR_CLK_EN_MASK,
|
||||
CDC_WSA_SWR_CLK_ENABLE);
|
||||
|
||||
/* Bring out of reset */
|
||||
regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_WSA_SWR_RST_EN_MASK, CDC_WSA_SWR_RST_DISABLE);
|
||||
} else {
|
||||
regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_WSA_SWR_CLK_EN_MASK, 0);
|
||||
|
@ -2451,10 +2442,16 @@ static int wsa_macro_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_fsgen;
|
||||
|
||||
ret = wsa_macro_register_mclk_output(wsa);
|
||||
if (ret)
|
||||
goto err_clkout;
|
||||
/* reset swr ip */
|
||||
regmap_update_bits(wsa->regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_WSA_SWR_RST_EN_MASK, CDC_WSA_SWR_RST_ENABLE);
|
||||
|
||||
regmap_update_bits(wsa->regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_WSA_SWR_CLK_EN_MASK, CDC_WSA_SWR_CLK_ENABLE);
|
||||
|
||||
/* Bring out of reset */
|
||||
regmap_update_bits(wsa->regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
|
||||
CDC_WSA_SWR_RST_EN_MASK, CDC_WSA_SWR_RST_DISABLE);
|
||||
|
||||
ret = devm_snd_soc_register_component(dev, &wsa_macro_component_drv,
|
||||
wsa_macro_dai,
|
||||
|
@ -2468,6 +2465,10 @@ static int wsa_macro_probe(struct platform_device *pdev)
|
|||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = wsa_macro_register_mclk_output(wsa);
|
||||
if (ret)
|
||||
goto err_clkout;
|
||||
|
||||
return 0;
|
||||
|
||||
err_clkout:
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <asm/dma.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
@ -53,6 +54,7 @@ struct q6apm_dai_rtd {
|
|||
uint16_t session_id;
|
||||
enum stream_state state;
|
||||
struct q6apm_graph *graph;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct q6apm_dai_data {
|
||||
|
@ -62,7 +64,8 @@ struct q6apm_dai_data {
|
|||
static struct snd_pcm_hardware q6apm_dai_hardware_capture = {
|
||||
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
|
||||
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
|
||||
SNDRV_PCM_INFO_BATCH),
|
||||
.formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE),
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.rate_min = 8000,
|
||||
|
@ -80,7 +83,8 @@ static struct snd_pcm_hardware q6apm_dai_hardware_capture = {
|
|||
static struct snd_pcm_hardware q6apm_dai_hardware_playback = {
|
||||
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
|
||||
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
|
||||
SNDRV_PCM_INFO_BATCH),
|
||||
.formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE),
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.rate_min = 8000,
|
||||
|
@ -99,20 +103,25 @@ static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, vo
|
|||
{
|
||||
struct q6apm_dai_rtd *prtd = priv;
|
||||
struct snd_pcm_substream *substream = prtd->substream;
|
||||
unsigned long flags;
|
||||
|
||||
switch (opcode) {
|
||||
case APM_CLIENT_EVENT_CMD_EOS_DONE:
|
||||
prtd->state = Q6APM_STREAM_STOPPED;
|
||||
break;
|
||||
case APM_CLIENT_EVENT_DATA_WRITE_DONE:
|
||||
spin_lock_irqsave(&prtd->lock, flags);
|
||||
prtd->pos += prtd->pcm_count;
|
||||
spin_unlock_irqrestore(&prtd->lock, flags);
|
||||
snd_pcm_period_elapsed(substream);
|
||||
if (prtd->state == Q6APM_STREAM_RUNNING)
|
||||
q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0);
|
||||
|
||||
break;
|
||||
case APM_CLIENT_EVENT_DATA_READ_DONE:
|
||||
spin_lock_irqsave(&prtd->lock, flags);
|
||||
prtd->pos += prtd->pcm_count;
|
||||
spin_unlock_irqrestore(&prtd->lock, flags);
|
||||
snd_pcm_period_elapsed(substream);
|
||||
if (prtd->state == Q6APM_STREAM_RUNNING)
|
||||
q6apm_read(prtd->graph);
|
||||
|
@ -253,6 +262,7 @@ static int q6apm_dai_open(struct snd_soc_component *component,
|
|||
if (prtd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&prtd->lock);
|
||||
prtd->substream = substream;
|
||||
prtd->graph = q6apm_graph_open(dev, (q6apm_cb)event_handler, prtd, graph_id);
|
||||
if (IS_ERR(prtd->graph)) {
|
||||
|
@ -332,11 +342,17 @@ static snd_pcm_uframes_t q6apm_dai_pointer(struct snd_soc_component *component,
|
|||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct q6apm_dai_rtd *prtd = runtime->private_data;
|
||||
snd_pcm_uframes_t ptr;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&prtd->lock, flags);
|
||||
if (prtd->pos == prtd->pcm_size)
|
||||
prtd->pos = 0;
|
||||
|
||||
return bytes_to_frames(runtime, prtd->pos);
|
||||
ptr = bytes_to_frames(runtime, prtd->pos);
|
||||
spin_unlock_irqrestore(&prtd->lock, flags);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static int q6apm_dai_hw_params(struct snd_soc_component *component,
|
||||
|
|
|
@ -127,6 +127,11 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s
|
|||
int graph_id = dai->id;
|
||||
int rc;
|
||||
|
||||
if (dai_data->is_port_started[dai->id]) {
|
||||
q6apm_graph_stop(dai_data->graph[dai->id]);
|
||||
dai_data->is_port_started[dai->id] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* It is recommend to load DSP with source graph first and then sink
|
||||
* graph, so sequence for playback and capture will be different
|
||||
|
|
|
@ -145,14 +145,6 @@ static void q6apm_put_audioreach_graph(struct kref *ref)
|
|||
kfree(graph);
|
||||
}
|
||||
|
||||
bool q6apm_is_adsp_ready(void)
|
||||
{
|
||||
if (g_apm && g_apm->state)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(q6apm_is_adsp_ready);
|
||||
|
||||
static int q6apm_get_apm_state(struct q6apm *apm)
|
||||
{
|
||||
|
@ -169,6 +161,15 @@ static int q6apm_get_apm_state(struct q6apm *apm)
|
|||
return apm->state;
|
||||
}
|
||||
|
||||
bool q6apm_is_adsp_ready(void)
|
||||
{
|
||||
if (g_apm)
|
||||
return q6apm_get_apm_state(g_apm);
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(q6apm_is_adsp_ready);
|
||||
|
||||
static struct audioreach_module *__q6apm_find_module_by_mid(struct q6apm *apm,
|
||||
struct audioreach_graph_info *info,
|
||||
uint32_t mid)
|
||||
|
|
Loading…
Reference in New Issue