mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 14:42:24 +00:00
ASoC: Merge fixes
Needed for new development.
This commit is contained in:
commit
644ed467c7
@ -16247,7 +16247,7 @@ F: drivers/crypto/qat/
|
||||
|
||||
QCOM AUDIO (ASoC) DRIVERS
|
||||
M: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
M: Banajit Goswami <bgoswami@codeaurora.org>
|
||||
M: Banajit Goswami <bgoswami@quicinc.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
F: sound/soc/codecs/lpass-va-macro.c
|
||||
|
@ -1880,8 +1880,7 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
|
||||
*/
|
||||
bool regmap_can_raw_write(struct regmap *map)
|
||||
{
|
||||
return map->bus && map->bus->write && map->format.format_val &&
|
||||
map->format.format_reg;
|
||||
return map->write && map->format.format_val && map->format.format_reg;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_can_raw_write);
|
||||
|
||||
@ -2155,10 +2154,9 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg,
|
||||
size_t write_len;
|
||||
int ret;
|
||||
|
||||
if (!map->bus)
|
||||
return -EINVAL;
|
||||
if (!map->bus->write)
|
||||
if (!map->write)
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (val_len % map->format.val_bytes)
|
||||
return -EINVAL;
|
||||
if (!IS_ALIGNED(reg, map->reg_stride))
|
||||
@ -2300,7 +2298,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
|
||||
* Some devices don't support bulk write, for them we have a series of
|
||||
* single write operations.
|
||||
*/
|
||||
if (!map->bus || !map->format.parse_inplace) {
|
||||
if (!map->write || !map->format.parse_inplace) {
|
||||
map->lock(map->lock_arg);
|
||||
for (i = 0; i < val_count; i++) {
|
||||
unsigned int ival;
|
||||
@ -2926,6 +2924,9 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg,
|
||||
size_t read_len;
|
||||
int ret;
|
||||
|
||||
if (!map->read)
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (val_len % map->format.val_bytes)
|
||||
return -EINVAL;
|
||||
if (!IS_ALIGNED(reg, map->reg_stride))
|
||||
@ -3039,7 +3040,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
|
||||
if (val_count == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) {
|
||||
if (map->read && map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) {
|
||||
ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
@ -333,7 +333,7 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = {
|
||||
SOC_SINGLE("HW Noise Gate Enable", CS35L41_NG_CFG, 8, 63, 0),
|
||||
SOC_SINGLE("HW Noise Gate Delay", CS35L41_NG_CFG, 4, 7, 0),
|
||||
SOC_SINGLE("HW Noise Gate Threshold", CS35L41_NG_CFG, 0, 7, 0),
|
||||
SOC_SINGLE("Aux Noise Gate CH1 Enable",
|
||||
SOC_SINGLE("Aux Noise Gate CH1 Switch",
|
||||
CS35L41_MIXER_NGATE_CH1_CFG, 16, 1, 0),
|
||||
SOC_SINGLE("Aux Noise Gate CH1 Entry Delay",
|
||||
CS35L41_MIXER_NGATE_CH1_CFG, 8, 15, 0),
|
||||
@ -341,15 +341,15 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = {
|
||||
CS35L41_MIXER_NGATE_CH1_CFG, 0, 7, 0),
|
||||
SOC_SINGLE("Aux Noise Gate CH2 Entry Delay",
|
||||
CS35L41_MIXER_NGATE_CH2_CFG, 8, 15, 0),
|
||||
SOC_SINGLE("Aux Noise Gate CH2 Enable",
|
||||
SOC_SINGLE("Aux Noise Gate CH2 Switch",
|
||||
CS35L41_MIXER_NGATE_CH2_CFG, 16, 1, 0),
|
||||
SOC_SINGLE("Aux Noise Gate CH2 Threshold",
|
||||
CS35L41_MIXER_NGATE_CH2_CFG, 0, 7, 0),
|
||||
SOC_SINGLE("SCLK Force", CS35L41_SP_FORMAT, CS35L41_SCLK_FRC_SHIFT, 1, 0),
|
||||
SOC_SINGLE("LRCLK Force", CS35L41_SP_FORMAT, CS35L41_LRCLK_FRC_SHIFT, 1, 0),
|
||||
SOC_SINGLE("Invert Class D", CS35L41_AMP_DIG_VOL_CTRL,
|
||||
SOC_SINGLE("SCLK Force Switch", CS35L41_SP_FORMAT, CS35L41_SCLK_FRC_SHIFT, 1, 0),
|
||||
SOC_SINGLE("LRCLK Force Switch", CS35L41_SP_FORMAT, CS35L41_LRCLK_FRC_SHIFT, 1, 0),
|
||||
SOC_SINGLE("Invert Class D Switch", CS35L41_AMP_DIG_VOL_CTRL,
|
||||
CS35L41_AMP_INV_PCM_SHIFT, 1, 0),
|
||||
SOC_SINGLE("Amp Gain ZC", CS35L41_AMP_GAIN_CTRL,
|
||||
SOC_SINGLE("Amp Gain ZC Switch", CS35L41_AMP_GAIN_CTRL,
|
||||
CS35L41_AMP_GAIN_ZC_SHIFT, 1, 0),
|
||||
WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
|
||||
WM_ADSP_FW_CONTROL("DSP1", 0),
|
||||
|
@ -34,7 +34,7 @@ static int rt711_sdca_index_write(struct rt711_sdca_priv *rt711,
|
||||
|
||||
ret = regmap_write(regmap, addr, value);
|
||||
if (ret < 0)
|
||||
dev_err(rt711->component->dev,
|
||||
dev_err(&rt711->slave->dev,
|
||||
"Failed to set private value: %06x <= %04x ret=%d\n",
|
||||
addr, value, ret);
|
||||
|
||||
@ -50,7 +50,7 @@ static int rt711_sdca_index_read(struct rt711_sdca_priv *rt711,
|
||||
|
||||
ret = regmap_read(regmap, addr, value);
|
||||
if (ret < 0)
|
||||
dev_err(rt711->component->dev,
|
||||
dev_err(&rt711->slave->dev,
|
||||
"Failed to get private value: %06x => %04x ret=%d\n",
|
||||
addr, *value, ret);
|
||||
|
||||
|
@ -413,6 +413,7 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
|
||||
unsigned int rnew = (!!ucontrol->value.integer.value[1]) << mc->rshift;
|
||||
unsigned int lold, rold;
|
||||
unsigned int lena, rena;
|
||||
bool change = false;
|
||||
int ret;
|
||||
|
||||
snd_soc_dapm_mutex_lock(dapm);
|
||||
@ -440,8 +441,8 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(arizona->regmap, ARIZONA_DRE_ENABLE,
|
||||
mask, lnew | rnew);
|
||||
ret = regmap_update_bits_check(arizona->regmap, ARIZONA_DRE_ENABLE,
|
||||
mask, lnew | rnew, &change);
|
||||
if (ret) {
|
||||
dev_err(arizona->dev, "Failed to set DRE: %d\n", ret);
|
||||
goto err;
|
||||
@ -454,6 +455,9 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
|
||||
if (!rnew && rold)
|
||||
wm5110_clear_pga_volume(arizona, mc->rshift);
|
||||
|
||||
if (change)
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
snd_soc_dapm_mutex_unlock(dapm);
|
||||
|
||||
|
@ -997,7 +997,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
|
||||
snd_soc_dapm_sync(dapm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spinlock.h>
|
||||
@ -54,8 +55,40 @@ struct rk_i2s_dev {
|
||||
const struct rk_i2s_pins *pins;
|
||||
unsigned int bclk_ratio;
|
||||
spinlock_t lock; /* tx/rx lock */
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *bclk_on;
|
||||
struct pinctrl_state *bclk_off;
|
||||
};
|
||||
|
||||
static int i2s_pinctrl_select_bclk_on(struct rk_i2s_dev *i2s)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!IS_ERR(i2s->pinctrl) && !IS_ERR_OR_NULL(i2s->bclk_on))
|
||||
ret = pinctrl_select_state(i2s->pinctrl,
|
||||
i2s->bclk_on);
|
||||
|
||||
if (ret)
|
||||
dev_err(i2s->dev, "bclk enable failed %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int i2s_pinctrl_select_bclk_off(struct rk_i2s_dev *i2s)
|
||||
{
|
||||
|
||||
int ret = 0;
|
||||
|
||||
if (!IS_ERR(i2s->pinctrl) && !IS_ERR_OR_NULL(i2s->bclk_off))
|
||||
ret = pinctrl_select_state(i2s->pinctrl,
|
||||
i2s->bclk_off);
|
||||
|
||||
if (ret)
|
||||
dev_err(i2s->dev, "bclk disable failed %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int i2s_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct rk_i2s_dev *i2s = dev_get_drvdata(dev);
|
||||
@ -92,38 +125,49 @@ static inline struct rk_i2s_dev *to_info(struct snd_soc_dai *dai)
|
||||
return snd_soc_dai_get_drvdata(dai);
|
||||
}
|
||||
|
||||
static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
|
||||
static int rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
int retry = 10;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock(&i2s->lock);
|
||||
if (on) {
|
||||
regmap_update_bits(i2s->regmap, I2S_DMACR,
|
||||
ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
|
||||
I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
regmap_update_bits(i2s->regmap, I2S_XFER,
|
||||
ret = regmap_update_bits(i2s->regmap, I2S_XFER,
|
||||
I2S_XFER_TXS_START | I2S_XFER_RXS_START,
|
||||
I2S_XFER_TXS_START | I2S_XFER_RXS_START);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
i2s->tx_start = true;
|
||||
} else {
|
||||
i2s->tx_start = false;
|
||||
|
||||
regmap_update_bits(i2s->regmap, I2S_DMACR,
|
||||
ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
|
||||
I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
if (!i2s->rx_start) {
|
||||
regmap_update_bits(i2s->regmap, I2S_XFER,
|
||||
ret = regmap_update_bits(i2s->regmap, I2S_XFER,
|
||||
I2S_XFER_TXS_START |
|
||||
I2S_XFER_RXS_START,
|
||||
I2S_XFER_TXS_STOP |
|
||||
I2S_XFER_RXS_STOP);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
udelay(150);
|
||||
regmap_update_bits(i2s->regmap, I2S_CLR,
|
||||
ret = regmap_update_bits(i2s->regmap, I2S_CLR,
|
||||
I2S_CLR_TXC | I2S_CLR_RXC,
|
||||
I2S_CLR_TXC | I2S_CLR_RXC);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
regmap_read(i2s->regmap, I2S_CLR, &val);
|
||||
|
||||
@ -138,44 +182,57 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
|
||||
}
|
||||
}
|
||||
}
|
||||
end:
|
||||
spin_unlock(&i2s->lock);
|
||||
if (ret < 0)
|
||||
dev_err(i2s->dev, "lrclk update failed\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
|
||||
static int rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
int retry = 10;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock(&i2s->lock);
|
||||
if (on) {
|
||||
regmap_update_bits(i2s->regmap, I2S_DMACR,
|
||||
ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
|
||||
I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
regmap_update_bits(i2s->regmap, I2S_XFER,
|
||||
ret = regmap_update_bits(i2s->regmap, I2S_XFER,
|
||||
I2S_XFER_TXS_START | I2S_XFER_RXS_START,
|
||||
I2S_XFER_TXS_START | I2S_XFER_RXS_START);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
i2s->rx_start = true;
|
||||
} else {
|
||||
i2s->rx_start = false;
|
||||
|
||||
regmap_update_bits(i2s->regmap, I2S_DMACR,
|
||||
ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
|
||||
I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
if (!i2s->tx_start) {
|
||||
regmap_update_bits(i2s->regmap, I2S_XFER,
|
||||
ret = regmap_update_bits(i2s->regmap, I2S_XFER,
|
||||
I2S_XFER_TXS_START |
|
||||
I2S_XFER_RXS_START,
|
||||
I2S_XFER_TXS_STOP |
|
||||
I2S_XFER_RXS_STOP);
|
||||
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
udelay(150);
|
||||
regmap_update_bits(i2s->regmap, I2S_CLR,
|
||||
ret = regmap_update_bits(i2s->regmap, I2S_CLR,
|
||||
I2S_CLR_TXC | I2S_CLR_RXC,
|
||||
I2S_CLR_TXC | I2S_CLR_RXC);
|
||||
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
regmap_read(i2s->regmap, I2S_CLR, &val);
|
||||
|
||||
/* Should wait for clear operation to finish */
|
||||
while (val) {
|
||||
regmap_read(i2s->regmap, I2S_CLR, &val);
|
||||
@ -187,7 +244,12 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
|
||||
}
|
||||
}
|
||||
}
|
||||
end:
|
||||
spin_unlock(&i2s->lock);
|
||||
if (ret < 0)
|
||||
dev_err(i2s->dev, "lrclk update failed\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
|
||||
@ -425,17 +487,26 @@ static int rockchip_i2s_trigger(struct snd_pcm_substream *substream,
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
rockchip_snd_rxctrl(i2s, 1);
|
||||
ret = rockchip_snd_rxctrl(i2s, 1);
|
||||
else
|
||||
rockchip_snd_txctrl(i2s, 1);
|
||||
ret = rockchip_snd_txctrl(i2s, 1);
|
||||
/* Do not turn on bclk if lrclk open fails. */
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
i2s_pinctrl_select_bclk_on(i2s);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
rockchip_snd_rxctrl(i2s, 0);
|
||||
else
|
||||
rockchip_snd_txctrl(i2s, 0);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
||||
if (!i2s->tx_start)
|
||||
i2s_pinctrl_select_bclk_off(i2s);
|
||||
ret = rockchip_snd_rxctrl(i2s, 0);
|
||||
} else {
|
||||
if (!i2s->rx_start)
|
||||
i2s_pinctrl_select_bclk_off(i2s);
|
||||
ret = rockchip_snd_txctrl(i2s, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
@ -736,6 +807,33 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
i2s->bclk_ratio = 64;
|
||||
i2s->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
if (IS_ERR(i2s->pinctrl))
|
||||
dev_err(&pdev->dev, "failed to find i2s pinctrl\n");
|
||||
|
||||
i2s->bclk_on = pinctrl_lookup_state(i2s->pinctrl,
|
||||
"bclk_on");
|
||||
if (IS_ERR_OR_NULL(i2s->bclk_on))
|
||||
dev_err(&pdev->dev, "failed to find i2s default state\n");
|
||||
else
|
||||
dev_dbg(&pdev->dev, "find i2s bclk state\n");
|
||||
|
||||
i2s->bclk_off = pinctrl_lookup_state(i2s->pinctrl,
|
||||
"bclk_off");
|
||||
if (IS_ERR_OR_NULL(i2s->bclk_off))
|
||||
dev_err(&pdev->dev, "failed to find i2s gpio state\n");
|
||||
else
|
||||
dev_dbg(&pdev->dev, "find i2s bclk_off state\n");
|
||||
|
||||
i2s_pinctrl_select_bclk_off(i2s);
|
||||
|
||||
i2s->playback_dma_data.addr = res->start + I2S_TXDR;
|
||||
i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
i2s->playback_dma_data.maxburst = 4;
|
||||
|
||||
i2s->capture_dma_data.addr = res->start + I2S_RXDR;
|
||||
i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
i2s->capture_dma_data.maxburst = 4;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, i2s);
|
||||
|
||||
|
@ -395,7 +395,8 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
|
||||
struct snd_dma_buffer dmab;
|
||||
int ret, ret1, i;
|
||||
|
||||
if (hda->imrboot_supported && !sdev->first_boot) {
|
||||
if (sdev->system_suspend_target < SOF_SUSPEND_S4 &&
|
||||
hda->imrboot_supported && !sdev->first_boot) {
|
||||
dev_dbg(sdev->dev, "IMR restore supported, booting from IMR directly\n");
|
||||
hda->boot_iteration = 0;
|
||||
ret = hda_dsp_boot_imr(sdev);
|
||||
|
@ -192,79 +192,7 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
|
||||
goto found;
|
||||
}
|
||||
|
||||
switch (sof_hda_position_quirk) {
|
||||
case SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY:
|
||||
/*
|
||||
* This legacy code, inherited from the Skylake driver,
|
||||
* mixes DPIB registers and DPIB DDR updates and
|
||||
* does not seem to follow any known hardware recommendations.
|
||||
* It's not clear e.g. why there is a different flow
|
||||
* for capture and playback, the only information that matters is
|
||||
* what traffic class is used, and on all SOF-enabled platforms
|
||||
* only VC0 is supported so the work-around was likely not necessary
|
||||
* and quite possibly wrong.
|
||||
*/
|
||||
|
||||
/* DPIB/posbuf position mode:
|
||||
* For Playback, Use DPIB register from HDA space which
|
||||
* reflects the actual data transferred.
|
||||
* For Capture, Use the position buffer for pointer, as DPIB
|
||||
* is not accurate enough, its update may be completed
|
||||
* earlier than the data written to DDR.
|
||||
*/
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
|
||||
AZX_REG_VS_SDXDPIB_XBASE +
|
||||
(AZX_REG_VS_SDXDPIB_XINTERVAL *
|
||||
hstream->index));
|
||||
} else {
|
||||
/*
|
||||
* For capture stream, we need more workaround to fix the
|
||||
* position incorrect issue:
|
||||
*
|
||||
* 1. Wait at least 20us before reading position buffer after
|
||||
* the interrupt generated(IOC), to make sure position update
|
||||
* happens on frame boundary i.e. 20.833uSec for 48KHz.
|
||||
* 2. Perform a dummy Read to DPIB register to flush DMA
|
||||
* position value.
|
||||
* 3. Read the DMA Position from posbuf. Now the readback
|
||||
* value should be >= period boundary.
|
||||
*/
|
||||
usleep_range(20, 21);
|
||||
snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
|
||||
AZX_REG_VS_SDXDPIB_XBASE +
|
||||
(AZX_REG_VS_SDXDPIB_XINTERVAL *
|
||||
hstream->index));
|
||||
pos = snd_hdac_stream_get_pos_posbuf(hstream);
|
||||
}
|
||||
break;
|
||||
case SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS:
|
||||
/*
|
||||
* In case VC1 traffic is disabled this is the recommended option
|
||||
*/
|
||||
pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
|
||||
AZX_REG_VS_SDXDPIB_XBASE +
|
||||
(AZX_REG_VS_SDXDPIB_XINTERVAL *
|
||||
hstream->index));
|
||||
break;
|
||||
case SOF_HDA_POSITION_QUIRK_USE_DPIB_DDR_UPDATE:
|
||||
/*
|
||||
* This is the recommended option when VC1 is enabled.
|
||||
* While this isn't needed for SOF platforms it's added for
|
||||
* consistency and debug.
|
||||
*/
|
||||
pos = snd_hdac_stream_get_pos_posbuf(hstream);
|
||||
break;
|
||||
default:
|
||||
dev_err_once(sdev->dev, "hda_position_quirk value %d not supported\n",
|
||||
sof_hda_position_quirk);
|
||||
pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pos >= hstream->bufsize)
|
||||
pos = 0;
|
||||
|
||||
pos = hda_dsp_stream_get_position(hstream, substream->stream, true);
|
||||
found:
|
||||
pos = bytes_to_frames(substream->runtime, pos);
|
||||
|
||||
|
@ -707,12 +707,13 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
|
||||
}
|
||||
|
||||
static void
|
||||
hda_dsp_set_bytes_transferred(struct hdac_stream *hstream, u64 buffer_size)
|
||||
hda_dsp_compr_bytes_transferred(struct hdac_stream *hstream, int direction)
|
||||
{
|
||||
u64 buffer_size = hstream->bufsize;
|
||||
u64 prev_pos, pos, num_bytes;
|
||||
|
||||
div64_u64_rem(hstream->curr_pos, buffer_size, &prev_pos);
|
||||
pos = snd_hdac_stream_get_pos_posbuf(hstream);
|
||||
pos = hda_dsp_stream_get_position(hstream, direction, false);
|
||||
|
||||
if (pos < prev_pos)
|
||||
num_bytes = (buffer_size - prev_pos) + pos;
|
||||
@ -748,8 +749,7 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status)
|
||||
if (s->substream && sof_hda->no_ipc_position) {
|
||||
snd_sof_pcm_period_elapsed(s->substream);
|
||||
} else if (s->cstream) {
|
||||
hda_dsp_set_bytes_transferred(s,
|
||||
s->cstream->runtime->buffer_size);
|
||||
hda_dsp_compr_bytes_transferred(s, s->cstream->direction);
|
||||
snd_compr_fragment_elapsed(s->cstream);
|
||||
}
|
||||
}
|
||||
@ -1009,3 +1009,89 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev)
|
||||
devm_kfree(sdev->dev, hda_stream);
|
||||
}
|
||||
}
|
||||
|
||||
snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
|
||||
int direction, bool can_sleep)
|
||||
{
|
||||
struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
|
||||
struct sof_intel_hda_stream *hda_stream = hstream_to_sof_hda_stream(hext_stream);
|
||||
struct snd_sof_dev *sdev = hda_stream->sdev;
|
||||
snd_pcm_uframes_t pos;
|
||||
|
||||
switch (sof_hda_position_quirk) {
|
||||
case SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY:
|
||||
/*
|
||||
* This legacy code, inherited from the Skylake driver,
|
||||
* mixes DPIB registers and DPIB DDR updates and
|
||||
* does not seem to follow any known hardware recommendations.
|
||||
* It's not clear e.g. why there is a different flow
|
||||
* for capture and playback, the only information that matters is
|
||||
* what traffic class is used, and on all SOF-enabled platforms
|
||||
* only VC0 is supported so the work-around was likely not necessary
|
||||
* and quite possibly wrong.
|
||||
*/
|
||||
|
||||
/* DPIB/posbuf position mode:
|
||||
* For Playback, Use DPIB register from HDA space which
|
||||
* reflects the actual data transferred.
|
||||
* For Capture, Use the position buffer for pointer, as DPIB
|
||||
* is not accurate enough, its update may be completed
|
||||
* earlier than the data written to DDR.
|
||||
*/
|
||||
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
|
||||
AZX_REG_VS_SDXDPIB_XBASE +
|
||||
(AZX_REG_VS_SDXDPIB_XINTERVAL *
|
||||
hstream->index));
|
||||
} else {
|
||||
/*
|
||||
* For capture stream, we need more workaround to fix the
|
||||
* position incorrect issue:
|
||||
*
|
||||
* 1. Wait at least 20us before reading position buffer after
|
||||
* the interrupt generated(IOC), to make sure position update
|
||||
* happens on frame boundary i.e. 20.833uSec for 48KHz.
|
||||
* 2. Perform a dummy Read to DPIB register to flush DMA
|
||||
* position value.
|
||||
* 3. Read the DMA Position from posbuf. Now the readback
|
||||
* value should be >= period boundary.
|
||||
*/
|
||||
if (can_sleep)
|
||||
usleep_range(20, 21);
|
||||
|
||||
snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
|
||||
AZX_REG_VS_SDXDPIB_XBASE +
|
||||
(AZX_REG_VS_SDXDPIB_XINTERVAL *
|
||||
hstream->index));
|
||||
pos = snd_hdac_stream_get_pos_posbuf(hstream);
|
||||
}
|
||||
break;
|
||||
case SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS:
|
||||
/*
|
||||
* In case VC1 traffic is disabled this is the recommended option
|
||||
*/
|
||||
pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
|
||||
AZX_REG_VS_SDXDPIB_XBASE +
|
||||
(AZX_REG_VS_SDXDPIB_XINTERVAL *
|
||||
hstream->index));
|
||||
break;
|
||||
case SOF_HDA_POSITION_QUIRK_USE_DPIB_DDR_UPDATE:
|
||||
/*
|
||||
* This is the recommended option when VC1 is enabled.
|
||||
* While this isn't needed for SOF platforms it's added for
|
||||
* consistency and debug.
|
||||
*/
|
||||
pos = snd_hdac_stream_get_pos_posbuf(hstream);
|
||||
break;
|
||||
default:
|
||||
dev_err_once(sdev->dev, "hda_position_quirk value %d not supported\n",
|
||||
sof_hda_position_quirk);
|
||||
pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pos >= hstream->bufsize)
|
||||
pos = 0;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
@ -565,6 +565,9 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
|
||||
bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
|
||||
bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev);
|
||||
|
||||
snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
|
||||
int direction, bool can_sleep);
|
||||
|
||||
struct hdac_ext_stream *
|
||||
hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags);
|
||||
int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag);
|
||||
|
@ -392,7 +392,7 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev)
|
||||
PLATFORM_DEVID_NONE,
|
||||
pdev, sizeof(*pdev));
|
||||
if (IS_ERR(priv->ipc_dev)) {
|
||||
ret = IS_ERR(priv->ipc_dev);
|
||||
ret = PTR_ERR(priv->ipc_dev);
|
||||
dev_err(sdev->dev, "failed to create mtk-adsp-ipc device\n");
|
||||
goto err_adsp_off;
|
||||
}
|
||||
|
@ -23,6 +23,9 @@ static u32 snd_sof_dsp_power_target(struct snd_sof_dev *sdev)
|
||||
u32 target_dsp_state;
|
||||
|
||||
switch (sdev->system_suspend_target) {
|
||||
case SOF_SUSPEND_S5:
|
||||
case SOF_SUSPEND_S4:
|
||||
/* DSP should be in D3 if the system is suspending to S3+ */
|
||||
case SOF_SUSPEND_S3:
|
||||
/* DSP should be in D3 if the system is suspending to S3 */
|
||||
target_dsp_state = SOF_DSP_PM_D3;
|
||||
@ -335,8 +338,24 @@ int snd_sof_prepare(struct device *dev)
|
||||
return 0;
|
||||
|
||||
#if defined(CONFIG_ACPI)
|
||||
if (acpi_target_system_state() == ACPI_STATE_S0)
|
||||
switch (acpi_target_system_state()) {
|
||||
case ACPI_STATE_S0:
|
||||
sdev->system_suspend_target = SOF_SUSPEND_S0IX;
|
||||
break;
|
||||
case ACPI_STATE_S1:
|
||||
case ACPI_STATE_S2:
|
||||
case ACPI_STATE_S3:
|
||||
sdev->system_suspend_target = SOF_SUSPEND_S3;
|
||||
break;
|
||||
case ACPI_STATE_S4:
|
||||
sdev->system_suspend_target = SOF_SUSPEND_S4;
|
||||
break;
|
||||
case ACPI_STATE_S5:
|
||||
sdev->system_suspend_target = SOF_SUSPEND_S5;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
@ -91,6 +91,8 @@ enum sof_system_suspend_state {
|
||||
SOF_SUSPEND_NONE = 0,
|
||||
SOF_SUSPEND_S0IX,
|
||||
SOF_SUSPEND_S3,
|
||||
SOF_SUSPEND_S4,
|
||||
SOF_SUSPEND_S5,
|
||||
};
|
||||
|
||||
enum sof_dfsentry_type {
|
||||
|
Loading…
Reference in New Issue
Block a user