3
0
mirror of https://github.com/Qortal/Brooklyn.git synced 2025-01-30 06:42:18 +00:00
This commit is contained in:
Raziel K. Crowe 2022-09-09 14:21:57 +05:00
parent 26999baf09
commit 13f0645c94
1355 changed files with 181039 additions and 43440 deletions

View File

@ -75,6 +75,7 @@ static struct audioreach_graph *q6apm_get_audioreach_graph(struct q6apm *apm, ui
id = idr_alloc(&apm->graph_idr, graph, graph_id, graph_id + 1, GFP_KERNEL);
if (id < 0) {
dev_err(apm->dev, "Unable to allocate graph id (%d)\n", graph_id);
kfree(graph->graph);
kfree(graph);
mutex_unlock(&apm->lock);
return ERR_PTR(id);

View File

@ -1205,17 +1205,18 @@ static const struct snd_soc_dapm_widget q6asm_dapm_widgets[] = {
};
static const struct snd_soc_component_driver q6asm_fe_dai_component = {
.name = DRV_NAME,
.open = q6asm_dai_open,
.hw_params = q6asm_dai_hw_params,
.close = q6asm_dai_close,
.prepare = q6asm_dai_prepare,
.trigger = q6asm_dai_trigger,
.pointer = q6asm_dai_pointer,
.pcm_construct = q6asm_dai_pcm_new,
.compress_ops = &q6asm_dai_compress_ops,
.dapm_widgets = q6asm_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(q6asm_dapm_widgets),
.name = DRV_NAME,
.open = q6asm_dai_open,
.hw_params = q6asm_dai_hw_params,
.close = q6asm_dai_close,
.prepare = q6asm_dai_prepare,
.trigger = q6asm_dai_trigger,
.pointer = q6asm_dai_pointer,
.pcm_construct = q6asm_dai_pcm_new,
.compress_ops = &q6asm_dai_compress_ops,
.dapm_widgets = q6asm_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(q6asm_dapm_widgets),
.legacy_dai_naming = 1,
};
static struct snd_soc_dai_driver q6asm_fe_dais_template[] = {

View File

@ -513,7 +513,7 @@ int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac,
return 0;
}
buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_ATOMIC);
buf = kcalloc(periods, sizeof(*buf), GFP_ATOMIC);
if (!buf) {
spin_unlock_irqrestore(&ac->lock, flags);
return -ENOMEM;

View File

@ -124,10 +124,10 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime)
/* Enable Headset Jack detection */
if (gpio_is_valid(machine->gpio_hp_det)) {
snd_soc_card_jack_new(runtime->card, "Headphone Jack",
SND_JACK_HEADPHONE, &headphone_jack,
headphone_jack_pins,
ARRAY_SIZE(headphone_jack_pins));
snd_soc_card_jack_new_pins(runtime->card, "Headphone Jack",
SND_JACK_HEADPHONE, &headphone_jack,
headphone_jack_pins,
ARRAY_SIZE(headphone_jack_pins));
rk_hp_jack_gpio.gpio = machine->gpio_hp_det;
snd_soc_jack_add_gpios(&headphone_jack, 1, &rk_hp_jack_gpio);
}
@ -169,7 +169,7 @@ static struct snd_soc_card snd_soc_card_rk = {
static int snd_rk_mc_probe(struct platform_device *pdev)
{
int ret = 0;
int ret;
struct snd_soc_card *card = &snd_soc_card_rk;
struct device_node *np = pdev->dev.of_node;
struct rk_drvdata *machine;
@ -253,7 +253,7 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, ret,
"Soc register card failed\n");
return ret;
return 0;
}
static const struct of_device_id rockchip_sound_of_match[] = {

View File

@ -174,7 +174,7 @@ static int rockchip_sound_cdndp_init(struct snd_soc_pcm_runtime *rtd)
/* Enable jack detection. */
ret = snd_soc_card_jack_new(card, "DP Jack", SND_JACK_LINEOUT,
&cdn_dp_card_jack, NULL, 0);
&cdn_dp_card_jack);
if (ret) {
dev_err(card->dev, "Can't create DP Jack %d\n", ret);
return ret;
@ -204,13 +204,13 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
}
/* Enable Headset and 4 Buttons Jack detection */
ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
&rockchip_sound_jack,
rockchip_sound_jack_pins,
ARRAY_SIZE(rockchip_sound_jack_pins));
ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
&rockchip_sound_jack,
rockchip_sound_jack_pins,
ARRAY_SIZE(rockchip_sound_jack_pins));
if (ret) {
dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret);

View File

@ -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,38 @@ 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,39 +123,46 @@ 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,
I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
regmap_update_bits(i2s->regmap, I2S_XFER,
I2S_XFER_TXS_START | I2S_XFER_RXS_START,
I2S_XFER_TXS_START | I2S_XFER_RXS_START);
ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
I2S_DMACR_TDE_ENABLE,
I2S_DMACR_TDE_ENABLE);
if (ret < 0)
goto end;
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,
I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
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,
I2S_XFER_TXS_START |
I2S_XFER_RXS_START,
I2S_XFER_TXS_STOP |
I2S_XFER_RXS_STOP);
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,
I2S_CLR_TXC | I2S_CLR_RXC,
I2S_CLR_TXC | I2S_CLR_RXC);
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 */
@ -133,61 +171,80 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
retry--;
if (!retry) {
dev_warn(i2s->dev, "fail to clear\n");
ret = -EBUSY;
break;
}
}
}
}
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,
I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE);
regmap_update_bits(i2s->regmap, I2S_XFER,
I2S_XFER_TXS_START | I2S_XFER_RXS_START,
I2S_XFER_TXS_START | I2S_XFER_RXS_START);
ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
I2S_DMACR_RDE_ENABLE,
I2S_DMACR_RDE_ENABLE);
if (ret < 0)
goto end;
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,
I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
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,
I2S_XFER_TXS_START |
I2S_XFER_RXS_START,
I2S_XFER_TXS_STOP |
I2S_XFER_RXS_STOP);
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,
I2S_CLR_TXC | I2S_CLR_RXC,
I2S_CLR_TXC | I2S_CLR_RXC);
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);
retry--;
if (!retry) {
dev_warn(i2s->dev, "fail to clear\n");
ret = -EBUSY;
break;
}
}
}
}
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,
@ -199,13 +256,13 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
pm_runtime_get_sync(cpu_dai->dev);
mask = I2S_CKR_MSS_MASK;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_BP_FP:
/* Set source clock in Master mode */
val = I2S_CKR_MSS_MASTER;
i2s->is_master_mode = true;
break;
case SND_SOC_DAIFMT_CBM_CFM:
case SND_SOC_DAIFMT_BC_FC:
val = I2S_CKR_MSS_SLAVE;
i2s->is_master_mode = false;
break;
@ -425,17 +482,25 @@ 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);
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;
@ -498,6 +563,7 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = {
static const struct snd_soc_component_driver rockchip_i2s_component = {
.name = DRV_NAME,
.legacy_dai_naming = 1,
};
static bool rockchip_i2s_wr_reg(struct device *dev, unsigned int reg)
@ -736,6 +802,22 @@ 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)) {
i2s->bclk_on = pinctrl_lookup_state(i2s->pinctrl, "bclk_on");
if (!IS_ERR_OR_NULL(i2s->bclk_on)) {
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 bclk_off\n");
ret = -EINVAL;
goto err_clk;
}
}
} else {
dev_dbg(&pdev->dev, "failed to find i2s pinctrl\n");
}
i2s_pinctrl_select_bclk_off(i2s);
dev_set_drvdata(&pdev->dev, i2s);

View File

@ -404,19 +404,17 @@ static int rockchip_i2s_tdm_set_fmt(struct snd_soc_dai *cpu_dai,
int ret;
bool is_tdm = i2s_tdm->tdm_mode;
ret = pm_runtime_get_sync(cpu_dai->dev);
if (ret < 0 && ret != -EACCES) {
pm_runtime_put_noidle(cpu_dai->dev);
ret = pm_runtime_resume_and_get(cpu_dai->dev);
if (ret < 0 && ret != -EACCES)
return ret;
}
mask = I2S_CKR_MSS_MASK;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBC_CFC:
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_BP_FP:
val = I2S_CKR_MSS_MASTER;
i2s_tdm->is_master_mode = true;
break;
case SND_SOC_DAIFMT_CBP_CFP:
case SND_SOC_DAIFMT_BC_FC:
val = I2S_CKR_MSS_SLAVE;
i2s_tdm->is_master_mode = false;
break;
@ -1120,6 +1118,7 @@ static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = {
static const struct snd_soc_component_driver rockchip_i2s_tdm_component = {
.name = DRV_NAME,
.legacy_dai_naming = 1,
};
static bool rockchip_i2s_tdm_wr_reg(struct device *dev, unsigned int reg)

View File

@ -231,7 +231,7 @@ static int rk_hdmi_init(struct snd_soc_pcm_runtime *runtime)
/* enable jack detection */
ret = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT,
&rk_hdmi_jack, NULL, 0);
&rk_hdmi_jack);
if (ret) {
dev_err(card->dev, "Can't new HDMI Jack %d\n", ret);
return ret;
@ -345,13 +345,13 @@ static int rk_98090_headset_init(struct snd_soc_component *component)
int ret;
/* Enable Headset and 4 Buttons Jack detection */
ret = snd_soc_card_jack_new(component->card, "Headset Jack",
SND_JACK_HEADSET |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
&headset_jack,
headset_jack_pins,
ARRAY_SIZE(headset_jack_pins));
ret = snd_soc_card_jack_new_pins(component->card, "Headset Jack",
SND_JACK_HEADSET |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
&headset_jack,
headset_jack_pins,
ARRAY_SIZE(headset_jack_pins));
if (ret)
return ret;

View File

@ -405,6 +405,7 @@ static struct snd_soc_dai_driver rockchip_pdm_dai = {
static const struct snd_soc_component_driver rockchip_pdm_component = {
.name = "rockchip-pdm",
.legacy_dai_naming = 1,
};
static int rockchip_pdm_runtime_suspend(struct device *dev)
@ -688,11 +689,9 @@ static int rockchip_pdm_resume(struct device *dev)
struct rk_pdm_dev *pdm = dev_get_drvdata(dev);
int ret;
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
pm_runtime_put(dev);
ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;
}
ret = regcache_sync(pdm->regmap);

View File

@ -107,7 +107,7 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime)
SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
&headset_jack, NULL, 0);
&headset_jack);
if (ret) {
dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret);
return ret;

View File

@ -225,6 +225,7 @@ static struct snd_soc_dai_driver rk_spdif_dai = {
static const struct snd_soc_component_driver rk_spdif_component = {
.name = "rockchip-spdif",
.legacy_dai_naming = 1,
};
static bool rk_spdif_wr_reg(struct device *dev, unsigned int reg)

View File

@ -33,7 +33,8 @@ config SND_SAMSUNG_I2S
config SND_SOC_SAMSUNG_NEO1973_WM8753
tristate "Audio support for Openmoko Neo1973 Smartphones (GTA02)"
depends on MACH_NEO1973_GTA02
depends on MACH_NEO1973_GTA02 || COMPILE_TEST
depends on SND_SOC_I2C_AND_SPI
select SND_S3C24XX_I2S
select SND_SOC_WM8753
select SND_SOC_BT_SCO
@ -43,7 +44,8 @@ config SND_SOC_SAMSUNG_NEO1973_WM8753
config SND_SOC_SAMSUNG_JIVE_WM8750
tristate "SoC I2S Audio support for Jive"
depends on MACH_JIVE && I2C
depends on MACH_JIVE && I2C || COMPILE_TEST && ARM
depends on SND_SOC_I2C_AND_SPI
select SND_SOC_WM8750
select SND_S3C2412_SOC_I2S
help
@ -69,7 +71,7 @@ config SND_SOC_SAMSUNG_SMDK_WM8994
config SND_SOC_SAMSUNG_S3C24XX_UDA134X
tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
depends on ARCH_S3C24XX
depends on ARCH_S3C24XX || COMPILE_TEST
select SND_S3C24XX_I2S
select SND_SOC_L3
select SND_SOC_UDA134X
@ -81,21 +83,24 @@ config SND_SOC_SAMSUNG_SIMTEC
config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23
tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
depends on ARCH_S3C24XX && I2C
depends on ARCH_S3C24XX || COMPILE_TEST
depends on I2C
select SND_S3C24XX_I2S
select SND_SOC_TLV320AIC23_I2C
select SND_SOC_SAMSUNG_SIMTEC
config SND_SOC_SAMSUNG_SIMTEC_HERMES
tristate "SoC I2S Audio support for Simtec Hermes board"
depends on ARCH_S3C24XX && I2C
depends on ARCH_S3C24XX || COMPILE_TEST
depends on I2C
select SND_S3C24XX_I2S
select SND_SOC_TLV320AIC3X
select SND_SOC_SAMSUNG_SIMTEC
config SND_SOC_SAMSUNG_H1940_UDA1380
tristate "Audio support for the HP iPAQ H1940"
depends on ARCH_H1940 && I2C
depends on ARCH_H1940 || COMPILE_TEST
depends on I2C
select SND_S3C24XX_I2S
select SND_SOC_UDA1380
help
@ -103,7 +108,8 @@ config SND_SOC_SAMSUNG_H1940_UDA1380
config SND_SOC_SAMSUNG_RX1950_UDA1380
tristate "Audio support for the HP iPAQ RX1950"
depends on MACH_RX1950 && I2C
depends on MACH_RX1950 || COMPILE_TEST
depends on I2C
select SND_S3C24XX_I2S
select SND_SOC_UDA1380
help

View File

@ -343,7 +343,7 @@ static int aries_late_probe(struct snd_soc_card *card)
struct aries_wm8994_data *priv = snd_soc_card_get_drvdata(card);
int ret, irq;
ret = snd_soc_card_jack_new(card, "Dock", SND_JACK_LINEOUT,
ret = snd_soc_card_jack_new_pins(card, "Dock", SND_JACK_LINEOUT,
&aries_dock, dock_pins, ARRAY_SIZE(dock_pins));
if (ret)
return ret;
@ -361,7 +361,7 @@ static int aries_late_probe(struct snd_soc_card *card)
else
snd_soc_jack_report(&aries_dock, 0, SND_JACK_LINEOUT);
ret = snd_soc_card_jack_new(card, "Headset",
ret = snd_soc_card_jack_new_pins(card, "Headset",
SND_JACK_HEADSET | SND_JACK_BTN_0,
&aries_headset,
jack_pins, ARRAY_SIZE(jack_pins));
@ -432,7 +432,6 @@ static const struct snd_soc_component_driver aries_component = {
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
.non_legacy_dai_naming = 1,
};
static struct snd_soc_dai_driver aries_ext_dai[] = {
@ -585,10 +584,10 @@ static int aries_audio_probe(struct platform_device *pdev)
extcon_np = of_parse_phandle(np, "extcon", 0);
priv->usb_extcon = extcon_find_edev_by_node(extcon_np);
of_node_put(extcon_np);
if (IS_ERR(priv->usb_extcon))
return dev_err_probe(dev, PTR_ERR(priv->usb_extcon),
"Failed to get extcon device");
of_node_put(extcon_np);
priv->adc = devm_iio_channel_get(dev, "headset-detect");
if (IS_ERR(priv->adc))
@ -628,8 +627,10 @@ static int aries_audio_probe(struct platform_device *pdev)
return -EINVAL;
codec = of_get_child_by_name(dev->of_node, "codec");
if (!codec)
return -EINVAL;
if (!codec) {
ret = -EINVAL;
goto out;
}
for_each_card_prelinks(card, i, dai_link) {
dai_link->codecs->of_node = of_parse_phandle(codec,

View File

@ -386,11 +386,11 @@ static struct snd_soc_codec_conf bells_codec_conf[] = {
},
};
static struct snd_soc_dapm_widget bells_widgets[] = {
static const struct snd_soc_dapm_widget bells_widgets[] = {
SND_SOC_DAPM_MIC("DMIC", NULL),
};
static struct snd_soc_dapm_route bells_routes[] = {
static const struct snd_soc_dapm_route bells_routes[] = {
{ "Sub CLK_SYS", NULL, "OPCLK" },
{ "CLKIN", NULL, "OPCLK" },

View File

@ -8,7 +8,7 @@
// Based on version from Arnaud Patard <arnaud.patard@rtp-net.org>
#include <linux/types.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <sound/soc.h>
@ -151,7 +151,8 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
{
snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE,
snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack",
SND_JACK_HEADPHONE,
&hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),

View File

@ -671,11 +671,11 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_BC_FC:
tmp |= mod_slave;
break;
case SND_SOC_DAIFMT_CBS_CFS:
case SND_SOC_DAIFMT_BP_FP:
/*
* Set default source clock in Master mode, only when the
* CLK_I2S_RCLK_SRC clock is not exposed so we ensure any
@ -1143,6 +1143,8 @@ static const struct snd_soc_component_driver samsung_i2s_component = {
.suspend = i2s_suspend,
.resume = i2s_resume,
.legacy_dai_naming = 1,
};
#define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \

View File

@ -228,7 +228,7 @@ static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("WM1250 Output"),
};
static struct snd_soc_dapm_widget widgets[] = {
static const struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("AMIC", NULL),
@ -239,7 +239,7 @@ static struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
};
static struct snd_soc_dapm_route audio_paths[] = {
static const struct snd_soc_dapm_route audio_paths[] = {
{ "Headphone", NULL, "HPOUT1L" },
{ "Headphone", NULL, "HPOUT1R" },
@ -285,7 +285,7 @@ static int littlemill_late_probe(struct snd_soc_card *card)
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3 |
SND_JACK_BTN_4 | SND_JACK_BTN_5,
&littlemill_headset, NULL, 0);
&littlemill_headset);
if (ret)
return ret;

View File

@ -51,10 +51,11 @@ static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
ret = snd_soc_card_jack_new(rtd->card, "Headset", SND_JACK_LINEOUT |
SND_JACK_HEADSET | SND_JACK_BTN_0,
&lowland_headset, lowland_headset_pins,
ARRAY_SIZE(lowland_headset_pins));
ret = snd_soc_card_jack_new_pins(rtd->card, "Headset",
SND_JACK_LINEOUT | SND_JACK_HEADSET |
SND_JACK_BTN_0,
&lowland_headset, lowland_headset_pins,
ARRAY_SIZE(lowland_headset_pins));
if (ret)
return ret;
@ -140,7 +141,7 @@ static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"),
};
static struct snd_soc_dapm_widget widgets[] = {
static const struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
@ -150,7 +151,7 @@ static struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_MIC("Main DMIC", NULL),
};
static struct snd_soc_dapm_route audio_paths[] = {
static const struct snd_soc_dapm_route audio_paths[] = {
{ "Sub IN1", NULL, "HPOUT2L" },
{ "Sub IN2", NULL, "HPOUT2R" },

View File

@ -309,7 +309,7 @@ static int midas_late_probe(struct snd_soc_card *card)
SND_JACK_HEADSET | SND_JACK_MECHANICAL |
SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5,
&priv->headset_jack, NULL, 0);
&priv->headset_jack);
if (ret)
return ret;

View File

@ -344,7 +344,7 @@ static int neo1973_probe(struct platform_device *pdev)
return devm_snd_soc_register_card(dev, &neo1973);
}
struct platform_driver neo1973_audio = {
static struct platform_driver neo1973_audio = {
.driver = {
.name = "neo1973-audio",
.pm = &snd_soc_pm_ops,

View File

@ -340,8 +340,8 @@ static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
goto exit;
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_BP_FP:
/* Nothing to do, Master by default */
break;
default:
@ -480,7 +480,8 @@ static struct snd_soc_dai_driver s3c_pcm_dai[] = {
};
static const struct snd_soc_component_driver s3c_pcm_component = {
.name = "s3c-pcm",
.name = "s3c-pcm",
.legacy_dai_naming = 1,
};
static int s3c_pcm_dev_probe(struct platform_device *pdev)

View File

@ -128,7 +128,7 @@ static int rx1950_startup(struct snd_pcm_substream *substream)
&hw_rates);
}
struct gpio_desc *gpiod_speaker_power;
static struct gpio_desc *gpiod_speaker_power;
static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
@ -201,7 +201,8 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream,
static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
{
snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE,
snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack",
SND_JACK_HEADPHONE,
&hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
@ -227,7 +228,7 @@ static int rx1950_probe(struct platform_device *pdev)
return devm_snd_soc_register_card(dev, &rx1950_asoc);
}
struct platform_driver rx1950_audio = {
static struct platform_driver rx1950_audio = {
.driver = {
.name = "rx1950-audio",
.pm = &snd_soc_pm_ops,

View File

@ -21,17 +21,6 @@
#include "regs-i2s-v2.h"
#include "s3c-i2s-v2.h"
#undef S3C_IIS_V2_SUPPORTED
#if defined(CONFIG_CPU_S3C2412) \
|| defined(CONFIG_ARCH_S3C64XX) || defined(CONFIG_CPU_S5PV210)
#define S3C_IIS_V2_SUPPORTED
#endif
#ifndef S3C_IIS_V2_SUPPORTED
#error Unsupported CPU model
#endif
#define S3C2412_I2S_DEBUG_CON 0
static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
@ -252,12 +241,12 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
iismod = readl(i2s->regs + S3C2412_IISMOD);
pr_debug("hw_params r: IISMOD: %x \n", iismod);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_BC_FC:
i2s->master = 0;
iismod |= S3C2412_IISMOD_SLAVE;
break;
case SND_SOC_DAIFMT_CBS_CFS:
case SND_SOC_DAIFMT_BP_FP:
i2s->master = 1;
iismod &= ~S3C2412_IISMOD_SLAVE;
break;

View File

@ -192,9 +192,10 @@ static struct snd_soc_dai_driver s3c2412_i2s_dai = {
};
static const struct snd_soc_component_driver s3c2412_i2s_component = {
.name = "s3c2412-i2s",
.suspend = s3c2412_i2s_suspend,
.resume = s3c2412_i2s_resume,
.name = "s3c2412-i2s",
.suspend = s3c2412_i2s_suspend,
.resume = s3c2412_i2s_resume,
.legacy_dai_naming = 1,
};
static int s3c2412_iis_dev_probe(struct platform_device *pdev)

View File

@ -12,7 +12,6 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <sound/soc.h>
@ -169,11 +168,11 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
pr_debug("hw_params r: IISMOD: %x \n", iismod);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_BC_FC:
iismod |= S3C2410_IISMOD_SLAVE;
break;
case SND_SOC_DAIFMT_CBS_CFS:
case SND_SOC_DAIFMT_BP_FP:
iismod &= ~S3C2410_IISMOD_SLAVE;
break;
default:
@ -415,9 +414,10 @@ static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
};
static const struct snd_soc_component_driver s3c24xx_i2s_component = {
.name = "s3c24xx-i2s",
.suspend = s3c24xx_i2s_suspend,
.resume = s3c24xx_i2s_resume,
.name = "s3c24xx-i2s",
.suspend = s3c24xx_i2s_suspend,
.resume = s3c24xx_i2s_resume,
.legacy_dai_naming = 1,
};
static int s3c24xx_iis_dev_probe(struct platform_device *pdev)

View File

@ -139,10 +139,10 @@ static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_nc_pin(dapm, "ROUT1");
/* Headphone jack detection */
err = snd_soc_card_jack_new(rtd->card, "Headphone Jack",
SND_JACK_HEADPHONE, &smartq_jack,
smartq_jack_pins,
ARRAY_SIZE(smartq_jack_pins));
err = snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack",
SND_JACK_HEADPHONE, &smartq_jack,
smartq_jack_pins,
ARRAY_SIZE(smartq_jack_pins));
if (err)
return err;

View File

@ -216,7 +216,7 @@ static int snow_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, ret,
"snd_soc_register_card failed\n");
return ret;
return 0;
}
static int snow_remove(struct platform_device *pdev)

View File

@ -352,9 +352,10 @@ static struct snd_soc_dai_driver samsung_spdif_dai = {
};
static const struct snd_soc_component_driver samsung_spdif_component = {
.name = "samsung-spdif",
.suspend = spdif_suspend,
.resume = spdif_resume,
.name = "samsung-spdif",
.suspend = spdif_suspend,
.resume = spdif_resume,
.legacy_dai_naming = 1,
};
static int spdif_probe(struct platform_device *pdev)
@ -467,8 +468,7 @@ static int spdif_remove(struct platform_device *pdev)
iounmap(spdif->regs);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (mem_res)
release_mem_region(mem_res->start, resource_size(mem_res));
release_mem_region(mem_res->start, resource_size(mem_res));
clk_disable_unprepare(spdif->sclk);
clk_disable_unprepare(spdif->pclk);

View File

@ -156,10 +156,12 @@ static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
pr_err("Failed to request HP_SEL GPIO: %d\n", ret);
gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
ret = snd_soc_card_jack_new(rtd->card, "Headset", SND_JACK_LINEOUT |
SND_JACK_HEADSET | SND_JACK_BTN_0,
&speyside_headset, speyside_headset_pins,
ARRAY_SIZE(speyside_headset_pins));
ret = snd_soc_card_jack_new_pins(rtd->card, "Headset",
SND_JACK_LINEOUT | SND_JACK_HEADSET |
SND_JACK_BTN_0,
&speyside_headset,
speyside_headset_pins,
ARRAY_SIZE(speyside_headset_pins));
if (ret)
return ret;
@ -261,7 +263,7 @@ static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"),
};
static struct snd_soc_dapm_widget widgets[] = {
static const struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
@ -271,7 +273,7 @@ static struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_MIC("Main DMIC", NULL),
};
static struct snd_soc_dapm_route audio_paths[] = {
static const struct snd_soc_dapm_route audio_paths[] = {
{ "IN1RN", NULL, "MICB1" },
{ "IN1RP", NULL, "MICB1" },
{ "IN1RN", NULL, "MICB2" },

View File

@ -130,7 +130,7 @@ static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("DMIC"),
};
static struct snd_soc_dapm_widget widgets[] = {
static const struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
@ -140,7 +140,7 @@ static struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_SPK("Main Speaker", NULL),
};
static struct snd_soc_dapm_route audio_paths[] = {
static const struct snd_soc_dapm_route audio_paths[] = {
{ "Headphone", NULL, "HPOUTL" },
{ "Headphone", NULL, "HPOUTR" },
@ -189,10 +189,10 @@ static int tobermory_late_probe(struct snd_soc_card *card)
if (ret < 0)
return ret;
ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET |
SND_JACK_BTN_0, &tobermory_headset,
tobermory_headset_pins,
ARRAY_SIZE(tobermory_headset_pins));
ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET |
SND_JACK_BTN_0, &tobermory_headset,
tobermory_headset_pins,
ARRAY_SIZE(tobermory_headset_pins));
if (ret)
return ret;

View File

@ -47,7 +47,7 @@ config SND_SOC_RCAR
config SND_SOC_RZ
tristate "RZ/G2L series SSIF-2 support"
depends on ARCH_R9A07G044 || COMPILE_TEST
depends on ARCH_RZG2L || COMPILE_TEST
help
This option enables RZ/G2L SSIF-2 sound support.

View File

@ -1646,10 +1646,10 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
int ret;
/* set clock master audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_BC_FC:
break;
case SND_SOC_DAIFMT_CBS_CFS:
case SND_SOC_DAIFMT_BP_FP:
fsi->clk_master = 1; /* cpu is master */
break;
default:

View File

@ -307,7 +307,8 @@ static struct snd_soc_dai_driver sh4_hac_dai[] = {
};
static const struct snd_soc_component_driver sh4_hac_component = {
.name = "sh4-hac",
.name = "sh4-hac",
.legacy_dai_naming = 1,
};
static int hac_soc_platform_probe(struct platform_device *pdev)

View File

@ -755,11 +755,11 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
/* set clock master for audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBP_CFP:
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_BC_FC:
rdai->clk_master = 0;
break;
case SND_SOC_DAIFMT_CBC_CFC:
case SND_SOC_DAIFMT_BP_FP:
rdai->clk_master = 1; /* cpu is master */
break;
default:
@ -1159,6 +1159,7 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name,
struct device_node *capture)
{
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *np;
int i;
@ -1169,7 +1170,11 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name,
for_each_child_of_node(node, np) {
struct rsnd_mod *mod;
i = rsnd_node_fixed_index(np, name, i);
i = rsnd_node_fixed_index(dev, np, name, i);
if (i < 0) {
of_node_put(np);
break;
}
mod = mod_get(priv, i);
@ -1183,7 +1188,7 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name,
of_node_put(node);
}
int rsnd_node_fixed_index(struct device_node *node, char *name, int idx)
int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *name, int idx)
{
char node_name[16];
@ -1210,6 +1215,8 @@ int rsnd_node_fixed_index(struct device_node *node, char *name, int idx)
return idx;
}
dev_err(dev, "strange node numbering (%s)",
of_node_full_name(node));
return -EINVAL;
}
@ -1221,10 +1228,8 @@ int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name
i = 0;
for_each_child_of_node(node, np) {
i = rsnd_node_fixed_index(np, name, i);
i = rsnd_node_fixed_index(dev, np, name, i);
if (i < 0) {
dev_err(dev, "strange node numbering (%s)",
of_node_full_name(node));
of_node_put(np);
return 0;
}
@ -1808,11 +1813,12 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
* snd_soc_component
*/
static const struct snd_soc_component_driver rsnd_soc_component = {
.name = "rsnd",
.probe = rsnd_debugfs_probe,
.hw_params = rsnd_hw_params,
.hw_free = rsnd_hw_free,
.pointer = rsnd_pointer,
.name = "rsnd",
.probe = rsnd_debugfs_probe,
.hw_params = rsnd_hw_params,
.hw_free = rsnd_hw_free,
.pointer = rsnd_pointer,
.legacy_dai_naming = 1,
};
static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
@ -1963,19 +1969,26 @@ static int rsnd_remove(struct platform_device *pdev)
rsnd_cmd_remove,
rsnd_adg_remove,
};
int ret = 0, i;
int i;
pm_runtime_disable(&pdev->dev);
for_each_rsnd_dai(rdai, priv, i) {
ret |= rsnd_dai_call(remove, &rdai->playback, priv);
ret |= rsnd_dai_call(remove, &rdai->capture, priv);
int ret;
ret = rsnd_dai_call(remove, &rdai->playback, priv);
if (ret)
dev_warn(&pdev->dev, "Failed to remove playback dai #%d\n", i);
ret = rsnd_dai_call(remove, &rdai->capture, priv);
if (ret)
dev_warn(&pdev->dev, "Failed to remove capture dai #%d\n", i);
}
for (i = 0; i < ARRAY_SIZE(remove_func); i++)
remove_func[i](priv);
return ret;
return 0;
}
static int __maybe_unused rsnd_suspend(struct device *dev)

View File

@ -240,12 +240,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name,
struct rsnd_mod *mod, char *x)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
struct dma_chan *chan = NULL;
struct device_node *np;
int i = 0;
for_each_child_of_node(of_node, np) {
i = rsnd_node_fixed_index(np, name, i);
i = rsnd_node_fixed_index(dev, np, name, i);
if (i < 0) {
chan = NULL;
of_node_put(np);
break;
}
if (i == rsnd_mod_id_raw(mod) && (!chan))
chan = of_dma_request_slave_channel(np, x);

View File

@ -460,7 +460,7 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name,
struct device_node *playback,
struct device_node *capture);
int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name);
int rsnd_node_fixed_index(struct device_node *node, char *name, int idx);
int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *name, int idx);
int rsnd_channel_normalization(int chan);
#define rsnd_runtime_channel_original(io) \

View File

@ -676,7 +676,12 @@ int rsnd_src_probe(struct rsnd_priv *priv)
if (!of_device_is_available(np))
goto skip;
i = rsnd_node_fixed_index(np, SRC_NAME, i);
i = rsnd_node_fixed_index(dev, np, SRC_NAME, i);
if (i < 0) {
ret = -EINVAL;
of_node_put(np);
goto rsnd_src_probe_done;
}
src = rsnd_src_get(priv, i);

View File

@ -1105,6 +1105,7 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
struct device_node *capture)
{
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *node;
struct device_node *np;
int i;
@ -1117,7 +1118,11 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
for_each_child_of_node(node, np) {
struct rsnd_mod *mod;
i = rsnd_node_fixed_index(np, SSI_NAME, i);
i = rsnd_node_fixed_index(dev, np, SSI_NAME, i);
if (i < 0) {
of_node_put(np);
break;
}
mod = rsnd_ssi_mod_get(priv, i);
@ -1182,7 +1187,12 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
if (!of_device_is_available(np))
goto skip;
i = rsnd_node_fixed_index(np, SSI_NAME, i);
i = rsnd_node_fixed_index(dev, np, SSI_NAME, i);
if (i < 0) {
ret = -EINVAL;
of_node_put(np);
goto rsnd_ssi_probe_done;
}
ssi = rsnd_ssi_get(priv, i);

View File

@ -67,6 +67,8 @@ static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable)
shift = 1;
offset = 1;
break;
default:
return;
}
for (i = 0; i < 4; i++) {
@ -102,6 +104,8 @@ bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod)
shift = 1;
offset = 1;
break;
default:
goto out;
}
for (i = 0; i < 4; i++) {
@ -120,7 +124,7 @@ bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod)
}
rsnd_mod_write(mod, reg, val);
}
out:
return error;
}
@ -415,6 +419,7 @@ static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
.name = SSIU_NAME,
.dma_req = rsnd_ssiu_dma_req,
.init = rsnd_ssiu_init_gen2,
.quit = rsnd_ssiu_quit,
.start = rsnd_ssiu_start_gen2,
.stop = rsnd_ssiu_stop_gen2,
.get_status = rsnd_ssiu_get_status,
@ -460,6 +465,7 @@ void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
struct device_node *capture)
{
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *node = rsnd_ssiu_of_node(priv);
struct rsnd_dai_stream *io_p = &rdai->playback;
struct rsnd_dai_stream *io_c = &rdai->capture;
@ -472,7 +478,11 @@ void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
for_each_child_of_node(node, np) {
struct rsnd_mod *mod;
i = rsnd_node_fixed_index(np, SSIU_NAME, i);
i = rsnd_node_fixed_index(dev, np, SSIU_NAME, i);
if (i < 0) {
of_node_put(np);
break;
}
mod = rsnd_ssiu_mod_get(priv, i);

View File

@ -59,9 +59,7 @@
#define SSIFSR_RDC_MASK 0x3f
#define SSIFSR_RDC_SHIFT 8
#define SSIFSR_TDC(x) (((x) & 0x1f) << 24)
#define SSIFSR_TDE BIT(16)
#define SSIFSR_RDC(x) (((x) & 0x1f) << 8)
#define SSIFSR_RDF BIT(0)
#define SSIOFR_LRCONT BIT(8)
@ -769,7 +767,7 @@ static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBC_CFC:
case SND_SOC_DAIFMT_BP_FP:
break;
default:
dev_err(ssi->dev, "Codec should be clk and frame consumer\n");
@ -908,10 +906,11 @@ static struct snd_soc_dai_driver rz_ssi_soc_dai[] = {
};
static const struct snd_soc_component_driver rz_ssi_soc_component = {
.name = "rz-ssi",
.open = rz_ssi_pcm_open,
.pointer = rz_ssi_pcm_pointer,
.pcm_construct = rz_ssi_pcm_new,
.name = "rz-ssi",
.open = rz_ssi_pcm_open,
.pointer = rz_ssi_pcm_pointer,
.pcm_construct = rz_ssi_pcm_new,
.legacy_dai_naming = 1,
};
static int rz_ssi_probe(struct platform_device *pdev)
@ -978,22 +977,24 @@ static int rz_ssi_probe(struct platform_device *pdev)
/* Error Interrupt */
ssi->irq_int = platform_get_irq_byname(pdev, "int_req");
if (ssi->irq_int < 0)
return dev_err_probe(&pdev->dev, -ENODEV,
"Unable to get SSI int_req IRQ\n");
if (ssi->irq_int < 0) {
rz_ssi_release_dma_channels(ssi);
return ssi->irq_int;
}
ret = devm_request_irq(&pdev->dev, ssi->irq_int, &rz_ssi_interrupt,
0, dev_name(&pdev->dev), ssi);
if (ret < 0)
if (ret < 0) {
rz_ssi_release_dma_channels(ssi);
return dev_err_probe(&pdev->dev, ret,
"irq request error (int_req)\n");
}
if (!rz_ssi_is_dma_enabled(ssi)) {
/* Tx and Rx interrupts (pio only) */
ssi->irq_tx = platform_get_irq_byname(pdev, "dma_tx");
if (ssi->irq_tx < 0)
return dev_err_probe(&pdev->dev, -ENODEV,
"Unable to get SSI dma_tx IRQ\n");
return ssi->irq_tx;
ret = devm_request_irq(&pdev->dev, ssi->irq_tx,
&rz_ssi_interrupt, 0,
@ -1004,8 +1005,7 @@ static int rz_ssi_probe(struct platform_device *pdev)
ssi->irq_rx = platform_get_irq_byname(pdev, "dma_rx");
if (ssi->irq_rx < 0)
return dev_err_probe(&pdev->dev, -ENODEV,
"Unable to get SSI dma_rx IRQ\n");
return ssi->irq_rx;
ret = devm_request_irq(&pdev->dev, ssi->irq_rx,
&rz_ssi_interrupt, 0,
@ -1016,30 +1016,37 @@ static int rz_ssi_probe(struct platform_device *pdev)
}
ssi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(ssi->rstc))
return PTR_ERR(ssi->rstc);
if (IS_ERR(ssi->rstc)) {
ret = PTR_ERR(ssi->rstc);
goto err_reset;
}
reset_control_deassert(ssi->rstc);
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret < 0) {
pm_runtime_disable(ssi->dev);
reset_control_assert(ssi->rstc);
return dev_err_probe(ssi->dev, ret, "pm_runtime_resume_and_get failed\n");
dev_err(&pdev->dev, "pm_runtime_resume_and_get failed\n");
goto err_pm;
}
ret = devm_snd_soc_register_component(&pdev->dev, &rz_ssi_soc_component,
rz_ssi_soc_dai,
ARRAY_SIZE(rz_ssi_soc_dai));
if (ret < 0) {
rz_ssi_release_dma_channels(ssi);
pm_runtime_put(ssi->dev);
pm_runtime_disable(ssi->dev);
reset_control_assert(ssi->rstc);
dev_err(&pdev->dev, "failed to register snd component\n");
goto err_snd_soc;
}
return 0;
err_snd_soc:
pm_runtime_put(ssi->dev);
err_pm:
pm_runtime_disable(ssi->dev);
reset_control_assert(ssi->rstc);
err_reset:
rz_ssi_release_dma_channels(ssi);
return ret;
}

View File

@ -540,13 +540,14 @@ static void siu_pcm_free(struct snd_soc_component *component,
}
const struct snd_soc_component_driver siu_component = {
.name = DRV_NAME,
.open = siu_pcm_open,
.close = siu_pcm_close,
.prepare = siu_pcm_prepare,
.trigger = siu_pcm_trigger,
.pointer = siu_pcm_pointer_dma,
.pcm_construct = siu_pcm_new,
.pcm_destruct = siu_pcm_free,
.name = DRV_NAME,
.open = siu_pcm_open,
.close = siu_pcm_close,
.prepare = siu_pcm_prepare,
.trigger = siu_pcm_trigger,
.pointer = siu_pcm_pointer_dma,
.pcm_construct = siu_pcm_new,
.pcm_destruct = siu_pcm_free,
.legacy_dai_naming = 1,
};
EXPORT_SYMBOL_GPL(siu_component);

View File

@ -291,16 +291,16 @@ static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_BC_FC:
break;
case SND_SOC_DAIFMT_CBS_CFM:
case SND_SOC_DAIFMT_BP_FC:
ssicr |= CR_SCK_MASTER;
break;
case SND_SOC_DAIFMT_CBM_CFS:
case SND_SOC_DAIFMT_BC_FP:
ssicr |= CR_SWS_MASTER;
break;
case SND_SOC_DAIFMT_CBS_CFS:
case SND_SOC_DAIFMT_BP_FP:
ssicr |= CR_SWS_MASTER | CR_SCK_MASTER;
break;
default:
@ -377,7 +377,8 @@ static struct snd_soc_dai_driver sh4_ssi_dai[] = {
};
static const struct snd_soc_component_driver sh4_ssi_component = {
.name = "sh4-ssi",
.name = "sh4-ssi",
.legacy_dai_naming = 1,
};
static int sh4_soc_dai_probe(struct platform_device *pdev)

View File

@ -252,6 +252,13 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE
When selected, the probe is handled in two steps, for example to
avoid lockdeps if request_module is used in the probe.
# Supported IPC versions
config SND_SOC_SOF_IPC3
bool
config SND_SOC_SOF_INTEL_IPC4
bool
source "sound/soc/sof/amd/Kconfig"
source "sound/soc/sof/imx/Kconfig"
source "sound/soc/sof/intel/Kconfig"

View File

@ -1,8 +1,18 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\
ipc3-topology.o ipc3.o ipc3-control.o ipc3-pcm.o
control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o
# IPC implementations
ifneq ($(CONFIG_SND_SOC_SOF_IPC3),)
snd-sof-objs += ipc3.o ipc3-loader.o ipc3-topology.o ipc3-control.o ipc3-pcm.o\
ipc3-dtrace.o
endif
ifneq ($(CONFIG_SND_SOC_SOF_INTEL_IPC4),)
snd-sof-objs += ipc4.o ipc4-loader.o ipc4-topology.o ipc4-control.o ipc4-pcm.o
endif
# SOF client support
ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),)
snd-sof-objs += sof-client.o
endif

View File

@ -17,6 +17,7 @@ if SND_SOC_SOF_AMD_TOPLEVEL
config SND_SOC_SOF_AMD_COMMON
tristate
select SND_SOC_SOF
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_PCI_DEV
select SND_AMD_ACP_CONFIG
select SND_SOC_ACPI if ACPI

View File

@ -46,12 +46,14 @@
#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0xC3C
#define ACPAXI2AXI_ATU_CTRL 0xC40
#define ACP_SOFT_RESET 0x1000
#define ACP_CONTROL 0x1004
#define ACP_I2S_PIN_CONFIG 0x1400
/* Registers from ACP_PGFSM block */
#define ACP_PGFSM_CONTROL 0x141C
#define ACP_PGFSM_STATUS 0x1420
#define ACP_CLKMUX_SEL 0x1424
/* Registers from ACP_INTR block */
#define ACP_EXTERNAL_INTR_ENB 0x1800

View File

@ -34,7 +34,7 @@ int acp_sof_trace_release(struct snd_sof_dev *sdev)
}
EXPORT_SYMBOL_NS(acp_sof_trace_release, SND_SOC_SOF_AMD_COMMON);
int acp_sof_trace_init(struct snd_sof_dev *sdev,
int acp_sof_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
struct sof_ipc_dma_trace_params_ext *dtrace_params)
{
struct acp_dsp_stream *stream;
@ -46,7 +46,7 @@ int acp_sof_trace_init(struct snd_sof_dev *sdev,
if (!stream)
return -ENODEV;
stream->dmab = &sdev->dmatb;
stream->dmab = dmab;
stream->num_pages = NUM_PAGES;
ret = acp_dsp_stream_config(sdev, stream);

View File

@ -138,23 +138,75 @@ int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr,
return ret;
}
static int psp_fw_validate(struct acp_dev_data *adata)
/*
* psp_mbox_ready- function to poll ready bit of psp mbox
* @adata: acp device data
* @ack: bool variable to check ready bit status or psp ack
*/
static int psp_mbox_ready(struct acp_dev_data *adata, bool ack)
{
struct snd_sof_dev *sdev = adata->dev;
int timeout;
u32 data;
smn_write(adata->smn_dev, MP0_C2PMSG_26_REG, MBOX_ACP_SHA_DMA_COMMAND);
for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) {
msleep(20);
smn_read(adata->smn_dev, MP0_C2PMSG_26_REG, &data);
smn_read(adata->smn_dev, MP0_C2PMSG_114_REG, &data);
if (data & MBOX_READY_MASK)
return 0;
}
dev_err(sdev->dev, "FW validation timedout: status %x\n", data & MBOX_STATUS_MASK);
return -ETIMEDOUT;
dev_err(sdev->dev, "PSP error status %x\n", data & MBOX_STATUS_MASK);
if (ack)
return -ETIMEDOUT;
return -EBUSY;
}
/*
* psp_send_cmd - function to send psp command over mbox
* @adata: acp device data
* @cmd: non zero integer value for command type
*/
static int psp_send_cmd(struct acp_dev_data *adata, int cmd)
{
struct snd_sof_dev *sdev = adata->dev;
int ret, timeout;
u32 data;
if (!cmd)
return -EINVAL;
/* Get a non-zero Doorbell value from PSP */
for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) {
msleep(MBOX_DELAY);
smn_read(adata->smn_dev, MP0_C2PMSG_73_REG, &data);
if (data)
break;
}
if (!timeout) {
dev_err(sdev->dev, "Failed to get Doorbell from MBOX %x\n", MP0_C2PMSG_73_REG);
return -EINVAL;
}
/* Check if PSP is ready for new command */
ret = psp_mbox_ready(adata, 0);
if (ret)
return ret;
smn_write(adata->smn_dev, MP0_C2PMSG_114_REG, cmd);
/* Ring the Doorbell for PSP */
smn_write(adata->smn_dev, MP0_C2PMSG_73_REG, data);
/* Check MBOX ready as PSP ack */
ret = psp_mbox_ready(adata, 1);
return ret;
}
int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
@ -196,7 +248,7 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
return ret;
}
ret = psp_fw_validate(adata);
ret = psp_send_cmd(adata, MBOX_ACP_SHA_DMA_COMMAND);
if (ret)
return ret;
@ -361,10 +413,46 @@ static int acp_init(struct snd_sof_dev *sdev)
dev_err(sdev->dev, "ACP power on failed\n");
return ret;
}
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x01);
/* Reset */
return acp_reset(sdev);
}
int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state)
{
int ret;
ret = acp_reset(sdev);
if (ret) {
dev_err(sdev->dev, "ACP Reset failed\n");
return ret;
}
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x00);
return 0;
}
EXPORT_SYMBOL_NS(amd_sof_acp_suspend, SND_SOC_SOF_AMD_COMMON);
int amd_sof_acp_resume(struct snd_sof_dev *sdev)
{
int ret;
ret = acp_init(sdev);
if (ret) {
dev_err(sdev->dev, "ACP Init failed\n");
return ret;
}
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CLKMUX_SEL, 0x03);
ret = acp_memory_init(sdev);
return ret;
}
EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON);
int amd_sof_acp_probe(struct snd_sof_dev *sdev)
{
struct pci_dev *pci = to_pci_dev(sdev->dev);

View File

@ -57,8 +57,10 @@
#define ACP_SHA_STAT 0x8000
#define ACP_PSP_TIMEOUT_COUNTER 5
#define ACP_EXT_INTR_ERROR_STAT 0x20000000
#define MP0_C2PMSG_26_REG 0x03810570
#define MBOX_ACP_SHA_DMA_COMMAND 0x330000
#define MP0_C2PMSG_114_REG 0x3810AC8
#define MP0_C2PMSG_73_REG 0x3810A24
#define MBOX_ACP_SHA_DMA_COMMAND 0x70000
#define MBOX_DELAY 1000
#define MBOX_READY_MASK 0x80000000
#define MBOX_STATUS_MASK 0xFFFF
@ -204,16 +206,20 @@ int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substr
struct snd_pcm_hw_params *params,
struct snd_sof_platform_stream_params *platform_params);
extern const struct snd_sof_dsp_ops sof_renoir_ops;
extern struct snd_sof_dsp_ops sof_renoir_ops;
/* Machine configuration */
int snd_amd_acp_find_config(struct pci_dev *pci);
/* Trace */
int acp_sof_trace_init(struct snd_sof_dev *sdev,
int acp_sof_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
struct sof_ipc_dma_trace_params_ext *dtrace_params);
int acp_sof_trace_release(struct snd_sof_dev *sdev);
/* PM Callbacks */
int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state);
int amd_sof_acp_resume(struct snd_sof_dev *sdev);
struct sof_amd_acp_desc {
unsigned int host_bridge_id;
};

View File

@ -49,14 +49,23 @@ static const struct sof_amd_acp_desc renoir_chip_info = {
static const struct sof_dev_desc renoir_desc = {
.machines = snd_soc_acpi_amd_sof_machines,
.use_acpi_target_states = true,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = -1,
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &renoir_chip_info,
.default_fw_path = "amd/sof",
.default_tplg_path = "amd/sof-tplg",
.default_fw_filename = "sof-rn.ri",
.ipc_supported_mask = BIT(SOF_IPC),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "amd/sof",
},
.default_tplg_path = {
[SOF_IPC] = "amd/sof-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-rn.ri",
},
.nocodec_tplg_filename = "sof-acp.tplg",
.ops = &sof_renoir_ops,
};
@ -93,6 +102,7 @@ static int acp_pci_rn_probe(struct pci_dev *pci, const struct pci_device_id *pci
res = devm_kzalloc(&pci->dev, sizeof(struct resource) * ARRAY_SIZE(renoir_res), GFP_KERNEL);
if (!res) {
sof_pci_remove(pci);
platform_device_unregister(dmic_dev);
return -ENOMEM;
}
@ -157,6 +167,9 @@ static struct pci_driver snd_sof_pci_amd_rn_driver = {
.id_table = rn_pci_ids,
.probe = acp_pci_rn_probe,
.remove = acp_pci_rn_remove,
.driver = {
.pm = &sof_pci_pm,
},
};
module_pci_driver(snd_sof_pci_amd_rn_driver);

View File

@ -123,7 +123,7 @@ static struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev
}
/* AMD Renoir DSP ops */
const struct snd_sof_dsp_ops sof_renoir_ops = {
struct snd_sof_dsp_ops sof_renoir_ops = {
/* probe and remove */
.probe = amd_sof_acp_probe,
.remove = amd_sof_acp_remove,
@ -136,9 +136,6 @@ const struct snd_sof_dsp_ops sof_renoir_ops = {
.block_read = acp_dsp_block_read,
.block_write = acp_dsp_block_write,
/* Module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
.pre_fw_run = acp_dsp_pre_fw_run,
@ -152,7 +149,6 @@ const struct snd_sof_dsp_ops sof_renoir_ops = {
.ipc_msg_data = acp_sof_ipc_msg_data,
.get_mailbox_offset = acp_sof_ipc_get_mailbox_offset,
.irq_thread = acp_sof_ipc_irq_thread,
.fw_ready = sof_fw_ready,
/* DAI drivers */
.drv = renoir_sof_dai,
@ -177,6 +173,10 @@ const struct snd_sof_dsp_ops sof_renoir_ops = {
/* Trace Logger */
.trace_init = acp_sof_trace_init,
.trace_release = acp_sof_trace_release,
/* PM */
.suspend = amd_sof_acp_suspend,
.resume = amd_sof_acp_resume,
};
EXPORT_SYMBOL(sof_renoir_ops);

View File

@ -147,8 +147,7 @@ static int sof_compr_free(struct snd_soc_component *component,
stream.comp_id = spcm->stream[cstream->direction].comp_id;
if (spcm->prepared[cstream->direction]) {
ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd,
&stream, sizeof(stream),
ret = sof_ipc_tx_message(sdev->ipc, &stream, sizeof(stream),
&reply, sizeof(reply));
if (!ret)
spcm->prepared[cstream->direction] = false;
@ -168,11 +167,23 @@ static int sof_compr_set_params(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_compr_runtime *crtd = cstream->runtime;
struct sof_ipc_pcm_params_reply ipc_params_reply;
struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
struct sof_ipc_fw_version *v = &ready->version;
struct snd_compr_tstamp *tstamp;
struct sof_ipc_pcm_params pcm;
struct sof_ipc_pcm_params *pcm;
struct snd_sof_pcm *spcm;
size_t ext_data_size;
int ret;
if (v->abi_version < SOF_ABI_VER(3, 22, 0)) {
dev_err(component->dev,
"Compress params not supported with FW ABI version %d:%d:%d\n",
SOF_ABI_VERSION_MAJOR(v->abi_version),
SOF_ABI_VERSION_MINOR(v->abi_version),
SOF_ABI_VERSION_PATCH(v->abi_version));
return -EINVAL;
}
tstamp = crtd->private_data;
spcm = snd_sof_find_spcm_dai(component, rtd);
@ -180,40 +191,50 @@ static int sof_compr_set_params(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
ext_data_size = sizeof(params->codec);
if (sizeof(*pcm) + ext_data_size > sdev->ipc->max_payload_size)
return -EINVAL;
pcm = kzalloc(sizeof(*pcm) + ext_data_size, GFP_KERNEL);
if (!pcm)
return -ENOMEM;
cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG;
cstream->dma_buffer.dev.dev = sdev->dev;
ret = snd_compr_malloc_pages(cstream, crtd->buffer_size);
if (ret < 0)
return ret;
goto out;
ret = create_page_table(component, cstream, crtd->dma_area, crtd->dma_bytes);
if (ret < 0)
return ret;
goto out;
memset(&pcm, 0, sizeof(pcm));
pcm->params.buffer.pages = PFN_UP(crtd->dma_bytes);
pcm->hdr.size = sizeof(*pcm) + ext_data_size;
pcm->hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
pcm.params.buffer.pages = PFN_UP(crtd->dma_bytes);
pcm.hdr.size = sizeof(pcm);
pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
pcm.comp_id = spcm->stream[cstream->direction].comp_id;
pcm.params.hdr.size = sizeof(pcm.params);
pcm.params.buffer.phy_addr = spcm->stream[cstream->direction].page_table.addr;
pcm.params.buffer.size = crtd->dma_bytes;
pcm.params.direction = cstream->direction;
pcm.params.channels = params->codec.ch_out;
pcm.params.rate = params->codec.sample_rate;
pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
pcm.params.sample_container_bytes =
pcm->comp_id = spcm->stream[cstream->direction].comp_id;
pcm->params.hdr.size = sizeof(pcm->params) + ext_data_size;
pcm->params.buffer.phy_addr = spcm->stream[cstream->direction].page_table.addr;
pcm->params.buffer.size = crtd->dma_bytes;
pcm->params.direction = cstream->direction;
pcm->params.channels = params->codec.ch_out;
pcm->params.rate = params->codec.sample_rate;
pcm->params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
pcm->params.frame_fmt = SOF_IPC_FRAME_S32_LE;
pcm->params.sample_container_bytes =
snd_pcm_format_physical_width(SNDRV_PCM_FORMAT_S32) >> 3;
pcm.params.host_period_bytes = params->buffer.fragment_size;
pcm->params.host_period_bytes = params->buffer.fragment_size;
pcm->params.ext_data_length = ext_data_size;
ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
memcpy((u8 *)pcm->params.ext_data, &params->codec, ext_data_size);
ret = sof_ipc_tx_message(sdev->ipc, pcm, sizeof(*pcm) + ext_data_size,
&ipc_params_reply, sizeof(ipc_params_reply));
if (ret < 0) {
dev_err(component->dev, "error ipc failed\n");
return ret;
goto out;
}
tstamp->byte_offset = sdev->stream_box.offset + ipc_params_reply.posn_offset;
@ -221,7 +242,10 @@ static int sof_compr_set_params(struct snd_soc_component *component,
spcm->prepared[cstream->direction] = true;
return 0;
out:
kfree(pcm);
return ret;
}
static int sof_compr_get_params(struct snd_soc_component *component,
@ -268,8 +292,7 @@ static int sof_compr_trigger(struct snd_soc_component *component,
break;
}
return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd,
&stream, sizeof(stream),
return sof_ipc_tx_message(sdev->ipc, &stream, sizeof(stream),
&reply, sizeof(reply));
}

View File

@ -15,36 +15,6 @@
#include "sof-priv.h"
#include "sof-audio.h"
static void update_mute_led(struct snd_sof_control *scontrol,
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int temp = 0;
int mask;
int i;
mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
for (i = 0; i < scontrol->num_channels; i++) {
if (ucontrol->value.integer.value[i]) {
temp |= mask;
break;
}
}
if (temp == scontrol->led_ctl.led_value)
return;
scontrol->led_ctl.led_value = temp;
#if IS_REACHABLE(CONFIG_LEDS_TRIGGER_AUDIO)
if (!scontrol->led_ctl.direction)
ledtrig_audio_set(LED_AUDIO_MUTE, temp ? LED_OFF : LED_ON);
else
ledtrig_audio_set(LED_AUDIO_MICMUTE, temp ? LED_OFF : LED_ON);
#endif
}
int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@ -121,9 +91,6 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
if (scontrol->led_ctl.use_led)
update_mute_led(scontrol, kcontrol, ucontrol);
if (tplg_ops->control->switch_put)
return tplg_ops->control->switch_put(scontrol, ucontrol);
@ -220,10 +187,9 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
int ret, err;
ret = pm_runtime_get_sync(scomp->dev);
ret = pm_runtime_resume_and_get(scomp->dev);
if (ret < 0 && ret != -EACCES) {
dev_err_ratelimited(scomp->dev, "%s: failed to resume %d\n", __func__, ret);
pm_runtime_put_noidle(scomp->dev);
return ret;
}

View File

@ -189,7 +189,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
ret = snd_sof_probe(sdev);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret);
return ret;
goto probe_err;
}
sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
@ -250,14 +250,13 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
}
if (sof_debug_check_flag(SOF_DBG_ENABLE_TRACE)) {
sdev->dtrace_is_supported = true;
sdev->fw_trace_is_supported = true;
/* init DMA trace */
ret = snd_sof_init_trace(sdev);
/* init firmware tracing */
ret = sof_fw_trace_init(sdev);
if (ret < 0) {
/* non fatal */
dev_warn(sdev->dev,
"warning: failed to initialize trace %d\n",
dev_warn(sdev->dev, "failed to initialize firmware tracing %d\n",
ret);
}
} else {
@ -308,7 +307,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
sof_machine_err:
snd_sof_machine_unregister(sdev, plat_data);
fw_trace_err:
snd_sof_free_trace(sdev);
sof_fw_trace_free(sdev);
fw_run_err:
snd_sof_fw_unload(sdev);
fw_load_err:
@ -318,6 +317,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
snd_sof_free_debug(sdev);
dsp_err:
snd_sof_remove(sdev);
probe_err:
sof_ops_free(sdev);
/* all resources freed, update state to match */
sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
@ -342,6 +343,7 @@ static void sof_probe_work(struct work_struct *work)
int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
{
struct snd_sof_dev *sdev;
int ret;
sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL);
if (!sdev)
@ -357,11 +359,24 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
sdev->first_boot = true;
dev_set_drvdata(dev, sdev);
/* check IPC support */
if (!(BIT(plat_data->ipc_type) & plat_data->desc->ipc_supported_mask)) {
dev_err(dev, "ipc_type %d is not supported on this platform, mask is %#x\n",
plat_data->ipc_type, plat_data->desc->ipc_supported_mask);
return -EINVAL;
}
/* init ops, if necessary */
ret = sof_ops_init(sdev);
if (ret < 0)
return ret;
/* check all mandatory ops */
if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run ||
!sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write ||
!sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware ||
!sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->fw_ready) {
!sof_ops(sdev)->ipc_msg_data) {
sof_ops_free(sdev);
dev_err(dev, "error: missing mandatory ops\n");
return -EINVAL;
}
@ -434,7 +449,7 @@ int snd_sof_device_remove(struct device *dev)
snd_sof_machine_unregister(sdev, pdata);
if (sdev->fw_state > SOF_FW_BOOT_NOT_STARTED) {
snd_sof_free_trace(sdev);
sof_fw_trace_free(sdev);
ret = snd_sof_dsp_power_down_notify(sdev);
if (ret < 0)
dev_warn(dev, "error: %d failed to prepare DSP for device removal",
@ -445,6 +460,8 @@ int snd_sof_device_remove(struct device *dev)
snd_sof_remove(sdev);
}
sof_ops_free(sdev);
/* release firmware */
snd_sof_fw_unload(sdev);

View File

@ -229,14 +229,13 @@ static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_s
if (!reply)
return -ENOMEM;
ret = pm_runtime_get_sync(sdev->dev);
ret = pm_runtime_resume_and_get(sdev->dev);
if (ret < 0 && ret != -EACCES) {
pm_runtime_put_noidle(sdev->dev);
dev_err(sdev->dev, "error: enabling device failed: %d\n", ret);
goto error;
}
ret = sof_ipc_tx_message(sdev->ipc, msg.cmd, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE);
ret = sof_ipc_tx_message(sdev->ipc, &msg, msg.size, reply, SOF_IPC_MSG_MAX_SIZE);
pm_runtime_mark_last_busy(sdev->dev);
pm_runtime_put_autosuspend(sdev->dev);
if (ret < 0 || reply->rhdr.error < 0) {
@ -253,9 +252,9 @@ static int memory_info_update(struct snd_sof_dev *sdev, char *buf, size_t buff_s
}
for (i = 0, len = 0; i < reply->num_elems; i++) {
ret = snprintf(buf + len, buff_size - len, "zone %d.%d used %#8x free %#8x\n",
reply->elems[i].zone, reply->elems[i].id,
reply->elems[i].used, reply->elems[i].free);
ret = scnprintf(buf + len, buff_size - len, "zone %d.%d used %#8x free %#8x\n",
reply->elems[i].zone, reply->elems[i].id,
reply->elems[i].used, reply->elems[i].free);
if (ret < 0)
goto error;
len += ret;
@ -331,7 +330,7 @@ EXPORT_SYMBOL_GPL(snd_sof_dbg_memory_info_init);
int snd_sof_dbg_init(struct snd_sof_dev *sdev)
{
const struct snd_sof_dsp_ops *ops = sof_ops(sdev);
struct snd_sof_dsp_ops *ops = sof_ops(sdev);
const struct snd_sof_debugfs_map *map;
int i;
int err;
@ -429,7 +428,7 @@ static void snd_sof_ipc_dump(struct snd_sof_dev *sdev)
}
}
void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev)
void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev, const char *msg)
{
if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) ||
sof_debug_check_flag(SOF_DBG_RETAIN_CTX)) {
@ -442,8 +441,7 @@ void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev)
/* dump vital information to the logs */
snd_sof_ipc_dump(sdev);
snd_sof_dsp_dbg_dump(sdev, "Firmware exception",
SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
snd_sof_trace_notify_for_error(sdev);
snd_sof_dsp_dbg_dump(sdev, msg, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
sof_fw_trace_fw_crashed(sdev);
}
EXPORT_SYMBOL(snd_sof_handle_fw_exception);

View File

@ -15,6 +15,7 @@ config SND_SOC_SOF_IMX_COMMON
tristate
select SND_SOC_SOF_OF_DEV
select SND_SOC_SOF
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_XTENSA
select SND_SOC_SOF_COMPRESS
help

View File

@ -487,7 +487,7 @@ static int imx8_dsp_set_power_state(struct snd_sof_dev *sdev,
}
/* i.MX8 ops */
static const struct snd_sof_dsp_ops sof_imx8_ops = {
static struct snd_sof_dsp_ops sof_imx8_ops = {
/* probe and remove */
.probe = imx8_probe,
.remove = imx8_remove,
@ -504,16 +504,14 @@ static const struct snd_sof_dsp_ops sof_imx8_ops = {
/* ipc */
.send_msg = imx8_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = imx8_get_mailbox_offset,
.get_window_offset = imx8_get_window_offset,
.ipc_msg_data = sof_ipc_msg_data,
.set_stream_data_offset = sof_set_stream_data_offset,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
.get_bar_index = imx8_get_bar_index,
/* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
@ -550,7 +548,7 @@ static const struct snd_sof_dsp_ops sof_imx8_ops = {
};
/* i.MX8X ops */
static const struct snd_sof_dsp_ops sof_imx8x_ops = {
static struct snd_sof_dsp_ops sof_imx8x_ops = {
/* probe and remove */
.probe = imx8_probe,
.remove = imx8_remove,
@ -567,16 +565,14 @@ static const struct snd_sof_dsp_ops sof_imx8x_ops = {
/* ipc */
.send_msg = imx8_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = imx8_get_mailbox_offset,
.get_window_offset = imx8_get_window_offset,
.ipc_msg_data = sof_ipc_msg_data,
.set_stream_data_offset = sof_set_stream_data_offset,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
.get_bar_index = imx8_get_bar_index,
/* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
@ -613,17 +609,33 @@ static const struct snd_sof_dsp_ops sof_imx8x_ops = {
};
static struct sof_dev_desc sof_of_imx8qxp_desc = {
.default_fw_path = "imx/sof",
.default_tplg_path = "imx/sof-tplg",
.default_fw_filename = "sof-imx8x.ri",
.ipc_supported_mask = BIT(SOF_IPC),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "imx/sof",
},
.default_tplg_path = {
[SOF_IPC] = "imx/sof-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-imx8x.ri",
},
.nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
.ops = &sof_imx8x_ops,
};
static struct sof_dev_desc sof_of_imx8qm_desc = {
.default_fw_path = "imx/sof",
.default_tplg_path = "imx/sof-tplg",
.default_fw_filename = "sof-imx8.ri",
.ipc_supported_mask = BIT(SOF_IPC),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "imx/sof",
},
.default_tplg_path = {
[SOF_IPC] = "imx/sof-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-imx8.ri",
},
.nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
.ops = &sof_imx8_ops,
};

View File

@ -412,7 +412,7 @@ static int imx8m_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state
}
/* i.MX8 ops */
static const struct snd_sof_dsp_ops sof_imx8m_ops = {
static struct snd_sof_dsp_ops sof_imx8m_ops = {
/* probe and remove */
.probe = imx8m_probe,
.remove = imx8m_remove,
@ -430,16 +430,14 @@ static const struct snd_sof_dsp_ops sof_imx8m_ops = {
/* ipc */
.send_msg = imx8m_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = imx8m_get_mailbox_offset,
.get_window_offset = imx8m_get_window_offset,
.ipc_msg_data = sof_ipc_msg_data,
.set_stream_data_offset = sof_set_stream_data_offset,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
.get_bar_index = imx8m_get_bar_index,
/* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
@ -473,9 +471,17 @@ static const struct snd_sof_dsp_ops sof_imx8m_ops = {
};
static struct sof_dev_desc sof_of_imx8mp_desc = {
.default_fw_path = "imx/sof",
.default_tplg_path = "imx/sof-tplg",
.default_fw_filename = "sof-imx8m.ri",
.ipc_supported_mask = BIT(SOF_IPC),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "imx/sof",
},
.default_tplg_path = {
[SOF_IPC] = "imx/sof-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-imx8m.ri",
},
.nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
.ops = &sof_imx8m_ops,
};

View File

@ -40,6 +40,7 @@ if SND_SOC_SOF_ACPI
config SND_SOC_SOF_BAYTRAIL
tristate "SOF support for Baytrail, Braswell and Cherrytrail"
default SND_SOC_SOF_ACPI
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_COMMON
select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
select SND_SOC_SOF_ACPI_DEV
@ -60,6 +61,7 @@ config SND_SOC_SOF_BAYTRAIL
config SND_SOC_SOF_BROADWELL
tristate "SOF support for Broadwell"
default SND_SOC_SOF_ACPI
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_COMMON
select SND_SOC_SOF_INTEL_HIFI_EP_IPC
select SND_SOC_SOF_ACPI_DEV
@ -85,6 +87,7 @@ config SND_SOC_SOF_MERRIFIELD
tristate "SOF support for Tangier/Merrifield"
default SND_SOC_SOF_PCI
select SND_SOC_SOF_PCI_DEV
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
help
This adds support for Sound Open Firmware for Intel(R) platforms
@ -95,6 +98,8 @@ config SND_SOC_SOF_MERRIFIELD
config SND_SOC_SOF_INTEL_APL
tristate
select SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_IPC4
config SND_SOC_SOF_APOLLOLAKE
tristate "SOF support for Apollolake"
@ -120,6 +125,8 @@ config SND_SOC_SOF_INTEL_CNL
tristate
select SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_IPC4
config SND_SOC_SOF_CANNONLAKE
tristate "SOF support for Cannonlake"
@ -154,6 +161,8 @@ config SND_SOC_SOF_INTEL_ICL
tristate
select SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_IPC4
config SND_SOC_SOF_ICELAKE
tristate "SOF support for Icelake"
@ -179,6 +188,8 @@ config SND_SOC_SOF_INTEL_TGL
tristate
select SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_IPC4
config SND_SOC_SOF_TIGERLAKE
tristate "SOF support for Tigerlake"
@ -210,6 +221,22 @@ config SND_SOC_SOF_ALDERLAKE
Say Y if you have such a device.
If unsure select "N".
config SND_SOC_SOF_INTEL_MTL
tristate
select SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
select SND_SOC_SOF_INTEL_IPC4
config SND_SOC_SOF_METEORLAKE
tristate "SOF support for Meteorlake"
default SND_SOC_SOF_PCI
select SND_SOC_SOF_INTEL_MTL
help
This adds support for Sound Open Firmware for Intel(R) platforms
using the Meteorlake processors.
Say Y if you have such a device.
If unsure select "N".
config SND_SOC_SOF_HDA_COMMON
tristate
select SND_SOC_SOF_INTEL_COMMON
@ -260,7 +287,7 @@ config SND_SOC_SOF_HDA
'select' statements at a higher level.
config SND_SOC_SOF_HDA_PROBES
bool
tristate
select SND_SOC_SOF_DEBUG_PROBES
help
The option enables the data probing for Intel(R) Skylake and newer

View File

@ -6,7 +6,7 @@ snd-sof-acpi-intel-bdw-objs := bdw.o
snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \
hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \
hda-dai.o hda-bus.o \
apl.o cnl.o tgl.o icl.o
apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o
snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-probes.o
snd-sof-intel-hda-objs := hda-codec.o
@ -24,9 +24,11 @@ snd-sof-pci-intel-apl-objs := pci-apl.o
snd-sof-pci-intel-cnl-objs := pci-cnl.o
snd-sof-pci-intel-icl-objs := pci-icl.o
snd-sof-pci-intel-tgl-objs := pci-tgl.o
snd-sof-pci-intel-mtl-objs := pci-mtl.o
obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_APL) += snd-sof-pci-intel-apl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_CNL) += snd-sof-pci-intel-cnl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_TGL) += snd-sof-pci-intel-tgl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_MTL) += snd-sof-pci-intel-mtl.o

View File

@ -15,6 +15,8 @@
* Hardware interface for audio DSP on Apollolake and GeminiLake
*/
#include <sound/sof/ext_manifest4.h>
#include "../ipc4-priv.h"
#include "../sof-priv.h"
#include "hda.h"
#include "../sof-audio.h"
@ -26,108 +28,62 @@ static const struct snd_sof_debugfs_map apl_dsp_debugfs[] = {
};
/* apollolake ops */
const struct snd_sof_dsp_ops sof_apl_ops = {
struct snd_sof_dsp_ops sof_apl_ops;
EXPORT_SYMBOL_NS(sof_apl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
int sof_apl_ops_init(struct snd_sof_dev *sdev)
{
/* common defaults */
memcpy(&sof_apl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
/* probe/remove/shutdown */
.probe = hda_dsp_probe,
.remove = hda_dsp_remove,
.shutdown = hda_dsp_shutdown,
sof_apl_ops.shutdown = hda_dsp_shutdown;
/* Register IO */
.write = sof_io_write,
.read = sof_io_read,
.write64 = sof_io_write64,
.read64 = sof_io_read64,
if (sdev->pdata->ipc_type == SOF_IPC) {
/* doorbell */
sof_apl_ops.irq_thread = hda_dsp_ipc_irq_thread;
/* Block IO */
.block_read = sof_block_read,
.block_write = sof_block_write,
/* ipc */
sof_apl_ops.send_msg = hda_dsp_ipc_send_msg;
}
/* Mailbox IO */
.mailbox_read = sof_mailbox_read,
.mailbox_write = sof_mailbox_write,
if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
struct sof_ipc4_fw_data *ipc4_data;
/* doorbell */
.irq_thread = hda_dsp_ipc_irq_thread,
sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
/* ipc */
.send_msg = hda_dsp_ipc_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset,
.get_window_offset = hda_dsp_ipc_get_window_offset,
ipc4_data = sdev->private;
ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
.ipc_msg_data = hda_ipc_msg_data,
.set_stream_data_offset = hda_set_stream_data_offset,
/* doorbell */
sof_apl_ops.irq_thread = hda_dsp_ipc4_irq_thread;
/* machine driver */
.machine_select = hda_machine_select,
.machine_register = sof_machine_register,
.machine_unregister = sof_machine_unregister,
.set_mach_params = hda_set_mach_params,
/* ipc */
sof_apl_ops.send_msg = hda_dsp_ipc4_send_msg;
}
/* set DAI driver ops */
hda_set_dai_drv_ops(sdev, &sof_apl_ops);
/* debug */
.debug_map = apl_dsp_debugfs,
.debug_map_count = ARRAY_SIZE(apl_dsp_debugfs),
.dbg_dump = hda_dsp_dump,
.ipc_dump = hda_ipc_dump,
.debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
/* stream callbacks */
.pcm_open = hda_dsp_pcm_open,
.pcm_close = hda_dsp_pcm_close,
.pcm_hw_params = hda_dsp_pcm_hw_params,
.pcm_hw_free = hda_dsp_stream_hw_free,
.pcm_trigger = hda_dsp_pcm_trigger,
.pcm_pointer = hda_dsp_pcm_pointer,
.pcm_ack = hda_dsp_pcm_ack,
/* firmware loading */
.load_firmware = snd_sof_load_firmware_raw,
sof_apl_ops.debug_map = apl_dsp_debugfs;
sof_apl_ops.debug_map_count = ARRAY_SIZE(apl_dsp_debugfs);
sof_apl_ops.ipc_dump = hda_ipc_dump;
/* firmware run */
.run = hda_dsp_cl_boot_firmware,
sof_apl_ops.run = hda_dsp_cl_boot_firmware;
/* pre/post fw run */
.pre_fw_run = hda_dsp_pre_fw_run,
.post_fw_run = hda_dsp_post_fw_run,
/* parse platform specific extended manifest */
.parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
sof_apl_ops.post_fw_run = hda_dsp_post_fw_run;
/* dsp core get/put */
.core_get = hda_dsp_core_get,
sof_apl_ops.core_get = hda_dsp_core_get;
/* trace callback */
.trace_init = hda_dsp_trace_init,
.trace_release = hda_dsp_trace_release,
.trace_trigger = hda_dsp_trace_trigger,
/* client ops */
.register_ipc_clients = hda_register_clients,
.unregister_ipc_clients = hda_unregister_clients,
/* DAI drivers */
.drv = skl_dai,
.num_drv = SOF_SKL_NUM_DAIS,
/* PM */
.suspend = hda_dsp_suspend,
.resume = hda_dsp_resume,
.runtime_suspend = hda_dsp_runtime_suspend,
.runtime_resume = hda_dsp_runtime_resume,
.runtime_idle = hda_dsp_runtime_idle,
.set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume,
.set_power_state = hda_dsp_set_power_state,
/* ALSA HW info flags */
.hw_info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
.dsp_arch_ops = &sof_xtensa_arch_ops,
return 0;
};
EXPORT_SYMBOL_NS(sof_apl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
EXPORT_SYMBOL_NS(sof_apl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc apl_chip_info = {
/* Apollolake */
@ -139,9 +95,13 @@ const struct sof_intel_dsp_desc apl_chip_info = {
.ipc_ack = HDA_DSP_REG_HIPCIE,
.ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE,
.ipc_ctl = HDA_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 150,
.ssp_count = APL_SSP_COUNT,
.ssp_base_offset = APL_SSP_BASE_OFFSET,
.quirks = SOF_INTEL_PROCEN_FMT_QUIRK,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.hw_ip_version = SOF_INTEL_CAVS_1_5_PLUS,
};
EXPORT_SYMBOL_NS(apl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);

View File

@ -274,22 +274,22 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
const char *ssp_str)
{
const char *tplg_filename = NULL;
char *filename;
char *split_ext;
const char *split_ext;
char *filename, *tmp;
filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL);
filename = kstrdup(sof_tplg_filename, GFP_KERNEL);
if (!filename)
return NULL;
/* this assumes a .tplg extension */
split_ext = strsep(&filename, ".");
if (split_ext) {
tmp = filename;
split_ext = strsep(&tmp, ".");
if (split_ext)
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s-%s.tplg",
split_ext, ssp_str);
if (!tplg_filename)
return NULL;
}
kfree(filename);
return tplg_filename;
}

View File

@ -567,7 +567,7 @@ static struct snd_soc_dai_driver bdw_dai[] = {
};
/* broadwell ops */
static const struct snd_sof_dsp_ops sof_bdw_ops = {
static struct snd_sof_dsp_ops sof_bdw_ops = {
/*Device init */
.probe = bdw_probe,
@ -591,7 +591,6 @@ static const struct snd_sof_dsp_ops sof_bdw_ops = {
/* ipc */
.send_msg = bdw_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = bdw_get_mailbox_offset,
.get_window_offset = bdw_get_window_offset,
@ -614,9 +613,6 @@ static const struct snd_sof_dsp_ops sof_bdw_ops = {
.pcm_open = sof_stream_pcm_open,
.pcm_close = sof_stream_pcm_close,
/* Module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
@ -637,6 +633,7 @@ static const struct snd_sof_dsp_ops sof_bdw_ops = {
static const struct sof_intel_dsp_desc bdw_chip_info = {
.cores_num = 1,
.host_managed_cores_mask = 1,
.hw_ip_version = SOF_INTEL_BROADWELL,
};
static const struct sof_dev_desc sof_acpi_broadwell_desc = {
@ -646,9 +643,17 @@ static const struct sof_dev_desc sof_acpi_broadwell_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = 0,
.chip_info = &bdw_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-bdw.ri",
.ipc_supported_mask = BIT(SOF_IPC),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-bdw.ri",
},
.nocodec_tplg_filename = "sof-bdw-nocodec.tplg",
.ops = &sof_bdw_ops,
};
@ -676,11 +681,8 @@ static int sof_broadwell_probe(struct platform_device *pdev)
return -ENODEV;
}
desc = device_get_match_data(dev);
if (!desc)
return -ENODEV;
return sof_acpi_probe(pdev, device_get_match_data(dev));
desc = (const struct sof_dev_desc *)id->driver_data;
return sof_acpi_probe(pdev, desc);
}
/* acpi_driver definition */

View File

@ -216,7 +216,7 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev)
}
/* baytrail ops */
static const struct snd_sof_dsp_ops sof_byt_ops = {
static struct snd_sof_dsp_ops sof_byt_ops = {
/* device init */
.probe = byt_acpi_probe,
.remove = byt_remove,
@ -245,7 +245,6 @@ static const struct snd_sof_dsp_ops sof_byt_ops = {
/* ipc */
.send_msg = atom_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = atom_get_mailbox_offset,
.get_window_offset = atom_get_window_offset,
@ -268,9 +267,6 @@ static const struct snd_sof_dsp_ops sof_byt_ops = {
.pcm_open = sof_stream_pcm_open,
.pcm_close = sof_stream_pcm_close,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
@ -295,10 +291,11 @@ static const struct snd_sof_dsp_ops sof_byt_ops = {
static const struct sof_intel_dsp_desc byt_chip_info = {
.cores_num = 1,
.host_managed_cores_mask = 1,
.hw_ip_version = SOF_INTEL_BAYTRAIL,
};
/* cherrytrail and braswell ops */
static const struct snd_sof_dsp_ops sof_cht_ops = {
static struct snd_sof_dsp_ops sof_cht_ops = {
/* device init */
.probe = byt_acpi_probe,
.remove = byt_remove,
@ -327,7 +324,6 @@ static const struct snd_sof_dsp_ops sof_cht_ops = {
/* ipc */
.send_msg = atom_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = atom_get_mailbox_offset,
.get_window_offset = atom_get_window_offset,
@ -350,9 +346,6 @@ static const struct snd_sof_dsp_ops sof_cht_ops = {
.pcm_open = sof_stream_pcm_open,
.pcm_close = sof_stream_pcm_close,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
@ -378,6 +371,7 @@ static const struct snd_sof_dsp_ops sof_cht_ops = {
static const struct sof_intel_dsp_desc cht_chip_info = {
.cores_num = 1,
.host_managed_cores_mask = 1,
.hw_ip_version = SOF_INTEL_BAYTRAIL,
};
/* BYTCR uses different IRQ index */
@ -388,9 +382,17 @@ static const struct sof_dev_desc sof_acpi_baytrailcr_desc = {
.resindex_imr_base = 2,
.irqindex_host_ipc = 0,
.chip_info = &byt_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-byt.ri",
.ipc_supported_mask = BIT(SOF_IPC),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-byt.ri",
},
.nocodec_tplg_filename = "sof-byt-nocodec.tplg",
.ops = &sof_byt_ops,
};
@ -402,9 +404,17 @@ static const struct sof_dev_desc sof_acpi_baytrail_desc = {
.resindex_imr_base = 2,
.irqindex_host_ipc = 5,
.chip_info = &byt_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-byt.ri",
.ipc_supported_mask = BIT(SOF_IPC),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-byt.ri",
},
.nocodec_tplg_filename = "sof-byt-nocodec.tplg",
.ops = &sof_byt_ops,
};
@ -416,9 +426,17 @@ static const struct sof_dev_desc sof_acpi_cherrytrail_desc = {
.resindex_imr_base = 2,
.irqindex_host_ipc = 5,
.chip_info = &cht_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-cht.ri",
.ipc_supported_mask = BIT(SOF_IPC),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-cht.ri",
},
.nocodec_tplg_filename = "sof-cht-nocodec.tplg",
.ops = &sof_cht_ops,
};
@ -447,10 +465,7 @@ static int sof_baytrail_probe(struct platform_device *pdev)
return -ENODEV;
}
desc = device_get_match_data(&pdev->dev);
if (!desc)
return -ENODEV;
desc = (const struct sof_dev_desc *)id->driver_data;
if (desc == &sof_acpi_baytrail_desc && soc_intel_is_byt_cr(pdev))
desc = &sof_acpi_baytrailcr_desc;

View File

@ -15,6 +15,9 @@
* Hardware interface for audio DSP on Cannonlake.
*/
#include <sound/sof/ext_manifest4.h>
#include <sound/sof/ipc4/header.h>
#include "../ipc4-priv.h"
#include "../ops.h"
#include "hda.h"
#include "hda-ipc.h"
@ -29,6 +32,74 @@ static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = {
static void cnl_ipc_host_done(struct snd_sof_dev *sdev);
static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev);
irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
bool ipc_irq = false;
u32 hipcida, hipctdr;
hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA);
if (hipcida & CNL_DSP_REG_HIPCIDA_DONE) {
/* DSP received the message */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR,
CNL_DSP_REG_HIPCCTL,
CNL_DSP_REG_HIPCCTL_DONE, 0);
cnl_ipc_dsp_done(sdev);
ipc_irq = true;
}
hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR);
if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) {
/* Message from DSP (reply or notification) */
u32 hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
CNL_DSP_REG_HIPCTDD);
u32 primary = hipctdr & CNL_DSP_REG_HIPCTDR_MSG_MASK;
u32 extension = hipctdd & CNL_DSP_REG_HIPCTDD_MSG_MASK;
if (primary & SOF_IPC4_MSG_DIR_MASK) {
/* Reply received */
if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
data->primary = primary;
data->extension = extension;
spin_lock_irq(&sdev->ipc_lock);
snd_sof_ipc_get_reply(sdev);
snd_sof_ipc_reply(sdev, data->primary);
spin_unlock_irq(&sdev->ipc_lock);
} else {
dev_dbg_ratelimited(sdev->dev,
"IPC reply before FW_READY: %#x|%#x\n",
primary, extension);
}
} else {
/* Notification received */
notification_data.primary = primary;
notification_data.extension = extension;
sdev->ipc->msg.rx_data = &notification_data;
snd_sof_ipc_msgs_rx(sdev);
sdev->ipc->msg.rx_data = NULL;
}
/* Let DSP know that we have finished processing the message */
cnl_ipc_host_done(sdev);
ipc_irq = true;
}
if (!ipc_irq)
/* This interrupt is not shared so no need to return IRQ_NONE. */
dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
return IRQ_HANDLED;
}
irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
{
struct snd_sof_dev *sdev = context;
@ -59,15 +130,20 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
CNL_DSP_REG_HIPCCTL,
CNL_DSP_REG_HIPCCTL_DONE, 0);
spin_lock_irq(&sdev->ipc_lock);
if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
spin_lock_irq(&sdev->ipc_lock);
/* handle immediate reply from DSP core */
hda_dsp_ipc_get_reply(sdev);
snd_sof_ipc_reply(sdev, msg);
/* handle immediate reply from DSP core */
hda_dsp_ipc_get_reply(sdev);
snd_sof_ipc_reply(sdev, msg);
cnl_ipc_dsp_done(sdev);
cnl_ipc_dsp_done(sdev);
spin_unlock_irq(&sdev->ipc_lock);
spin_unlock_irq(&sdev->ipc_lock);
} else {
dev_dbg_ratelimited(sdev->dev, "IPC reply before FW_READY: %#x\n",
msg);
}
ipc_irq = true;
}
@ -176,6 +252,22 @@ static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg,
return false;
}
int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
struct sof_ipc4_msg *msg_data = msg->msg_data;
/* send the message via mailbox */
if (msg_data->data_size)
sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
msg_data->data_size);
snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDD, msg_data->extension);
snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR,
msg_data->primary | CNL_DSP_REG_HIPCIDR_BUSY);
return 0;
}
int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
@ -244,108 +336,63 @@ void cnl_ipc_dump(struct snd_sof_dev *sdev)
}
/* cannonlake ops */
const struct snd_sof_dsp_ops sof_cnl_ops = {
struct snd_sof_dsp_ops sof_cnl_ops;
EXPORT_SYMBOL_NS(sof_cnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
int sof_cnl_ops_init(struct snd_sof_dev *sdev)
{
/* common defaults */
memcpy(&sof_cnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
/* probe/remove/shutdown */
.probe = hda_dsp_probe,
.remove = hda_dsp_remove,
.shutdown = hda_dsp_shutdown,
/* Register IO */
.write = sof_io_write,
.read = sof_io_read,
.write64 = sof_io_write64,
.read64 = sof_io_read64,
/* Block IO */
.block_read = sof_block_read,
.block_write = sof_block_write,
/* Mailbox IO */
.mailbox_read = sof_mailbox_read,
.mailbox_write = sof_mailbox_write,
/* doorbell */
.irq_thread = cnl_ipc_irq_thread,
sof_cnl_ops.shutdown = hda_dsp_shutdown;
/* ipc */
.send_msg = cnl_ipc_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset,
.get_window_offset = hda_dsp_ipc_get_window_offset,
if (sdev->pdata->ipc_type == SOF_IPC) {
/* doorbell */
sof_cnl_ops.irq_thread = cnl_ipc_irq_thread;
.ipc_msg_data = hda_ipc_msg_data,
.set_stream_data_offset = hda_set_stream_data_offset,
/* ipc */
sof_cnl_ops.send_msg = cnl_ipc_send_msg;
}
/* machine driver */
.machine_select = hda_machine_select,
.machine_register = sof_machine_register,
.machine_unregister = sof_machine_unregister,
.set_mach_params = hda_set_mach_params,
if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
struct sof_ipc4_fw_data *ipc4_data;
sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
ipc4_data = sdev->private;
ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
/* doorbell */
sof_cnl_ops.irq_thread = cnl_ipc4_irq_thread;
/* ipc */
sof_cnl_ops.send_msg = cnl_ipc4_send_msg;
}
/* set DAI driver ops */
hda_set_dai_drv_ops(sdev, &sof_cnl_ops);
/* debug */
.debug_map = cnl_dsp_debugfs,
.debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs),
.dbg_dump = hda_dsp_dump,
.ipc_dump = cnl_ipc_dump,
.debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
/* stream callbacks */
.pcm_open = hda_dsp_pcm_open,
.pcm_close = hda_dsp_pcm_close,
.pcm_hw_params = hda_dsp_pcm_hw_params,
.pcm_hw_free = hda_dsp_stream_hw_free,
.pcm_trigger = hda_dsp_pcm_trigger,
.pcm_pointer = hda_dsp_pcm_pointer,
.pcm_ack = hda_dsp_pcm_ack,
/* firmware loading */
.load_firmware = snd_sof_load_firmware_raw,
sof_cnl_ops.debug_map = cnl_dsp_debugfs;
sof_cnl_ops.debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs);
sof_cnl_ops.ipc_dump = cnl_ipc_dump;
/* pre/post fw run */
.pre_fw_run = hda_dsp_pre_fw_run,
.post_fw_run = hda_dsp_post_fw_run,
/* parse platform specific extended manifest */
.parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
/* dsp core get/put */
.core_get = hda_dsp_core_get,
sof_cnl_ops.post_fw_run = hda_dsp_post_fw_run;
/* firmware run */
.run = hda_dsp_cl_boot_firmware,
sof_cnl_ops.run = hda_dsp_cl_boot_firmware;
/* trace callback */
.trace_init = hda_dsp_trace_init,
.trace_release = hda_dsp_trace_release,
.trace_trigger = hda_dsp_trace_trigger,
/* dsp core get/put */
sof_cnl_ops.core_get = hda_dsp_core_get;
/* client ops */
.register_ipc_clients = hda_register_clients,
.unregister_ipc_clients = hda_unregister_clients,
/* DAI drivers */
.drv = skl_dai,
.num_drv = SOF_SKL_NUM_DAIS,
/* PM */
.suspend = hda_dsp_suspend,
.resume = hda_dsp_resume,
.runtime_suspend = hda_dsp_runtime_suspend,
.runtime_resume = hda_dsp_runtime_resume,
.runtime_idle = hda_dsp_runtime_idle,
.set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume,
.set_power_state = hda_dsp_set_power_state,
/* ALSA HW info flags */
.hw_info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
.dsp_arch_ops = &sof_xtensa_arch_ops,
return 0;
};
EXPORT_SYMBOL_NS(sof_cnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
EXPORT_SYMBOL_NS(sof_cnl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc cnl_chip_info = {
/* Cannonlake */
@ -357,12 +404,16 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
.ipc_ack = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300,
.ssp_count = CNL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.hw_ip_version = SOF_INTEL_CAVS_1_8,
};
EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
@ -383,11 +434,15 @@ const struct sof_intel_dsp_desc jsl_chip_info = {
.ipc_ack = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.hw_ip_version = SOF_INTEL_CAVS_2_0,
};
EXPORT_SYMBOL_NS(jsl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);

View File

@ -10,10 +10,23 @@
#include <sound/pcm_params.h>
#include <sound/hdaudio_ext.h>
#include <sound/intel-nhlt.h>
#include <sound/sof/ipc4/header.h>
#include <uapi/sound/sof/header.h>
#include "../ipc4-priv.h"
#include "../ipc4-topology.h"
#include "../sof-priv.h"
#include "../sof-audio.h"
#include "hda.h"
/*
* The default method is to fetch NHLT from BIOS. With this parameter set
* it is possible to override that with NHLT in the SOF topology manifest.
*/
static bool hda_use_tplg_nhlt;
module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444);
MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override");
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
struct hda_pipe_params {
@ -50,8 +63,8 @@ static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
}
static struct hdac_ext_stream *
hda_link_stream_assign(struct hdac_bus *bus,
struct snd_pcm_substream *substream)
hda_link_stream_assign(struct hdac_bus *bus,
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct sof_intel_hda_stream *hda_stream;
@ -113,12 +126,8 @@ static struct hdac_ext_stream *
}
if (res) {
/*
* Decouple host and link DMA. The decoupled flag
* is updated in snd_hdac_ext_stream_decouple().
*/
if (!res->decoupled)
snd_hdac_ext_stream_decouple_locked(bus, res, true);
/* Make sure that host and link DMA is decoupled. */
snd_hdac_ext_stream_decouple_locked(bus, res, true);
res->link_locked = 1;
res->link_substream = substream;
@ -128,6 +137,40 @@ static struct hdac_ext_stream *
return res;
}
static int hda_link_dma_cleanup(struct snd_pcm_substream *substream,
struct hdac_stream *hstream,
struct snd_soc_dai *cpu_dai,
struct snd_soc_dai *codec_dai,
bool trigger_suspend_stop)
{
struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
struct hdac_bus *bus = hstream->bus;
struct sof_intel_hda_stream *hda_stream;
struct hdac_ext_link *link;
int stream_tag;
link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
if (!link)
return -EINVAL;
if (trigger_suspend_stop)
snd_hdac_ext_link_stream_clear(hext_stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
stream_tag = hdac_stream(hext_stream)->stream_tag;
snd_hdac_ext_link_clear_stream_id(link, stream_tag);
}
snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
hext_stream->link_prepared = 0;
/* free the host DMA channel reserved by hostless streams */
hda_stream = hstream_to_sof_hda_stream(hext_stream);
hda_stream->host_reserved = 0;
return 0;
}
static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
struct hda_pipe_params *params)
{
@ -137,7 +180,6 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
struct hdac_ext_link *link;
unsigned int format_val;
snd_hdac_ext_stream_decouple(bus, hext_stream, true);
snd_hdac_ext_link_stream_reset(hext_stream);
format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch,
@ -162,61 +204,27 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
return 0;
}
static int hda_link_dai_widget_update(struct sof_intel_hda_stream *hda_stream,
struct snd_soc_dapm_widget *w,
int channel, bool widget_setup)
{
struct snd_sof_dai_config_data data;
data.dai_data = channel;
/* set up/free DAI widget and send DAI_CONFIG IPC */
if (widget_setup)
return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP, &data);
return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
}
static int hda_link_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct hdac_stream *hstream = substream->runtime->private_data;
struct hdac_bus *bus = hstream->bus;
struct hdac_ext_stream *hext_stream;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct sof_intel_hda_stream *hda_stream;
struct hda_pipe_params p_params = {0};
struct snd_soc_dapm_widget *w;
struct hdac_bus *bus = hstream->bus;
struct hdac_ext_link *link;
int stream_tag;
int ret;
/* get stored dma data if resuming from system suspend */
hext_stream = snd_soc_dai_get_dma_data(dai, substream);
hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
if (!hext_stream) {
hext_stream = hda_link_stream_assign(bus, substream);
if (!hext_stream)
return -EBUSY;
snd_soc_dai_set_dma_data(dai, substream, (void *)hext_stream);
snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream);
}
stream_tag = hdac_stream(hext_stream)->stream_tag;
hda_stream = hstream_to_sof_hda_stream(hext_stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
w = dai->playback_widget;
else
w = dai->capture_widget;
/* set up the DAI widget and send the DAI_CONFIG with the new tag */
ret = hda_link_dai_widget_update(hda_stream, w, stream_tag - 1, true);
if (ret < 0)
return ret;
link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
if (!link)
return -EINVAL;
@ -239,26 +247,117 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream,
return hda_link_dma_params(hext_stream, &p_params);
}
static int hda_link_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
static int hda_link_dma_prepare(struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *hext_stream =
snd_soc_dai_get_dma_data(dai, substream);
struct snd_sof_dev *sdev =
snd_soc_component_get_drvdata(dai->component);
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
int stream = substream->stream;
if (hext_stream->link_prepared)
return 0;
dev_dbg(sdev->dev, "hda: prepare stream dir %d\n", substream->stream);
return hda_link_hw_params(substream, &rtd->dpcm[stream].hw_params,
dai);
return hda_link_dma_hw_params(substream, &rtd->dpcm[stream].hw_params);
}
static int hda_link_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct hdac_stream *hstream = substream->runtime->private_data;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
int ret;
if (!hext_stream)
return 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
snd_hdac_ext_link_stream_start(hext_stream);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
ret = hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, true);
if (ret < 0)
return ret;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
snd_hdac_ext_link_stream_clear(hext_stream);
break;
default:
return -EINVAL;
}
return 0;
}
static int hda_link_dma_hw_free(struct snd_pcm_substream *substream)
{
struct hdac_stream *hstream = substream->runtime->private_data;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct hdac_ext_stream *hext_stream;
hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
if (!hext_stream)
return 0;
return hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, false);
}
static int hda_dai_widget_update(struct snd_soc_dapm_widget *w,
int channel, bool widget_setup)
{
struct snd_sof_dai_config_data data;
data.dai_data = channel;
/* set up/free DAI widget and send DAI_CONFIG IPC */
if (widget_setup)
return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP, &data);
return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
}
static int hda_dai_hw_params_update(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct hdac_ext_stream *hext_stream;
struct snd_soc_dapm_widget *w;
int stream_tag;
hext_stream = snd_soc_dai_get_dma_data(dai, substream);
if (!hext_stream)
return -EINVAL;
stream_tag = hdac_stream(hext_stream)->stream_tag;
w = snd_soc_dai_get_widget(dai, substream->stream);
/* set up the DAI widget and send the DAI_CONFIG with the new tag */
return hda_dai_widget_update(w, stream_tag - 1, true);
}
static int hda_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct hdac_ext_stream *hext_stream =
snd_soc_dai_get_dma_data(dai, substream);
int ret;
if (hext_stream && hext_stream->link_prepared)
return 0;
ret = hda_link_dma_hw_params(substream, params);
if (ret < 0)
return ret;
return hda_dai_hw_params_update(substream, params, dai);
}
static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
{
struct snd_sof_widget *swidget = w->dobj.private;
struct snd_soc_component *component = swidget->scomp;
@ -276,34 +375,104 @@ static int hda_link_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
return ret;
}
static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct hdac_ext_stream *hext_stream =
snd_soc_dai_get_dma_data(dai, substream);
struct sof_intel_hda_stream *hda_stream;
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_dapm_widget *w;
struct hdac_ext_link *link;
struct hdac_stream *hstream;
struct hdac_bus *bus;
int stream_tag;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
int stream = substream->stream;
int ret;
hstream = substream->runtime->private_data;
bus = hstream->bus;
rtd = asoc_substream_to_rtd(substream);
if (hext_stream && hext_stream->link_prepared)
return 0;
link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
if (!link)
return -EINVAL;
dev_dbg(sdev->dev, "prepare stream dir %d\n", substream->stream);
hda_stream = hstream_to_sof_hda_stream(hext_stream);
ret = hda_link_dma_prepare(substream);
if (ret < 0)
return ret;
dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
return hda_dai_hw_params_update(substream, &rtd->dpcm[stream].hw_params, dai);
}
static int hda_dai_hw_free_ipc(int stream, /* direction */
struct snd_soc_dai *dai)
{
struct snd_soc_dapm_widget *w;
w = snd_soc_dai_get_widget(dai, stream);
/* free the link DMA channel in the FW and the DAI widget */
return hda_dai_widget_update(w, DMA_CHAN_INVALID, false);
}
static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct snd_soc_dapm_widget *w;
int ret;
dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
dai->name, substream->stream);
ret = hda_link_dma_trigger(substream, cmd);
if (ret < 0)
return ret;
w = snd_soc_dai_get_widget(dai, substream->stream);
switch (cmd) {
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
/*
* free DAI widget during stop/suspend to keep widget use_count's balanced.
*/
ret = hda_dai_hw_free_ipc(substream->stream, dai);
if (ret < 0)
return ret;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ret = hda_dai_config_pause_push_ipc(w);
if (ret < 0)
return ret;
break;
default:
break;
}
return 0;
}
/*
* In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes
* (over IPC channel) and DMA state change (direct host register changes).
*/
static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(dai, substream);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
struct snd_soc_pcm_runtime *rtd;
struct snd_sof_widget *swidget;
struct snd_soc_dapm_widget *w;
struct snd_soc_dai *codec_dai;
struct hdac_stream *hstream;
struct snd_soc_dai *cpu_dai;
int ret;
dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
dai->name, substream->stream);
hstream = substream->runtime->private_data;
rtd = asoc_substream_to_rtd(substream);
cpu_dai = asoc_rtd_to_cpu(rtd, 0);
codec_dai = asoc_rtd_to_codec(rtd, 0);
w = snd_soc_dai_get_widget(dai, substream->stream);
swidget = w->dobj.private;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@ -311,95 +480,121 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
snd_hdac_ext_link_stream_clear(hext_stream);
{
struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
/*
* free DAI widget during stop/suspend to keep widget use_count's balanced.
*/
ret = hda_link_dai_widget_update(hda_stream, w, DMA_CHAN_INVALID, false);
ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
SOF_IPC4_PIPE_PAUSED);
if (ret < 0)
return ret;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
stream_tag = hdac_stream(hext_stream)->stream_tag;
snd_hdac_ext_link_clear_stream_id(link, stream_tag);
pipeline->state = SOF_IPC4_PIPE_PAUSED;
snd_hdac_ext_link_stream_clear(hext_stream);
ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
SOF_IPC4_PIPE_RESET);
if (ret < 0)
return ret;
pipeline->state = SOF_IPC4_PIPE_RESET;
ret = hda_link_dma_cleanup(substream, hstream, cpu_dai, codec_dai, false);
if (ret < 0) {
dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
return ret;
}
hext_stream->link_prepared = 0;
break;
}
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
snd_hdac_ext_link_stream_clear(hext_stream);
{
struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
ret = hda_link_dai_config_pause_push_ipc(w);
ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
SOF_IPC4_PIPE_PAUSED);
if (ret < 0)
return ret;
pipeline->state = SOF_IPC4_PIPE_PAUSED;
snd_hdac_ext_link_stream_clear(hext_stream);
break;
}
default:
dev_err(sdev->dev, "%s: unknown trigger command %d\n", __func__, cmd);
return -EINVAL;
}
return 0;
}
static int hda_link_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
static int hda_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
unsigned int stream_tag;
struct sof_intel_hda_stream *hda_stream;
struct hdac_bus *bus;
struct hdac_ext_link *link;
struct hdac_stream *hstream;
struct snd_soc_pcm_runtime *rtd;
struct hdac_ext_stream *hext_stream;
struct snd_soc_dapm_widget *w;
int ret;
hstream = substream->runtime->private_data;
bus = hstream->bus;
rtd = asoc_substream_to_rtd(substream);
hext_stream = snd_soc_dai_get_dma_data(dai, substream);
if (!hext_stream) {
dev_dbg(dai->dev,
"%s: hext_stream is not assigned\n", __func__);
return -EINVAL;
}
hda_stream = hstream_to_sof_hda_stream(hext_stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
w = dai->playback_widget;
else
w = dai->capture_widget;
/* free the link DMA channel in the FW and the DAI widget */
ret = hda_link_dai_widget_update(hda_stream, w, DMA_CHAN_INVALID, false);
ret = hda_link_dma_hw_free(substream);
if (ret < 0)
return ret;
link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
if (!link)
return -EINVAL;
return hda_dai_hw_free_ipc(substream->stream, dai);
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
stream_tag = hdac_stream(hext_stream)->stream_tag;
snd_hdac_ext_link_clear_stream_id(link, stream_tag);
static const struct snd_soc_dai_ops ipc3_hda_dai_ops = {
.hw_params = hda_dai_hw_params,
.hw_free = hda_dai_hw_free,
.trigger = ipc3_hda_dai_trigger,
.prepare = hda_dai_prepare,
};
static int hda_dai_suspend(struct hdac_bus *bus)
{
struct snd_soc_pcm_runtime *rtd;
struct hdac_ext_stream *hext_stream;
struct hdac_stream *s;
int ret;
/* set internal flag for BE */
list_for_each_entry(s, &bus->stream_list, list) {
hext_stream = stream_to_hdac_ext_stream(s);
/*
* clear stream. This should already be taken care for running
* streams when the SUSPEND trigger is called. But paused
* streams do not get suspended, so this needs to be done
* explicitly during suspend.
*/
if (hext_stream->link_substream) {
struct snd_soc_dai *cpu_dai;
struct snd_soc_dai *codec_dai;
rtd = asoc_substream_to_rtd(hext_stream->link_substream);
cpu_dai = asoc_rtd_to_cpu(rtd, 0);
codec_dai = asoc_rtd_to_codec(rtd, 0);
ret = hda_link_dma_cleanup(hext_stream->link_substream, s,
cpu_dai, codec_dai, false);
if (ret < 0)
return ret;
/* for consistency with TRIGGER_SUSPEND we free DAI resources */
ret = hda_dai_hw_free_ipc(hdac_stream(hext_stream)->direction, cpu_dai);
if (ret < 0)
return ret;
}
}
snd_soc_dai_set_dma_data(dai, substream, NULL);
snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
hext_stream->link_prepared = 0;
/* free the host DMA channel reserved by hostless streams */
hda_stream->host_reserved = 0;
return 0;
}
static const struct snd_soc_dai_ops hda_link_dai_ops = {
.hw_params = hda_link_hw_params,
.hw_free = hda_link_hw_free,
.trigger = hda_link_pcm_trigger,
.prepare = hda_link_pcm_prepare,
static const struct snd_soc_dai_ops ipc4_hda_dai_ops = {
.hw_params = hda_dai_hw_params,
.hw_free = hda_dai_hw_free,
.trigger = ipc4_hda_dai_trigger,
.prepare = hda_dai_prepare,
};
#endif
@ -414,10 +609,7 @@ static int ssp_dai_setup_or_free(struct snd_pcm_substream *substream, struct snd
{
struct snd_soc_dapm_widget *w;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
w = dai->playback_widget;
else
w = dai->capture_widget;
w = snd_soc_dai_get_widget(dai, substream->stream);
if (setup)
return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE, NULL);
@ -478,8 +670,8 @@ static int ssp_dai_prepare(struct snd_pcm_substream *substream,
return ssp_dai_setup(substream, dai, true);
}
static int ssp_dai_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
static int ipc3_ssp_dai_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
if (cmd != SNDRV_PCM_TRIGGER_SUSPEND)
return 0;
@ -507,15 +699,137 @@ static void ssp_dai_shutdown(struct snd_pcm_substream *substream,
kfree(dma_data);
}
static const struct snd_soc_dai_ops ssp_dai_ops = {
static const struct snd_soc_dai_ops ipc3_ssp_dai_ops = {
.startup = ssp_dai_startup,
.hw_params = ssp_dai_hw_params,
.prepare = ssp_dai_prepare,
.trigger = ssp_dai_trigger,
.trigger = ipc3_ssp_dai_trigger,
.hw_free = ssp_dai_hw_free,
.shutdown = ssp_dai_shutdown,
};
static int ipc4_be_dai_common_trigger(struct snd_soc_dai *dai, int cmd, int stream)
{
struct snd_sof_widget *pipe_widget;
struct sof_ipc4_pipeline *pipeline;
struct snd_sof_widget *swidget;
struct snd_soc_dapm_widget *w;
struct snd_sof_dev *sdev;
int ret;
w = snd_soc_dai_get_widget(dai, stream);
swidget = w->dobj.private;
pipe_widget = swidget->pipe_widget;
pipeline = pipe_widget->private;
sdev = snd_soc_component_get_drvdata(swidget->scomp);
switch (cmd) {
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
SOF_IPC4_PIPE_PAUSED);
if (ret < 0)
return ret;
pipeline->state = SOF_IPC4_PIPE_PAUSED;
ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
SOF_IPC4_PIPE_RESET);
if (ret < 0)
return ret;
pipeline->state = SOF_IPC4_PIPE_RESET;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
SOF_IPC4_PIPE_PAUSED);
if (ret < 0)
return ret;
pipeline->state = SOF_IPC4_PIPE_PAUSED;
break;
default:
break;
}
return 0;
}
static int ipc4_be_dai_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
return ipc4_be_dai_common_trigger(dai, cmd, substream->stream);
}
static const struct snd_soc_dai_ops ipc4_dmic_dai_ops = {
.trigger = ipc4_be_dai_trigger,
};
static const struct snd_soc_dai_ops ipc4_ssp_dai_ops = {
.trigger = ipc4_be_dai_trigger,
};
void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
{
int i;
switch (sdev->pdata->ipc_type) {
case SOF_IPC:
for (i = 0; i < ops->num_drv; i++) {
if (strstr(ops->drv[i].name, "SSP")) {
ops->drv[i].ops = &ipc3_ssp_dai_ops;
continue;
}
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
if (strstr(ops->drv[i].name, "iDisp") ||
strstr(ops->drv[i].name, "Analog") ||
strstr(ops->drv[i].name, "Digital"))
ops->drv[i].ops = &ipc3_hda_dai_ops;
#endif
}
break;
case SOF_INTEL_IPC4:
{
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
for (i = 0; i < ops->num_drv; i++) {
if (strstr(ops->drv[i].name, "DMIC")) {
ops->drv[i].ops = &ipc4_dmic_dai_ops;
continue;
}
if (strstr(ops->drv[i].name, "SSP")) {
ops->drv[i].ops = &ipc4_ssp_dai_ops;
continue;
}
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
if (strstr(ops->drv[i].name, "iDisp") ||
strstr(ops->drv[i].name, "Analog") ||
strstr(ops->drv[i].name, "Digital"))
ops->drv[i].ops = &ipc4_hda_dai_ops;
#endif
}
if (!hda_use_tplg_nhlt)
ipc4_data->nhlt = intel_nhlt_init(sdev->dev);
if (IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE))
sdw_callback.trigger = ipc4_be_dai_common_trigger;
break;
}
default:
break;
}
}
void hda_ops_free(struct snd_sof_dev *sdev)
{
if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
if (!hda_use_tplg_nhlt)
intel_nhlt_free(ipc4_data->nhlt);
}
}
EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON);
/*
* common dai driver for skl+ platforms.
* some products who use this DAI array only physically have a subset of
@ -524,7 +838,6 @@ static const struct snd_soc_dai_ops ssp_dai_ops = {
struct snd_soc_dai_driver skl_dai[] = {
{
.name = "SSP0 Pin",
.ops = &ssp_dai_ops,
.playback = {
.channels_min = 1,
.channels_max = 8,
@ -536,7 +849,6 @@ struct snd_soc_dai_driver skl_dai[] = {
},
{
.name = "SSP1 Pin",
.ops = &ssp_dai_ops,
.playback = {
.channels_min = 1,
.channels_max = 8,
@ -548,7 +860,6 @@ struct snd_soc_dai_driver skl_dai[] = {
},
{
.name = "SSP2 Pin",
.ops = &ssp_dai_ops,
.playback = {
.channels_min = 1,
.channels_max = 8,
@ -560,7 +871,6 @@ struct snd_soc_dai_driver skl_dai[] = {
},
{
.name = "SSP3 Pin",
.ops = &ssp_dai_ops,
.playback = {
.channels_min = 1,
.channels_max = 8,
@ -572,7 +882,6 @@ struct snd_soc_dai_driver skl_dai[] = {
},
{
.name = "SSP4 Pin",
.ops = &ssp_dai_ops,
.playback = {
.channels_min = 1,
.channels_max = 8,
@ -584,7 +893,6 @@ struct snd_soc_dai_driver skl_dai[] = {
},
{
.name = "SSP5 Pin",
.ops = &ssp_dai_ops,
.playback = {
.channels_min = 1,
.channels_max = 8,
@ -611,7 +919,6 @@ struct snd_soc_dai_driver skl_dai[] = {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
{
.name = "iDisp1 Pin",
.ops = &hda_link_dai_ops,
.playback = {
.channels_min = 1,
.channels_max = 8,
@ -619,7 +926,6 @@ struct snd_soc_dai_driver skl_dai[] = {
},
{
.name = "iDisp2 Pin",
.ops = &hda_link_dai_ops,
.playback = {
.channels_min = 1,
.channels_max = 8,
@ -627,7 +933,6 @@ struct snd_soc_dai_driver skl_dai[] = {
},
{
.name = "iDisp3 Pin",
.ops = &hda_link_dai_ops,
.playback = {
.channels_min = 1,
.channels_max = 8,
@ -635,7 +940,6 @@ struct snd_soc_dai_driver skl_dai[] = {
},
{
.name = "iDisp4 Pin",
.ops = &hda_link_dai_ops,
.playback = {
.channels_min = 1,
.channels_max = 8,
@ -643,7 +947,6 @@ struct snd_soc_dai_driver skl_dai[] = {
},
{
.name = "Analog CPU DAI",
.ops = &hda_link_dai_ops,
.playback = {
.channels_min = 1,
.channels_max = 16,
@ -655,7 +958,6 @@ struct snd_soc_dai_driver skl_dai[] = {
},
{
.name = "Digital CPU DAI",
.ops = &hda_link_dai_ops,
.playback = {
.channels_min = 1,
.channels_max = 16,
@ -667,7 +969,6 @@ struct snd_soc_dai_driver skl_dai[] = {
},
{
.name = "Alt Analog CPU DAI",
.ops = &hda_link_dai_ops,
.playback = {
.channels_min = 1,
.channels_max = 16,
@ -679,3 +980,22 @@ struct snd_soc_dai_driver skl_dai[] = {
},
#endif
};
int hda_dsp_dais_suspend(struct snd_sof_dev *sdev)
{
/*
* In the corner case where a SUSPEND happens during a PAUSE, the ALSA core
* does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state.
* Since the component suspend is called last, we can trap this corner case
* and force the DAIs to release their resources.
*/
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
int ret;
ret = hda_dai_suspend(sof_to_bus(sdev));
if (ret < 0)
return ret;
#endif
return 0;
}

View File

@ -181,12 +181,20 @@ int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask)
* Power Management.
*/
static int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask)
int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
unsigned int cpa;
u32 adspcs;
int ret;
/* restrict core_mask to host managed cores mask */
core_mask &= chip->host_managed_cores_mask;
/* return if core_mask is not valid */
if (!core_mask)
return 0;
/* update bits */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS,
HDA_DSP_ADSPCS_SPA_MASK(core_mask),
@ -363,9 +371,8 @@ static int hda_dsp_send_pm_gate_ipc(struct snd_sof_dev *sdev, u32 flags)
pm_gate.flags = flags;
/* send pm_gate ipc to dsp */
return sof_ipc_tx_message_no_pm(sdev->ipc, pm_gate.hdr.cmd,
&pm_gate, sizeof(pm_gate), &reply,
sizeof(reply));
return sof_ipc_tx_message_no_pm(sdev->ipc, &pm_gate, sizeof(pm_gate),
&reply, sizeof(reply));
}
static int hda_dsp_update_d0i3c_register(struct snd_sof_dev *sdev, u8 value)
@ -433,7 +440,7 @@ static int hda_dsp_set_D0_state(struct snd_sof_dev *sdev,
* when the DSP enters D0I3 while the system is in S0
* for debug purpose.
*/
if (!sdev->dtrace_is_supported ||
if (!sdev->fw_trace_is_supported ||
!hda_enable_trace_D0I3_S0 ||
sdev->system_suspend_target != SOF_SUSPEND_NONE)
flags = HDA_PM_NO_DMA_TRACE;
@ -610,6 +617,13 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
#endif
int ret, j;
/*
* The memory used for IMR boot loses its content in deeper than S3 state
* We must not try IMR boot on next power up (as it will fail).
*/
if (sdev->system_suspend_target > SOF_SUSPEND_S3)
hda->skip_imr_boot = true;
hda_sdw_int_enable(sdev, false);
/* disable IPC interrupts */
@ -736,7 +750,7 @@ int hda_dsp_resume(struct snd_sof_dev *sdev)
if (hlink->ref_count) {
ret = snd_hdac_ext_bus_link_power_up(hlink);
if (ret < 0) {
dev_dbg(sdev->dev,
dev_err(sdev->dev,
"error %d in %s: failed to power up links",
ret, __func__);
return ret;
@ -864,7 +878,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
/* no link can be powered in s0ix state */
ret = snd_hdac_ext_bus_link_power_down_all(bus);
if (ret < 0) {
dev_dbg(sdev->dev,
dev_err(sdev->dev,
"error %d in %s: failed to power down links",
ret, __func__);
return ret;
@ -895,44 +909,14 @@ int hda_dsp_shutdown(struct snd_sof_dev *sdev)
int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
{
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
struct hdac_bus *bus = sof_to_bus(sdev);
struct snd_soc_pcm_runtime *rtd;
struct hdac_ext_stream *hext_stream;
struct hdac_ext_link *link;
struct hdac_stream *s;
const char *name;
int stream_tag;
int ret;
/* set internal flag for BE */
list_for_each_entry(s, &bus->stream_list, list) {
hext_stream = stream_to_hdac_ext_stream(s);
/* make sure all DAI resources are freed */
ret = hda_dsp_dais_suspend(sdev);
if (ret < 0)
dev_warn(sdev->dev, "%s: failure in hda_dsp_dais_suspend\n", __func__);
/*
* clear stream. This should already be taken care for running
* streams when the SUSPEND trigger is called. But paused
* streams do not get suspended, so this needs to be done
* explicitly during suspend.
*/
if (hext_stream->link_substream) {
rtd = asoc_substream_to_rtd(hext_stream->link_substream);
name = asoc_rtd_to_codec(rtd, 0)->component->name;
link = snd_hdac_ext_bus_get_link(bus, name);
if (!link)
return -EINVAL;
hext_stream->link_prepared = 0;
if (hdac_stream(hext_stream)->direction ==
SNDRV_PCM_STREAM_CAPTURE)
continue;
stream_tag = hdac_stream(hext_stream)->stream_tag;
snd_hdac_ext_link_clear_stream_id(link, stream_tag);
}
}
#endif
return 0;
return ret;
}
void hda_dsp_d0i3_work(struct work_struct *work)
@ -963,13 +947,7 @@ void hda_dsp_d0i3_work(struct work_struct *work)
int hda_dsp_core_get(struct snd_sof_dev *sdev, int core)
{
struct sof_ipc_pm_core_config pm_core_config = {
.hdr = {
.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
.size = sizeof(pm_core_config),
},
.enable_mask = sdev->enabled_cores_mask | BIT(core),
};
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
int ret, ret1;
/* power up core */
@ -984,10 +962,12 @@ int hda_dsp_core_get(struct snd_sof_dev *sdev, int core)
if (sdev->fw_state != SOF_FW_BOOT_COMPLETE || core == SOF_DSP_PRIMARY_CORE)
return 0;
/* No need to continue the set_core_state ops is not available */
if (!pm_ops->set_core_state)
return 0;
/* Now notify DSP for secondary cores */
ret = sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd,
&pm_core_config, sizeof(pm_core_config),
&pm_core_config, sizeof(pm_core_config));
ret = pm_ops->set_core_state(sdev, core, true);
if (ret < 0) {
dev_err(sdev->dev, "failed to enable secondary core '%d' failed with %d\n",
core, ret);

View File

@ -15,6 +15,7 @@
* Hardware interface for generic Intel audio DSP HDA IP
*/
#include <sound/sof/ipc4/header.h>
#include "../ops.h"
#include "hda.h"
@ -65,6 +66,22 @@ int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
return 0;
}
int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
struct sof_ipc4_msg *msg_data = msg->msg_data;
/* send the message via mailbox */
if (msg_data->data_size)
sof_mailbox_write(sdev, sdev->host_box.offset, msg_data->data_ptr,
msg_data->data_size);
snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE, msg_data->extension);
snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI,
msg_data->primary | HDA_DSP_REG_HIPCI_BUSY);
return 0;
}
void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
{
struct snd_sof_ipc_msg *msg = sdev->msg;
@ -100,6 +117,77 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
}
}
irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
bool ipc_irq = false;
u32 hipcie, hipct;
hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE);
if (hipcie & HDA_DSP_REG_HIPCIE_DONE) {
/* DSP received the message */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL,
HDA_DSP_REG_HIPCCTL_DONE, 0);
hda_dsp_ipc_dsp_done(sdev);
ipc_irq = true;
}
hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
if (hipct & HDA_DSP_REG_HIPCT_BUSY) {
/* Message from DSP (reply or notification) */
u32 hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
HDA_DSP_REG_HIPCTE);
u32 primary = hipct & HDA_DSP_REG_HIPCT_MSG_MASK;
u32 extension = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK;
/* mask BUSY interrupt */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL,
HDA_DSP_REG_HIPCCTL_BUSY, 0);
if (primary & SOF_IPC4_MSG_DIR_MASK) {
/* Reply received */
if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data;
data->primary = primary;
data->extension = extension;
spin_lock_irq(&sdev->ipc_lock);
snd_sof_ipc_get_reply(sdev);
snd_sof_ipc_reply(sdev, data->primary);
spin_unlock_irq(&sdev->ipc_lock);
} else {
dev_dbg_ratelimited(sdev->dev,
"IPC reply before FW_READY: %#x|%#x\n",
primary, extension);
}
} else {
/* Notification received */
notification_data.primary = primary;
notification_data.extension = extension;
sdev->ipc->msg.rx_data = &notification_data;
snd_sof_ipc_msgs_rx(sdev);
sdev->ipc->msg.rx_data = NULL;
}
/* Let DSP know that we have finished processing the message */
hda_dsp_ipc_host_done(sdev);
ipc_irq = true;
}
if (!ipc_irq)
/* This interrupt is not shared so no need to return IRQ_NONE. */
dev_dbg_ratelimited(sdev->dev, "nothing to do in IPC IRQ thread\n");
return IRQ_HANDLED;
}
/* IPC handler thread */
irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
{
@ -143,16 +231,21 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
* place, the message might not yet be marked as expecting a
* reply.
*/
spin_lock_irq(&sdev->ipc_lock);
if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
spin_lock_irq(&sdev->ipc_lock);
/* handle immediate reply from DSP core */
hda_dsp_ipc_get_reply(sdev);
snd_sof_ipc_reply(sdev, msg);
/* handle immediate reply from DSP core */
hda_dsp_ipc_get_reply(sdev);
snd_sof_ipc_reply(sdev, msg);
/* set the done bit */
hda_dsp_ipc_dsp_done(sdev);
/* set the done bit */
hda_dsp_ipc_dsp_done(sdev);
spin_unlock_irq(&sdev->ipc_lock);
spin_unlock_irq(&sdev->ipc_lock);
} else {
dev_dbg_ratelimited(sdev->dev, "IPC reply before FW_READY: %#x\n",
msg);
}
ipc_irq = true;
}

View File

@ -24,8 +24,6 @@
#include "../sof-priv.h"
#include "hda.h"
#define HDA_CL_STREAM_FORMAT 0x40
static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
@ -43,9 +41,9 @@ static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev)
}
}
static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
unsigned int size, struct snd_dma_buffer *dmab,
int direction)
struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
unsigned int size, struct snd_dma_buffer *dmab,
int direction)
{
struct hdac_ext_stream *hext_stream;
struct hdac_stream *hstream;
@ -97,22 +95,22 @@ static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsig
}
/*
* first boot sequence has some extra steps. core 0 waits for power
* status on core 1, so power up core 1 also momentarily, keep it in
* reset/stall and then turn it off
* first boot sequence has some extra steps.
* power on all host managed cores and only unstall/run the boot core to boot the
* DSP then turn off all non boot cores (if any) is powered on.
*/
static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
unsigned int status;
unsigned int status, target_status;
u32 flags, ipc_hdr, j;
unsigned long mask;
char *dump_msg;
u32 flags, j;
int ret;
/* step 1: power up corex */
ret = hda_dsp_enable_core(sdev, chip->host_managed_cores_mask);
ret = hda_dsp_core_power_up(sdev, chip->host_managed_cores_mask);
if (ret < 0) {
if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n");
@ -121,13 +119,15 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
hda_ssp_set_cbp_cfp(sdev);
/* step 2: purge FW request */
snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req,
chip->ipc_req_mask | (HDA_DSP_IPC_PURGE_FW |
((stream_tag - 1) << 9)));
/* step 2: Send ROM_CONTROL command (stream_tag is ignored for IMR boot) */
ipc_hdr = chip->ipc_req_mask | HDA_DSP_ROM_IPC_CONTROL;
if (!imr_boot)
ipc_hdr |= HDA_DSP_ROM_IPC_PURGE_FW | ((stream_tag - 1) << 9);
snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, ipc_hdr);
/* step 3: unset core 0 reset state & unstall/run core 0 */
ret = hda_dsp_core_run(sdev, BIT(0));
ret = hda_dsp_core_run(sdev, chip->init_core_mask);
if (ret < 0) {
if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
dev_err(sdev->dev,
@ -171,11 +171,20 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
/* step 6: enable IPC interrupts */
hda_dsp_ipc_int_enable(sdev);
/* step 7: wait for ROM init */
/*
* step 7:
* - Cold/Full boot: wait for ROM init to proceed to download the firmware
* - IMR boot: wait for ROM firmware entered (firmware booted up from IMR)
*/
if (imr_boot)
target_status = HDA_DSP_ROM_FW_ENTERED;
else
target_status = HDA_DSP_ROM_INIT;
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_STATUS, status,
chip->rom_status_reg, status,
((status & HDA_DSP_ROM_STS_MASK)
== HDA_DSP_ROM_INIT),
== target_status),
HDA_DSP_REG_POLL_INTERVAL_US,
chip->rom_init_timeout *
USEC_PER_MSEC);
@ -190,8 +199,8 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
dev_err(sdev->dev,
"error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n",
__func__);
"%s: timeout with rom_status_reg (%#x) read\n",
__func__, chip->rom_status_reg);
err:
flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL;
@ -236,8 +245,8 @@ static int cl_trigger(struct snd_sof_dev *sdev,
}
}
static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
struct hdac_ext_stream *hext_stream)
int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
struct hdac_ext_stream *hext_stream)
{
struct hdac_stream *hstream = &hext_stream->hstream;
int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
@ -268,8 +277,10 @@ static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
return ret;
}
static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream)
int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
unsigned int reg;
int ret, status;
@ -280,7 +291,7 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_str
}
status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_STATUS, reg,
chip->rom_status_reg, reg,
((reg & HDA_DSP_ROM_STS_MASK)
== HDA_DSP_ROM_FW_ENTERED),
HDA_DSP_REG_POLL_INTERVAL_US,
@ -293,8 +304,8 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_str
if (status < 0) {
dev_err(sdev->dev,
"error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n",
__func__);
"%s: timeout with rom_status_reg (%#x) read\n",
__func__, chip->rom_status_reg);
}
ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP);
@ -313,6 +324,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
struct hdac_ext_stream *iccmax_stream;
struct hdac_bus *bus = sof_to_bus(sdev);
struct firmware stripped_firmware;
struct snd_dma_buffer dmab_bdl;
int ret, ret1;
u8 original_gb;
@ -327,8 +339,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
/* prepare capture stream for ICCMAX */
iccmax_stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size,
&sdev->dmab_bdl, SNDRV_PCM_STREAM_CAPTURE);
iccmax_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size,
&dmab_bdl, SNDRV_PCM_STREAM_CAPTURE);
if (IS_ERR(iccmax_stream)) {
dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n");
return PTR_ERR(iccmax_stream);
@ -340,7 +352,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
* Perform iccmax stream cleanup. This should be done even if firmware loading fails.
* If the cleanup also fails, we return the initial error
*/
ret1 = cl_cleanup(sdev, &sdev->dmab_bdl, iccmax_stream);
ret1 = hda_cl_cleanup(sdev, &dmab_bdl, iccmax_stream);
if (ret1 < 0) {
dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n");
@ -357,32 +369,17 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
static int hda_dsp_boot_imr(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
unsigned long mask;
u32 j;
const struct sof_intel_dsp_desc *chip_info;
int ret;
/* power up & unstall/run the cores to run the firmware */
ret = hda_dsp_enable_core(sdev, chip->init_core_mask);
if (ret < 0) {
dev_err(sdev->dev, "dsp core start failed %d\n", ret);
return -EIO;
}
chip_info = get_chip_info(sdev->pdata);
if (chip_info->cl_init)
ret = chip_info->cl_init(sdev, 0, true);
else
ret = -EINVAL;
/* set enabled cores mask and increment ref count for cores in init_core_mask */
sdev->enabled_cores_mask |= chip->init_core_mask;
mask = sdev->enabled_cores_mask;
for_each_set_bit(j, &mask, SOF_MAX_DSP_NUM_CORES)
sdev->dsp_core_ref_count[j]++;
hda_ssp_set_cbp_cfp(sdev);
/* enable IPC interrupts */
hda_dsp_ipc_int_enable(sdev);
/* process wakes */
hda_sdw_process_wakeen(sdev);
if (!ret)
hda_sdw_process_wakeen(sdev);
return ret;
}
@ -395,13 +392,17 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
const struct sof_intel_dsp_desc *chip_info;
struct hdac_ext_stream *hext_stream;
struct firmware stripped_firmware;
struct snd_dma_buffer dmab;
int ret, ret1, i;
if ((sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT) &&
!(sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT)) &&
!sdev->first_boot) {
if (hda->imrboot_supported && !sdev->first_boot && !hda->skip_imr_boot) {
dev_dbg(sdev->dev, "IMR restore supported, booting from IMR directly\n");
return hda_dsp_boot_imr(sdev);
hda->boot_iteration = 0;
ret = hda_dsp_boot_imr(sdev);
if (!ret)
return 0;
dev_warn(sdev->dev, "IMR restore failed, trying to cold boot\n");
}
chip_info = desc->chip_info;
@ -418,14 +419,15 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
init_waitqueue_head(&sdev->boot_wait);
/* prepare DMA for code loader stream */
hext_stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size,
&sdev->dmab, SNDRV_PCM_STREAM_PLAYBACK);
hext_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT,
stripped_firmware.size,
&dmab, SNDRV_PCM_STREAM_PLAYBACK);
if (IS_ERR(hext_stream)) {
dev_err(sdev->dev, "error: dma prepare for fw loading failed\n");
return PTR_ERR(hext_stream);
}
memcpy(sdev->dmab.area, stripped_firmware.data,
memcpy(dmab.area, stripped_firmware.data,
stripped_firmware.size);
/* try ROM init a few times before giving up */
@ -434,7 +436,10 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
"Attempting iteration %d of Core En/ROM load...\n", i);
hda->boot_iteration = i + 1;
ret = cl_dsp_init(sdev, hext_stream->hstream.stream_tag);
if (chip_info->cl_init)
ret = chip_info->cl_init(sdev, hext_stream->hstream.stream_tag, false);
else
ret = -EINVAL;
/* don't retry anymore if successful */
if (!ret)
@ -473,12 +478,15 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
* Continue with code loading and firmware boot
*/
hda->boot_iteration = HDA_FW_BOOT_ATTEMPTS;
ret = cl_copy_fw(sdev, hext_stream);
if (!ret)
ret = hda_cl_copy_fw(sdev, hext_stream);
if (!ret) {
dev_dbg(sdev->dev, "Firmware download successful, booting...\n");
else
hda->skip_imr_boot = false;
} else {
snd_sof_dsp_dbg_dump(sdev, "Firmware download failed",
SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX);
hda->skip_imr_boot = true;
}
cleanup:
/*
@ -486,7 +494,7 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
* This should be done even if firmware loading fails.
* If the cleanup also fails, we return the initial error
*/
ret1 = cl_cleanup(sdev, &sdev->dmab, hext_stream);
ret1 = hda_cl_cleanup(sdev, &dmab, hext_stream);
if (ret1 < 0) {
dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n");
@ -522,12 +530,20 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev)
int ret;
if (sdev->first_boot) {
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
ret = hda_sdw_startup(sdev);
if (ret < 0) {
dev_err(sdev->dev,
"error: could not startup SoundWire links\n");
return ret;
}
/* Check if IMR boot is usable */
if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT) &&
(sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT ||
sdev->pdata->ipc_type == SOF_INTEL_IPC4))
hdev->imrboot_supported = true;
}
hda_sdw_int_enable(sdev, true);

View File

@ -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);

View File

@ -25,9 +25,9 @@ hda_compr_get_stream(struct snd_compr_stream *cstream)
return cstream->runtime->private_data;
}
static int hda_probes_compr_assign(struct sof_client_dev *cdev,
struct snd_compr_stream *cstream,
struct snd_soc_dai *dai, u32 *stream_id)
static int hda_probes_compr_startup(struct sof_client_dev *cdev,
struct snd_compr_stream *cstream,
struct snd_soc_dai *dai, u32 *stream_id)
{
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
struct hdac_ext_stream *hext_stream;
@ -45,9 +45,9 @@ static int hda_probes_compr_assign(struct sof_client_dev *cdev,
return 0;
}
static int hda_probes_compr_free(struct sof_client_dev *cdev,
struct snd_compr_stream *cstream,
struct snd_soc_dai *dai)
static int hda_probes_compr_shutdown(struct sof_client_dev *cdev,
struct snd_compr_stream *cstream,
struct snd_soc_dai *dai)
{
struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream);
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
@ -127,8 +127,8 @@ static int hda_probes_compr_pointer(struct sof_client_dev *cdev,
/* SOF client implementation */
static const struct sof_probes_host_ops hda_probes_ops = {
.assign = hda_probes_compr_assign,
.free = hda_probes_compr_free,
.startup = hda_probes_compr_startup,
.shutdown = hda_probes_compr_shutdown,
.set_params = hda_probes_compr_set_params,
.trigger = hda_probes_compr_trigger,
.pointer = hda_probes_compr_pointer,

View File

@ -116,13 +116,13 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
int remain, ioc;
period_bytes = hstream->period_bytes;
dev_dbg(sdev->dev, "%s: period_bytes:0x%x\n", __func__, period_bytes);
dev_dbg(sdev->dev, "period_bytes:0x%x\n", period_bytes);
if (!period_bytes)
period_bytes = hstream->bufsize;
periods = hstream->bufsize / period_bytes;
dev_dbg(sdev->dev, "%s: periods:%d\n", __func__, periods);
dev_dbg(sdev->dev, "periods:%d\n", periods);
remain = hstream->bufsize % period_bytes;
if (remain)
@ -271,7 +271,7 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag)
HDA_VS_INTEL_EM2_L1SEN, HDA_VS_INTEL_EM2_L1SEN);
if (!found) {
dev_dbg(sdev->dev, "%s: stream_tag %d not opened!\n",
dev_err(sdev->dev, "%s: stream_tag %d not opened!\n",
__func__, stream_tag);
return -ENODEV;
}
@ -411,6 +411,11 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
return -ENODEV;
}
if (!dmab) {
dev_err(sdev->dev, "error: no dma buffer allocated!\n");
return -ENODEV;
}
if (hstream->posbuf)
*hstream->posbuf = 0;
@ -485,16 +490,16 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
return -ENODEV;
}
/* decouple host and link DMA */
mask = 0x1 << hstream->index;
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
mask, mask);
if (!dmab) {
dev_err(sdev->dev, "error: no dma buffer allocated!\n");
return -ENODEV;
}
/* decouple host and link DMA */
mask = 0x1 << hstream->index;
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
mask, mask);
/* clear stream status */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
SOF_HDA_CL_DMA_SD_INT_MASK |
@ -707,12 +712,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 +754,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 +1014,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;
}

View File

@ -36,7 +36,7 @@ static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev, struct snd_dma_buffer
return ret;
}
int hda_dsp_trace_init(struct snd_sof_dev *sdev,
int hda_dsp_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
struct sof_ipc_dma_trace_params_ext *dtrace_params)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
@ -57,7 +57,7 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev,
* initialize capture stream, set BDL address and return corresponding
* stream tag which will be sent to the firmware by IPC message.
*/
ret = hda_dsp_trace_prepare(sdev, &sdev->dmatb);
ret = hda_dsp_trace_prepare(sdev, dmab);
if (ret < 0) {
dev_err(sdev->dev, "error: hdac trace init failed: %d\n", ret);
hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_CAPTURE,

View File

@ -147,7 +147,7 @@ static int sdw_free_stream(struct device *dev,
return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
}
static const struct sdw_intel_ops sdw_callback = {
struct sdw_intel_ops sdw_callback = {
.params_stream = sdw_params_stream,
.free_stream = sdw_free_stream,
};
@ -353,7 +353,7 @@ static inline bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
struct hda_dsp_msg_code {
u32 code;
const char *msg;
const char *text;
};
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG)
@ -382,10 +382,7 @@ module_param_named(use_common_hdmi, hda_codec_use_common_hdmi, bool, 0444);
MODULE_PARM_DESC(use_common_hdmi, "SOF HDA use common HDMI codec driver");
#endif
static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = {
{HDA_DSP_ROM_FW_MANIFEST_LOADED, "status: manifest loaded"},
{HDA_DSP_ROM_FW_FW_LOADED, "status: fw loaded"},
{HDA_DSP_ROM_FW_ENTERED, "status: fw entered"},
static const struct hda_dsp_msg_code hda_dsp_rom_fw_error_texts[] = {
{HDA_DSP_ROM_CSE_ERROR, "error: cse error"},
{HDA_DSP_ROM_CSE_WRONG_RESPONSE, "error: cse wrong response"},
{HDA_DSP_ROM_IMR_TO_SMALL, "error: IMR too small"},
@ -404,24 +401,136 @@ static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = {
{HDA_DSP_ROM_NULL_FW_ENTRY, "error: null FW entry point"},
};
static void hda_dsp_get_status(struct snd_sof_dev *sdev, const char *level)
#define FSR_ROM_STATE_ENTRY(state) {FSR_STATE_ROM_##state, #state}
static const struct hda_dsp_msg_code fsr_rom_state_names[] = {
FSR_ROM_STATE_ENTRY(INIT),
FSR_ROM_STATE_ENTRY(INIT_DONE),
FSR_ROM_STATE_ENTRY(CSE_MANIFEST_LOADED),
FSR_ROM_STATE_ENTRY(FW_MANIFEST_LOADED),
FSR_ROM_STATE_ENTRY(FW_FW_LOADED),
FSR_ROM_STATE_ENTRY(FW_ENTERED),
FSR_ROM_STATE_ENTRY(VERIFY_FEATURE_MASK),
FSR_ROM_STATE_ENTRY(GET_LOAD_OFFSET),
FSR_ROM_STATE_ENTRY(FETCH_ROM_EXT),
FSR_ROM_STATE_ENTRY(FETCH_ROM_EXT_DONE),
/* CSE states */
FSR_ROM_STATE_ENTRY(CSE_IMR_REQUEST),
FSR_ROM_STATE_ENTRY(CSE_IMR_GRANTED),
FSR_ROM_STATE_ENTRY(CSE_VALIDATE_IMAGE_REQUEST),
FSR_ROM_STATE_ENTRY(CSE_IMAGE_VALIDATED),
FSR_ROM_STATE_ENTRY(CSE_IPC_IFACE_INIT),
FSR_ROM_STATE_ENTRY(CSE_IPC_RESET_PHASE_1),
FSR_ROM_STATE_ENTRY(CSE_IPC_OPERATIONAL_ENTRY),
FSR_ROM_STATE_ENTRY(CSE_IPC_OPERATIONAL),
FSR_ROM_STATE_ENTRY(CSE_IPC_DOWN),
};
#define FSR_BRINGUP_STATE_ENTRY(state) {FSR_STATE_BRINGUP_##state, #state}
static const struct hda_dsp_msg_code fsr_bringup_state_names[] = {
FSR_BRINGUP_STATE_ENTRY(INIT),
FSR_BRINGUP_STATE_ENTRY(INIT_DONE),
FSR_BRINGUP_STATE_ENTRY(HPSRAM_LOAD),
FSR_BRINGUP_STATE_ENTRY(UNPACK_START),
FSR_BRINGUP_STATE_ENTRY(IMR_RESTORE),
FSR_BRINGUP_STATE_ENTRY(FW_ENTERED),
};
#define FSR_WAIT_STATE_ENTRY(state) {FSR_WAIT_FOR_##state, #state}
static const struct hda_dsp_msg_code fsr_wait_state_names[] = {
FSR_WAIT_STATE_ENTRY(IPC_BUSY),
FSR_WAIT_STATE_ENTRY(IPC_DONE),
FSR_WAIT_STATE_ENTRY(CACHE_INVALIDATION),
FSR_WAIT_STATE_ENTRY(LP_SRAM_OFF),
FSR_WAIT_STATE_ENTRY(DMA_BUFFER_FULL),
FSR_WAIT_STATE_ENTRY(CSE_CSR),
};
#define FSR_MODULE_NAME_ENTRY(mod) [FSR_MOD_##mod] = #mod
static const char * const fsr_module_names[] = {
FSR_MODULE_NAME_ENTRY(ROM),
FSR_MODULE_NAME_ENTRY(ROM_BYP),
FSR_MODULE_NAME_ENTRY(BASE_FW),
FSR_MODULE_NAME_ENTRY(LP_BOOT),
FSR_MODULE_NAME_ENTRY(BRNGUP),
FSR_MODULE_NAME_ENTRY(ROM_EXT),
};
static const char *
hda_dsp_get_state_text(u32 code, const struct hda_dsp_msg_code *msg_code,
size_t array_size)
{
u32 status;
int i;
status = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_STATUS);
for (i = 0; i < ARRAY_SIZE(hda_dsp_rom_msg); i++) {
if (status == hda_dsp_rom_msg[i].code) {
dev_printk(level, sdev->dev, "%s - code %8.8x\n",
hda_dsp_rom_msg[i].msg, status);
return;
}
for (i = 0; i < array_size; i++) {
if (code == msg_code[i].code)
return msg_code[i].text;
}
return NULL;
}
static void hda_dsp_get_state(struct snd_sof_dev *sdev, const char *level)
{
const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);
const char *state_text, *error_text, *module_text;
u32 fsr, state, wait_state, module, error_code;
fsr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg);
state = FSR_TO_STATE_CODE(fsr);
wait_state = FSR_TO_WAIT_STATE_CODE(fsr);
module = FSR_TO_MODULE_CODE(fsr);
if (module > FSR_MOD_ROM_EXT)
module_text = "unknown";
else
module_text = fsr_module_names[module];
if (module == FSR_MOD_BRNGUP)
state_text = hda_dsp_get_state_text(state, fsr_bringup_state_names,
ARRAY_SIZE(fsr_bringup_state_names));
else
state_text = hda_dsp_get_state_text(state, fsr_rom_state_names,
ARRAY_SIZE(fsr_rom_state_names));
/* not for us, must be generic sof message */
dev_dbg(sdev->dev, "unknown ROM status value %8.8x\n", status);
if (!state_text) {
dev_printk(level, sdev->dev, "%#010x: unknown ROM status value\n", fsr);
return;
}
if (wait_state) {
const char *wait_state_text;
wait_state_text = hda_dsp_get_state_text(wait_state, fsr_wait_state_names,
ARRAY_SIZE(fsr_wait_state_names));
if (!wait_state_text)
wait_state_text = "unknown";
dev_printk(level, sdev->dev,
"%#010x: module: %s, state: %s, waiting for: %s, %s\n",
fsr, module_text, state_text, wait_state_text,
fsr & FSR_HALTED ? "not running" : "running");
} else {
dev_printk(level, sdev->dev, "%#010x: module: %s, state: %s, %s\n",
fsr, module_text, state_text,
fsr & FSR_HALTED ? "not running" : "running");
}
error_code = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg + 4);
if (!error_code)
return;
error_text = hda_dsp_get_state_text(error_code, hda_dsp_rom_fw_error_texts,
ARRAY_SIZE(hda_dsp_rom_fw_error_texts));
if (!error_text)
error_text = "unknown";
if (state == FSR_STATE_FW_ENTERED)
dev_printk(level, sdev->dev, "status code: %#x (%s)\n", error_code,
error_text);
else
dev_printk(level, sdev->dev, "error code: %#x (%s)\n", error_code,
error_text);
}
static void hda_dsp_get_registers(struct snd_sof_dev *sdev,
@ -456,14 +565,16 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev,
static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, const char *level,
u32 flags)
{
const struct sof_intel_dsp_desc *chip;
char msg[128];
int len = 0;
u32 value;
int i;
chip = get_chip_info(sdev->pdata);
for (i = 0; i < HDA_EXT_ROM_STATUS_SIZE; i++) {
value = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_STATUS + i * 0x4);
len += snprintf(msg + len, sizeof(msg) - len, " 0x%x", value);
value = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg + i * 0x4);
len += scnprintf(msg + len, sizeof(msg) - len, " 0x%x", value);
}
dev_printk(level, sdev->dev, "extended rom status: %s", msg);
@ -478,7 +589,7 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
u32 stack[HDA_DSP_STACK_DUMP_SIZE];
/* print ROM/FW status */
hda_dsp_get_status(sdev, level);
hda_dsp_get_state(sdev, level);
if (flags & SOF_DBG_DUMP_REGS) {
u32 status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_STATUS);
@ -493,6 +604,17 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
}
}
static bool hda_check_ipc_irq(struct snd_sof_dev *sdev)
{
const struct sof_intel_dsp_desc *chip;
chip = get_chip_info(sdev->pdata);
if (chip && chip->check_ipc_irq)
return chip->check_ipc_irq(sdev);
return false;
}
void hda_ipc_irq_dump(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
@ -584,14 +706,13 @@ static int hda_init(struct snd_sof_dev *sdev)
static int check_dmic_num(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct nhlt_acpi_table *nhlt;
int dmic_num = 0;
nhlt = intel_nhlt_init(sdev->dev);
if (nhlt) {
nhlt = hdev->nhlt;
if (nhlt)
dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt);
intel_nhlt_free(nhlt);
}
/* allow for module parameter override */
if (dmic_num_override != -1) {
@ -611,10 +732,11 @@ static int check_dmic_num(struct snd_sof_dev *sdev)
static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct nhlt_acpi_table *nhlt;
int ssp_mask = 0;
nhlt = intel_nhlt_init(sdev->dev);
nhlt = hdev->nhlt;
if (!nhlt)
return ssp_mask;
@ -623,7 +745,6 @@ static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev)
if (ssp_mask)
dev_info(sdev->dev, "NHLT_DEVICE_I2S detected, ssp_mask %#x\n", ssp_mask);
}
intel_nhlt_free(nhlt);
return ssp_mask;
}
@ -655,13 +776,12 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
return tplg_filename;
}
static int dmic_topology_fixup(struct snd_sof_dev *sdev,
const char **tplg_filename,
const char *idisp_str,
int *dmic_found)
static int dmic_detect_topology_fixup(struct snd_sof_dev *sdev,
const char **tplg_filename,
const char *idisp_str,
int *dmic_found,
bool tplg_fixup)
{
const char *default_tplg_filename = *tplg_filename;
const char *fixed_tplg_filename;
const char *dmic_str;
int dmic_num;
@ -687,14 +807,19 @@ static int dmic_topology_fixup(struct snd_sof_dev *sdev,
break;
}
fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
idisp_str, dmic_str);
if (!fixed_tplg_filename)
return -ENOMEM;
if (tplg_fixup) {
const char *default_tplg_filename = *tplg_filename;
const char *fixed_tplg_filename;
fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
idisp_str, dmic_str);
if (!fixed_tplg_filename)
return -ENOMEM;
*tplg_filename = fixed_tplg_filename;
}
dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num);
*dmic_found = dmic_num;
*tplg_filename = fixed_tplg_filename;
return 0;
}
@ -816,7 +941,7 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context)
if (hda_dsp_check_stream_irq(sdev))
hda_dsp_stream_threaded_handler(irq, sdev);
if (hda_dsp_check_ipc_irq(sdev))
if (hda_check_ipc_irq(sdev))
sof_ops(sdev)->irq_thread(irq, sdev);
if (hda_dsp_check_sdw_irq(sdev))
@ -984,6 +1109,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
INIT_DELAYED_WORK(&hdev->d0i3_work, hda_dsp_d0i3_work);
hdev->nhlt = intel_nhlt_init(sdev->dev);
return 0;
free_ipc_irq:
@ -1009,6 +1136,10 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
const struct sof_intel_dsp_desc *chip = hda->desc;
struct hdac_bus *bus = sof_to_bus(sdev);
struct pci_dev *pci = to_pci_dev(sdev->dev);
struct nhlt_acpi_table *nhlt = hda->nhlt;
if (nhlt)
intel_nhlt_free(nhlt);
/* cancel any attempt for DSP D0I3 */
cancel_delayed_work_sync(&hda->d0i3_work);
@ -1094,6 +1225,8 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
* - one external HDAudio codec
*/
if (!*mach && codec_num <= 2) {
bool tplg_fixup;
hda_mach = snd_soc_acpi_intel_hda_machines;
dev_info(bus->dev, "using HDA machine driver %s now\n",
@ -1105,8 +1238,15 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
idisp_str = "";
/* topology: use the info from hda_machines */
tplg_filename = hda_mach->sof_tplg_filename;
ret = dmic_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num);
if (pdata->tplg_filename) {
tplg_fixup = false;
tplg_filename = pdata->tplg_filename;
} else {
tplg_fixup = true;
tplg_filename = hda_mach->sof_tplg_filename;
}
ret = dmic_detect_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num,
tplg_fixup);
if (ret < 0)
return;
@ -1270,30 +1410,37 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
}
if (mach && mach->link_mask) {
int dmic_num = 0;
bool tplg_fixup;
const char *tplg_filename;
mach->mach_params.links = mach->links;
mach->mach_params.link_mask = mach->link_mask;
mach->mach_params.platform = dev_name(sdev->dev);
pdata->fw_filename = pdata->desc->default_fw_filename;
pdata->tplg_filename = mach->sof_tplg_filename;
if (pdata->tplg_filename) {
tplg_fixup = false;
} else {
tplg_fixup = true;
tplg_filename = mach->sof_tplg_filename;
}
/*
* DMICs use up to 4 pins and are typically pin-muxed with SoundWire
* link 2 and 3, thus we only try to enable dmics if all conditions
* are true:
* a) link 2 and 3 are not used by SoundWire
* link 2 and 3, or link 1 and 2, thus we only try to enable dmics
* if all conditions are true:
* a) 2 or fewer links are used by SoundWire
* b) the NHLT table reports the presence of microphones
*/
if (!(mach->link_mask & GENMASK(3, 2))) {
const char *tplg_filename = mach->sof_tplg_filename;
if (hweight_long(mach->link_mask) <= 2) {
int ret;
ret = dmic_topology_fixup(sdev, &tplg_filename, "", &dmic_num);
ret = dmic_detect_topology_fixup(sdev, &tplg_filename, "",
&dmic_num, tplg_fixup);
if (ret < 0)
return NULL;
pdata->tplg_filename = tplg_filename;
}
if (tplg_fixup)
pdata->tplg_filename = tplg_filename;
mach->mach_params.dmic_num = dmic_num;
dev_dbg(sdev->dev,
@ -1339,18 +1486,22 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
mach = snd_soc_acpi_find_machine(desc->machines);
if (mach) {
bool add_extension = false;
bool tplg_fixup = false;
/*
* If tplg file name is overridden, use it instead of
* the one set in mach table
*/
if (!sof_pdata->tplg_filename)
if (!sof_pdata->tplg_filename) {
sof_pdata->tplg_filename = mach->sof_tplg_filename;
tplg_fixup = true;
}
/* report to machine driver if any DMICs are found */
mach->mach_params.dmic_num = check_dmic_num(sdev);
if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER &&
if (tplg_fixup &&
mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER &&
mach->mach_params.dmic_num) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s%d%s",
@ -1373,8 +1524,10 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
/* report SSP link mask to machine driver */
mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev);
if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER &&
if (tplg_fixup &&
mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER &&
mach->mach_params.i2s_link_mask) {
const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);
int ssp_num;
if (hweight_long(mach->mach_params.i2s_link_mask) > 1 &&
@ -1384,6 +1537,12 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
/* fls returns 1-based results, SSPs indices are 0-based */
ssp_num = fls(mach->mach_params.i2s_link_mask) - 1;
if (ssp_num >= chip->ssp_count) {
dev_err(sdev->dev, "Invalid SSP %d, max on this platform is %d\n",
ssp_num, chip->ssp_count);
return NULL;
}
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s%d",
sof_pdata->tplg_filename,
@ -1396,7 +1555,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
add_extension = true;
}
if (add_extension) {
if (tplg_fixup && add_extension) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s",
sof_pdata->tplg_filename,

View File

@ -187,6 +187,69 @@
#define HDA_DSP_STACK_DUMP_SIZE 32
/* ROM/FW status register */
#define FSR_STATE_MASK GENMASK(23, 0)
#define FSR_WAIT_STATE_MASK GENMASK(27, 24)
#define FSR_MODULE_MASK GENMASK(30, 28)
#define FSR_HALTED BIT(31)
#define FSR_TO_STATE_CODE(x) ((x) & FSR_STATE_MASK)
#define FSR_TO_WAIT_STATE_CODE(x) (((x) & FSR_WAIT_STATE_MASK) >> 24)
#define FSR_TO_MODULE_CODE(x) (((x) & FSR_MODULE_MASK) >> 28)
/* Wait states */
#define FSR_WAIT_FOR_IPC_BUSY 0x1
#define FSR_WAIT_FOR_IPC_DONE 0x2
#define FSR_WAIT_FOR_CACHE_INVALIDATION 0x3
#define FSR_WAIT_FOR_LP_SRAM_OFF 0x4
#define FSR_WAIT_FOR_DMA_BUFFER_FULL 0x5
#define FSR_WAIT_FOR_CSE_CSR 0x6
/* Module codes */
#define FSR_MOD_ROM 0x0
#define FSR_MOD_ROM_BYP 0x1
#define FSR_MOD_BASE_FW 0x2
#define FSR_MOD_LP_BOOT 0x3
#define FSR_MOD_BRNGUP 0x4
#define FSR_MOD_ROM_EXT 0x5
/* State codes (module dependent) */
/* Module independent states */
#define FSR_STATE_INIT 0x0
#define FSR_STATE_INIT_DONE 0x1
#define FSR_STATE_FW_ENTERED 0x5
/* ROM states */
#define FSR_STATE_ROM_INIT FSR_STATE_INIT
#define FSR_STATE_ROM_INIT_DONE FSR_STATE_INIT_DONE
#define FSR_STATE_ROM_CSE_MANIFEST_LOADED 0x2
#define FSR_STATE_ROM_FW_MANIFEST_LOADED 0x3
#define FSR_STATE_ROM_FW_FW_LOADED 0x4
#define FSR_STATE_ROM_FW_ENTERED FSR_STATE_FW_ENTERED
#define FSR_STATE_ROM_VERIFY_FEATURE_MASK 0x6
#define FSR_STATE_ROM_GET_LOAD_OFFSET 0x7
#define FSR_STATE_ROM_FETCH_ROM_EXT 0x8
#define FSR_STATE_ROM_FETCH_ROM_EXT_DONE 0x9
/* (ROM) CSE states */
#define FSR_STATE_ROM_CSE_IMR_REQUEST 0x10
#define FSR_STATE_ROM_CSE_IMR_GRANTED 0x11
#define FSR_STATE_ROM_CSE_VALIDATE_IMAGE_REQUEST 0x12
#define FSR_STATE_ROM_CSE_IMAGE_VALIDATED 0x13
#define FSR_STATE_ROM_CSE_IPC_IFACE_INIT 0x20
#define FSR_STATE_ROM_CSE_IPC_RESET_PHASE_1 0x21
#define FSR_STATE_ROM_CSE_IPC_OPERATIONAL_ENTRY 0x22
#define FSR_STATE_ROM_CSE_IPC_OPERATIONAL 0x23
#define FSR_STATE_ROM_CSE_IPC_DOWN 0x24
/* BRINGUP (or BRNGUP) states */
#define FSR_STATE_BRINGUP_INIT FSR_STATE_INIT
#define FSR_STATE_BRINGUP_INIT_DONE FSR_STATE_INIT_DONE
#define FSR_STATE_BRINGUP_HPSRAM_LOAD 0x2
#define FSR_STATE_BRINGUP_UNPACK_START 0X3
#define FSR_STATE_BRINGUP_IMR_RESTORE 0x4
#define FSR_STATE_BRINGUP_FW_ENTERED FSR_STATE_FW_ENTERED
/* ROM status/error values */
#define HDA_DSP_ROM_STS_MASK GENMASK(23, 0)
#define HDA_DSP_ROM_INIT 0x1
@ -210,7 +273,9 @@
#define HDA_DSP_ROM_USER_EXCEPTION 0xBEEF0000
#define HDA_DSP_ROM_UNEXPECTED_RESET 0xDECAF000
#define HDA_DSP_ROM_NULL_FW_ENTRY 0x4c4c4e55
#define HDA_DSP_IPC_PURGE_FW 0x01004000
#define HDA_DSP_ROM_IPC_CONTROL 0x01000000
#define HDA_DSP_ROM_IPC_PURGE_FW 0x00004000
/* various timeout values */
#define HDA_DSP_PU_TIMEOUT 50
@ -223,8 +288,8 @@
#define HDA_DSP_REG_POLL_INTERVAL_US 500 /* 0.5 msec */
#define HDA_DSP_REG_POLL_RETRY_COUNT 50
#define HDA_DSP_ADSPIC_IPC 1
#define HDA_DSP_ADSPIS_IPC 1
#define HDA_DSP_ADSPIC_IPC BIT(0)
#define HDA_DSP_ADSPIS_IPC BIT(0)
/* Intel HD Audio General DSP Registers */
#define HDA_DSP_GEN_BASE 0x0
@ -268,8 +333,8 @@
/* HIPCTE */
#define HDA_DSP_REG_HIPCTE_MSG_MASK 0x3FFFFFFF
#define HDA_DSP_ADSPIC_CL_DMA 0x2
#define HDA_DSP_ADSPIS_CL_DMA 0x2
#define HDA_DSP_ADSPIC_CL_DMA BIT(1)
#define HDA_DSP_ADSPIS_CL_DMA BIT(1)
/* Delay before scheduling D0i3 entry */
#define BXT_D0I3_DELAY 5000
@ -416,6 +481,9 @@ enum sof_hda_D0_substate {
/* represents DSP HDA controller frontend - i.e. host facing control */
struct sof_intel_hda_dev {
bool imrboot_supported;
bool skip_imr_boot;
int boot_iteration;
struct hda_bus hbus;
@ -449,6 +517,9 @@ struct sof_intel_hda_dev {
/* FW clock config, 0:HPRO, 1:LPRO */
bool clk_config_lpro;
/* Intel NHLT information */
struct nhlt_acpi_table *nhlt;
};
static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s)
@ -490,6 +561,7 @@ struct sof_intel_hda_stream {
*/
int hda_dsp_probe(struct snd_sof_dev *sdev);
int hda_dsp_remove(struct snd_sof_dev *sdev);
int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask);
int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask);
int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask);
int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev,
@ -557,6 +629,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);
@ -588,6 +663,14 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir);
*/
int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev);
int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev);
int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream);
struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
unsigned int size, struct snd_dma_buffer *dmab,
int direction);
int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
struct hdac_ext_stream *hext_stream);
int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
#define HDA_CL_STREAM_FORMAT 0x40
/* pre and post fw run ops */
int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev);
@ -644,7 +727,7 @@ static inline int hda_codec_i915_exit(struct snd_sof_dev *sdev) { return 0; }
/*
* Trace Control.
*/
int hda_dsp_trace_init(struct snd_sof_dev *sdev,
int hda_dsp_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
struct sof_ipc_dma_trace_params_ext *dtrace_params);
int hda_dsp_trace_release(struct snd_sof_dev *sdev);
int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd);
@ -683,24 +766,33 @@ static inline bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev)
/* common dai driver */
extern struct snd_soc_dai_driver skl_dai[];
int hda_dsp_dais_suspend(struct snd_sof_dev *sdev);
/*
* Platform Specific HW abstraction Ops.
*/
extern const struct snd_sof_dsp_ops sof_apl_ops;
extern const struct snd_sof_dsp_ops sof_cnl_ops;
extern const struct snd_sof_dsp_ops sof_tgl_ops;
extern const struct snd_sof_dsp_ops sof_icl_ops;
extern struct snd_sof_dsp_ops sof_hda_common_ops;
extern struct snd_sof_dsp_ops sof_apl_ops;
int sof_apl_ops_init(struct snd_sof_dev *sdev);
extern struct snd_sof_dsp_ops sof_cnl_ops;
int sof_cnl_ops_init(struct snd_sof_dev *sdev);
extern struct snd_sof_dsp_ops sof_tgl_ops;
int sof_tgl_ops_init(struct snd_sof_dev *sdev);
extern struct snd_sof_dsp_ops sof_icl_ops;
int sof_icl_ops_init(struct snd_sof_dev *sdev);
extern struct snd_sof_dsp_ops sof_mtl_ops;
int sof_mtl_ops_init(struct snd_sof_dev *sdev);
extern const struct sof_intel_dsp_desc apl_chip_info;
extern const struct sof_intel_dsp_desc cnl_chip_info;
extern const struct sof_intel_dsp_desc skl_chip_info;
extern const struct sof_intel_dsp_desc icl_chip_info;
extern const struct sof_intel_dsp_desc tgl_chip_info;
extern const struct sof_intel_dsp_desc tglh_chip_info;
extern const struct sof_intel_dsp_desc ehl_chip_info;
extern const struct sof_intel_dsp_desc jsl_chip_info;
extern const struct sof_intel_dsp_desc adls_chip_info;
extern const struct sof_intel_dsp_desc mtl_chip_info;
/* Probes support */
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
@ -742,4 +834,14 @@ int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w, unsigned int quirk_f
extern int sof_hda_position_quirk;
void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops);
void hda_ops_free(struct snd_sof_dev *sdev);
/* IPC4 */
irqreturn_t cnl_ipc4_irq_thread(int irq, void *context);
int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context);
int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
extern struct sdw_intel_ops sdw_callback;
#endif

View File

@ -56,11 +56,18 @@ static int icl_dsp_post_fw_run(struct snd_sof_dev *sdev)
int ret;
if (sdev->first_boot) {
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
ret = hda_sdw_startup(sdev);
if (ret < 0) {
dev_err(sdev->dev, "error: could not startup SoundWire links\n");
return ret;
}
/* Check if IMR boot is usable */
if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT) &&
sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT)
hdev->imrboot_supported = true;
}
hda_sdw_int_enable(sdev, true);
@ -88,109 +95,44 @@ static int icl_dsp_post_fw_run(struct snd_sof_dev *sdev)
}
/* Icelake ops */
const struct snd_sof_dsp_ops sof_icl_ops = {
struct snd_sof_dsp_ops sof_icl_ops;
EXPORT_SYMBOL_NS(sof_icl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
int sof_icl_ops_init(struct snd_sof_dev *sdev)
{
/* common defaults */
memcpy(&sof_icl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
/* probe/remove/shutdown */
.probe = hda_dsp_probe,
.remove = hda_dsp_remove,
.shutdown = hda_dsp_shutdown,
/* Register IO */
.write = sof_io_write,
.read = sof_io_read,
.write64 = sof_io_write64,
.read64 = sof_io_read64,
/* Block IO */
.block_read = sof_block_read,
.block_write = sof_block_write,
/* Mailbox IO */
.mailbox_read = sof_mailbox_read,
.mailbox_write = sof_mailbox_write,
sof_icl_ops.shutdown = hda_dsp_shutdown;
/* doorbell */
.irq_thread = cnl_ipc_irq_thread,
sof_icl_ops.irq_thread = cnl_ipc_irq_thread;
/* ipc */
.send_msg = cnl_ipc_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset,
.get_window_offset = hda_dsp_ipc_get_window_offset,
.ipc_msg_data = hda_ipc_msg_data,
.set_stream_data_offset = hda_set_stream_data_offset,
/* machine driver */
.machine_select = hda_machine_select,
.machine_register = sof_machine_register,
.machine_unregister = sof_machine_unregister,
.set_mach_params = hda_set_mach_params,
sof_icl_ops.send_msg = cnl_ipc_send_msg;
/* debug */
.debug_map = icl_dsp_debugfs,
.debug_map_count = ARRAY_SIZE(icl_dsp_debugfs),
.dbg_dump = hda_dsp_dump,
.ipc_dump = cnl_ipc_dump,
.debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
/* stream callbacks */
.pcm_open = hda_dsp_pcm_open,
.pcm_close = hda_dsp_pcm_close,
.pcm_hw_params = hda_dsp_pcm_hw_params,
.pcm_hw_free = hda_dsp_stream_hw_free,
.pcm_trigger = hda_dsp_pcm_trigger,
.pcm_pointer = hda_dsp_pcm_pointer,
.pcm_ack = hda_dsp_pcm_ack,
/* firmware loading */
.load_firmware = snd_sof_load_firmware_raw,
sof_icl_ops.debug_map = icl_dsp_debugfs;
sof_icl_ops.debug_map_count = ARRAY_SIZE(icl_dsp_debugfs);
sof_icl_ops.ipc_dump = cnl_ipc_dump;
/* pre/post fw run */
.pre_fw_run = hda_dsp_pre_fw_run,
.post_fw_run = icl_dsp_post_fw_run,
/* parse platform specific extended manifest */
.parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
/* dsp core get/put */
.core_get = hda_dsp_core_get,
sof_icl_ops.post_fw_run = icl_dsp_post_fw_run;
/* firmware run */
.run = hda_dsp_cl_boot_firmware_iccmax,
.stall = icl_dsp_core_stall,
sof_icl_ops.run = hda_dsp_cl_boot_firmware_iccmax;
sof_icl_ops.stall = icl_dsp_core_stall;
/* trace callback */
.trace_init = hda_dsp_trace_init,
.trace_release = hda_dsp_trace_release,
.trace_trigger = hda_dsp_trace_trigger,
/* dsp core get/put */
sof_icl_ops.core_get = hda_dsp_core_get;
/* client ops */
.register_ipc_clients = hda_register_clients,
.unregister_ipc_clients = hda_unregister_clients,
/* set DAI driver ops */
hda_set_dai_drv_ops(sdev, &sof_icl_ops);
/* DAI drivers */
.drv = skl_dai,
.num_drv = SOF_SKL_NUM_DAIS,
/* PM */
.suspend = hda_dsp_suspend,
.resume = hda_dsp_resume,
.runtime_suspend = hda_dsp_runtime_suspend,
.runtime_resume = hda_dsp_runtime_resume,
.runtime_idle = hda_dsp_runtime_idle,
.set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume,
.set_power_state = hda_dsp_set_power_state,
/* ALSA HW info flags */
.hw_info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
.dsp_arch_ops = &sof_xtensa_arch_ops,
return 0;
};
EXPORT_SYMBOL_NS(sof_icl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
EXPORT_SYMBOL_NS(sof_icl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc icl_chip_info = {
/* Icelake */
@ -202,11 +144,15 @@ const struct sof_intel_dsp_desc icl_chip_info = {
.ipc_ack = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.hw_ip_version = SOF_INTEL_CAVS_2_0,
};
EXPORT_SYMBOL_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);

View File

@ -27,11 +27,24 @@ static const struct sof_dev_desc bxt_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &apl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-apl.ri",
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/apl",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-apl.ri",
[SOF_INTEL_IPC4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-apl-nocodec.tplg",
.ops = &sof_apl_ops,
.ops_init = sof_apl_ops_init,
.ops_free = hda_ops_free,
};
static const struct sof_dev_desc glk_desc = {
@ -42,11 +55,23 @@ static const struct sof_dev_desc glk_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &apl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-glk.ri",
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/glk",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-glk.ri",
[SOF_INTEL_IPC4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-glk-nocodec.tplg",
.ops = &sof_apl_ops,
.ops_init = sof_apl_ops_init,
};
/* PCI IDs */

View File

@ -28,11 +28,23 @@ static const struct sof_dev_desc cnl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &cnl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-cnl.ri",
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/cnl",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-cnl.ri",
[SOF_INTEL_IPC4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
.ops = &sof_cnl_ops,
.ops_init = sof_cnl_ops_init,
};
static const struct sof_dev_desc cfl_desc = {
@ -44,11 +56,24 @@ static const struct sof_dev_desc cfl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &cnl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-cfl.ri",
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/cnl",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-cfl.ri",
[SOF_INTEL_IPC4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
.ops = &sof_cnl_ops,
.ops_init = sof_cnl_ops_init,
.ops_free = hda_ops_free,
};
static const struct sof_dev_desc cml_desc = {
@ -60,11 +85,23 @@ static const struct sof_dev_desc cml_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &cnl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-cml.ri",
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/cnl",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-cml.ri",
[SOF_INTEL_IPC4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-cnl-nocodec.tplg",
.ops = &sof_cnl_ops,
.ops_init = sof_cnl_ops_init,
};
/* PCI IDs */

View File

@ -28,11 +28,24 @@ static const struct sof_dev_desc icl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &icl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-icl.ri",
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/icl",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-icl.ri",
[SOF_INTEL_IPC4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-icl-nocodec.tplg",
.ops = &sof_icl_ops,
.ops_init = sof_icl_ops_init,
.ops_free = hda_ops_free,
};
static const struct sof_dev_desc jsl_desc = {
@ -43,11 +56,23 @@ static const struct sof_dev_desc jsl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &jsl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-jsl.ri",
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/jsl",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-jsl.ri",
[SOF_INTEL_IPC4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-jsl-nocodec.tplg",
.ops = &sof_cnl_ops,
.ops_init = sof_cnl_ops_init,
};
/* PCI IDs */

View File

@ -28,11 +28,23 @@ static const struct sof_dev_desc tgl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &tgl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-tgl.ri",
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/tgl",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-tgl.ri",
[SOF_INTEL_IPC4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
.ops = &sof_tgl_ops,
.ops_init = sof_tgl_ops_init,
};
static const struct sof_dev_desc tglh_desc = {
@ -44,11 +56,24 @@ static const struct sof_dev_desc tglh_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &tglh_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-tgl-h.ri",
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/tgl-h",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-tgl-h.ri",
[SOF_INTEL_IPC4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
.ops = &sof_tgl_ops,
.ops_init = sof_tgl_ops_init,
.ops_free = hda_ops_free,
};
static const struct sof_dev_desc ehl_desc = {
@ -59,11 +84,23 @@ static const struct sof_dev_desc ehl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &ehl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-ehl.ri",
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/ehl",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-ehl.ri",
[SOF_INTEL_IPC4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-ehl-nocodec.tplg",
.ops = &sof_tgl_ops,
.ops_init = sof_tgl_ops_init,
};
static const struct sof_dev_desc adls_desc = {
@ -75,11 +112,23 @@ static const struct sof_dev_desc adls_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &adls_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-adl-s.ri",
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/adl-s",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-adl-s.ri",
[SOF_INTEL_IPC4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-adl-nocodec.tplg",
.ops = &sof_tgl_ops,
.ops_init = sof_tgl_ops_init,
};
static const struct sof_dev_desc adl_desc = {
@ -91,11 +140,23 @@ static const struct sof_dev_desc adl_desc = {
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &tgl_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-adl.ri",
.ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
[SOF_INTEL_IPC4] = "intel/avs/adl",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
[SOF_INTEL_IPC4] = "intel/avs-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-adl.ri",
[SOF_INTEL_IPC4] = "dsp_basefw.bin",
},
.nocodec_tplg_filename = "sof-adl-nocodec.tplg",
.ops = &sof_tgl_ops,
.ops_init = sof_tgl_ops_init,
};
/* PCI IDs */
@ -116,6 +177,12 @@ static const struct pci_device_id sof_pci_ids[] = {
.driver_data = (unsigned long)&adl_desc},
{ PCI_DEVICE(0x8086, 0x51cd), /* ADL-P */
.driver_data = (unsigned long)&adl_desc},
{ PCI_DEVICE(0x8086, 0x51c9), /* ADL-PS */
.driver_data = (unsigned long)&adl_desc},
{ PCI_DEVICE(0x8086, 0x51ca), /* RPL-P */
.driver_data = (unsigned long)&adl_desc},
{ PCI_DEVICE(0x8086, 0x51cb), /* RPL-P */
.driver_data = (unsigned long)&adl_desc},
{ PCI_DEVICE(0x8086, 0x51cc), /* ADL-M */
.driver_data = (unsigned long)&adl_desc},
{ PCI_DEVICE(0x8086, 0x54c8), /* ADL-N */
@ -140,4 +207,3 @@ module_pci_driver(snd_sof_pci_intel_tgl_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);

View File

@ -75,7 +75,11 @@ static int tangier_pci_probe(struct snd_sof_dev *sdev)
/* LPE base */
base = pci_resource_start(pci, desc->resindex_lpe_base) - IRAM_OFFSET;
size = PCI_BAR_SIZE;
size = pci_resource_len(pci, desc->resindex_lpe_base);
if (size < PCI_BAR_SIZE) {
dev_err(sdev->dev, "error: I/O region is too small.\n");
return -ENODEV;
}
dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size);
sdev->bar[DSP_BAR] = devm_ioremap(sdev->dev, base, size);
@ -132,7 +136,7 @@ static int tangier_pci_probe(struct snd_sof_dev *sdev)
return ret;
}
const struct snd_sof_dsp_ops sof_tng_ops = {
struct snd_sof_dsp_ops sof_tng_ops = {
/* device init */
.probe = tangier_pci_probe,
@ -160,7 +164,6 @@ const struct snd_sof_dsp_ops sof_tng_ops = {
/* ipc */
.send_msg = atom_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = atom_get_mailbox_offset,
.get_window_offset = atom_get_window_offset,
@ -183,9 +186,6 @@ const struct snd_sof_dsp_ops sof_tng_ops = {
.pcm_open = sof_stream_pcm_open,
.pcm_close = sof_stream_pcm_close,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
@ -206,6 +206,7 @@ const struct snd_sof_dsp_ops sof_tng_ops = {
const struct sof_intel_dsp_desc tng_chip_info = {
.cores_num = 1,
.host_managed_cores_mask = 1,
.hw_ip_version = SOF_INTEL_TANGIER,
};
static const struct sof_dev_desc tng_desc = {
@ -215,9 +216,17 @@ static const struct sof_dev_desc tng_desc = {
.resindex_imr_base = 0,
.irqindex_host_ipc = -1,
.chip_info = &tng_chip_info,
.default_fw_path = "intel/sof",
.default_tplg_path = "intel/sof-tplg",
.default_fw_filename = "sof-byt.ri",
.ipc_supported_mask = BIT(SOF_IPC),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "intel/sof",
},
.default_tplg_path = {
[SOF_IPC] = "intel/sof-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-byt.ri",
},
.nocodec_tplg_filename = "sof-byt.tplg",
.ops = &sof_tng_ops,
};

View File

@ -11,6 +11,18 @@
#ifndef __SOF_INTEL_SHIM_H
#define __SOF_INTEL_SHIM_H
enum sof_intel_hw_ip_version {
SOF_INTEL_TANGIER,
SOF_INTEL_BAYTRAIL,
SOF_INTEL_BROADWELL,
SOF_INTEL_CAVS_1_5, /* SkyLake, KabyLake, AmberLake */
SOF_INTEL_CAVS_1_5_PLUS,/* ApolloLake, GeminiLake */
SOF_INTEL_CAVS_1_8, /* CannonLake, CometLake, CoffeeLake */
SOF_INTEL_CAVS_2_0, /* IceLake, JasperLake */
SOF_INTEL_CAVS_2_5, /* TigerLake, AlderLake */
SOF_INTEL_ACE_1_0, /* MeteorLake */
};
/*
* SHIM registers for BYT, BSW, CHT, BDW
*/
@ -164,16 +176,20 @@ struct sof_intel_dsp_desc {
int ipc_ack;
int ipc_ack_mask;
int ipc_ctl;
int rom_status_reg;
int rom_init_timeout;
int ssp_count; /* ssp count of the platform */
int ssp_base_offset; /* base address of the SSPs */
u32 sdw_shim_base;
u32 sdw_alh_base;
u32 quirks;
enum sof_intel_hw_ip_version hw_ip_version;
bool (*check_sdw_irq)(struct snd_sof_dev *sdev);
bool (*check_ipc_irq)(struct snd_sof_dev *sdev);
int (*cl_init)(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
};
extern const struct snd_sof_dsp_ops sof_tng_ops;
extern struct snd_sof_dsp_ops sof_tng_ops;
extern const struct sof_intel_dsp_desc tng_chip_info;

View File

@ -9,6 +9,8 @@
* Hardware interface for audio DSP on Tigerlake.
*/
#include <sound/sof/ext_manifest4.h>
#include "../ipc4-priv.h"
#include "../ops.h"
#include "hda.h"
#include "hda-ipc.h"
@ -22,148 +24,90 @@ static const struct snd_sof_debugfs_map tgl_dsp_debugfs[] = {
static int tgl_dsp_core_get(struct snd_sof_dev *sdev, int core)
{
struct sof_ipc_pm_core_config pm_core_config = {
.hdr = {
.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
.size = sizeof(pm_core_config),
},
.enable_mask = sdev->enabled_cores_mask | BIT(core),
};
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
/* power up primary core if not already powered up and return */
if (core == SOF_DSP_PRIMARY_CORE)
return hda_dsp_enable_core(sdev, BIT(core));
/* notify DSP for secondary cores */
return sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd,
&pm_core_config, sizeof(pm_core_config),
&pm_core_config, sizeof(pm_core_config));
if (pm_ops->set_core_state)
return pm_ops->set_core_state(sdev, core, true);
return 0;
}
static int tgl_dsp_core_put(struct snd_sof_dev *sdev, int core)
{
struct sof_ipc_pm_core_config pm_core_config = {
.hdr = {
.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
.size = sizeof(pm_core_config),
},
.enable_mask = sdev->enabled_cores_mask & ~BIT(core),
};
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
/* power down primary core and return */
if (core == SOF_DSP_PRIMARY_CORE)
return hda_dsp_core_reset_power_down(sdev, BIT(core));
/* notify DSP for secondary cores */
return sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd,
&pm_core_config, sizeof(pm_core_config),
&pm_core_config, sizeof(pm_core_config));
if (pm_ops->set_core_state)
return pm_ops->set_core_state(sdev, core, false);
return 0;
}
/* Tigerlake ops */
const struct snd_sof_dsp_ops sof_tgl_ops = {
struct snd_sof_dsp_ops sof_tgl_ops;
EXPORT_SYMBOL_NS(sof_tgl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
int sof_tgl_ops_init(struct snd_sof_dev *sdev)
{
/* common defaults */
memcpy(&sof_tgl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
/* probe/remove/shutdown */
.probe = hda_dsp_probe,
.remove = hda_dsp_remove,
.shutdown = hda_dsp_shutdown,
sof_tgl_ops.shutdown = hda_dsp_shutdown;
/* Register IO */
.write = sof_io_write,
.read = sof_io_read,
.write64 = sof_io_write64,
.read64 = sof_io_read64,
if (sdev->pdata->ipc_type == SOF_IPC) {
/* doorbell */
sof_tgl_ops.irq_thread = cnl_ipc_irq_thread;
/* Block IO */
.block_read = sof_block_read,
.block_write = sof_block_write,
/* ipc */
sof_tgl_ops.send_msg = cnl_ipc_send_msg;
}
/* Mailbox IO */
.mailbox_read = sof_mailbox_read,
.mailbox_write = sof_mailbox_write,
if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
struct sof_ipc4_fw_data *ipc4_data;
/* doorbell */
.irq_thread = cnl_ipc_irq_thread,
sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
/* ipc */
.send_msg = cnl_ipc_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset,
.get_window_offset = hda_dsp_ipc_get_window_offset,
ipc4_data = sdev->private;
ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
.ipc_msg_data = hda_ipc_msg_data,
.set_stream_data_offset = hda_set_stream_data_offset,
/* doorbell */
sof_tgl_ops.irq_thread = cnl_ipc4_irq_thread;
/* machine driver */
.machine_select = hda_machine_select,
.machine_register = sof_machine_register,
.machine_unregister = sof_machine_unregister,
.set_mach_params = hda_set_mach_params,
/* ipc */
sof_tgl_ops.send_msg = cnl_ipc4_send_msg;
}
/* set DAI driver ops */
hda_set_dai_drv_ops(sdev, &sof_tgl_ops);
/* debug */
.debug_map = tgl_dsp_debugfs,
.debug_map_count = ARRAY_SIZE(tgl_dsp_debugfs),
.dbg_dump = hda_dsp_dump,
.ipc_dump = cnl_ipc_dump,
.debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
/* stream callbacks */
.pcm_open = hda_dsp_pcm_open,
.pcm_close = hda_dsp_pcm_close,
.pcm_hw_params = hda_dsp_pcm_hw_params,
.pcm_hw_free = hda_dsp_stream_hw_free,
.pcm_trigger = hda_dsp_pcm_trigger,
.pcm_pointer = hda_dsp_pcm_pointer,
.pcm_ack = hda_dsp_pcm_ack,
/* firmware loading */
.load_firmware = snd_sof_load_firmware_raw,
sof_tgl_ops.debug_map = tgl_dsp_debugfs;
sof_tgl_ops.debug_map_count = ARRAY_SIZE(tgl_dsp_debugfs);
sof_tgl_ops.ipc_dump = cnl_ipc_dump;
/* pre/post fw run */
.pre_fw_run = hda_dsp_pre_fw_run,
.post_fw_run = hda_dsp_post_fw_run,
/* parse platform specific extended manifest */
.parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
/* dsp core get/put */
.core_get = tgl_dsp_core_get,
.core_put = tgl_dsp_core_put,
sof_tgl_ops.post_fw_run = hda_dsp_post_fw_run;
/* firmware run */
.run = hda_dsp_cl_boot_firmware_iccmax,
sof_tgl_ops.run = hda_dsp_cl_boot_firmware_iccmax;
/* trace callback */
.trace_init = hda_dsp_trace_init,
.trace_release = hda_dsp_trace_release,
.trace_trigger = hda_dsp_trace_trigger,
/* dsp core get/put */
sof_tgl_ops.core_get = tgl_dsp_core_get;
sof_tgl_ops.core_put = tgl_dsp_core_put;
/* client ops */
.register_ipc_clients = hda_register_clients,
.unregister_ipc_clients = hda_unregister_clients,
/* DAI drivers */
.drv = skl_dai,
.num_drv = SOF_SKL_NUM_DAIS,
/* PM */
.suspend = hda_dsp_suspend,
.resume = hda_dsp_resume,
.runtime_suspend = hda_dsp_runtime_suspend,
.runtime_resume = hda_dsp_runtime_resume,
.runtime_idle = hda_dsp_runtime_idle,
.set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume,
.set_power_state = hda_dsp_set_power_state,
/* ALSA HW info flags */
.hw_info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
.dsp_arch_ops = &sof_xtensa_arch_ops,
return 0;
};
EXPORT_SYMBOL_NS(sof_tgl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
EXPORT_SYMBOL_NS(sof_tgl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc tgl_chip_info = {
/* Tigerlake , Alderlake */
@ -175,12 +119,16 @@ const struct sof_intel_dsp_desc tgl_chip_info = {
.ipc_ack = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
};
EXPORT_SYMBOL_NS(tgl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
@ -194,12 +142,16 @@ const struct sof_intel_dsp_desc tglh_chip_info = {
.ipc_ack = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
};
EXPORT_SYMBOL_NS(tglh_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
@ -213,12 +165,16 @@ const struct sof_intel_dsp_desc ehl_chip_info = {
.ipc_ack = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
};
EXPORT_SYMBOL_NS(ehl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
@ -232,11 +188,15 @@ const struct sof_intel_dsp_desc adls_chip_info = {
.ipc_ack = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
};
EXPORT_SYMBOL_NS(adls_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);

File diff suppressed because it is too large Load Diff

View File

@ -9,26 +9,85 @@
#include "sof-priv.h"
#include "sof-audio.h"
#include "ipc3-ops.h"
#include "ipc3-priv.h"
static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size)
/* IPC set()/get() for kcontrols. */
static int sof_ipc3_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool set)
{
if (value >= size)
return volume_map[size - 1];
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scontrol->scomp);
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
const struct sof_ipc_ops *iops = sdev->ipc->ops;
enum sof_ipc_ctrl_type ctrl_type;
struct snd_sof_widget *swidget;
bool widget_found = false;
u32 ipc_cmd, msg_bytes;
return volume_map[value];
}
static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size)
{
int i;
for (i = 0; i < size; i++) {
if (volume_map[i] >= value)
return i;
list_for_each_entry(swidget, &sdev->widget_list, list) {
if (swidget->comp_id == scontrol->comp_id) {
widget_found = true;
break;
}
}
return i - 1;
if (!widget_found) {
dev_err(sdev->dev, "%s: can't find widget with id %d\n", __func__,
scontrol->comp_id);
return -EINVAL;
}
/*
* Volatile controls should always be part of static pipelines and the widget use_count
* would always be > 0 in this case. For the others, just return the cached value if the
* widget is not set up.
*/
if (!swidget->use_count)
return 0;
/*
* Select the IPC cmd and the ctrl_type based on the ctrl_cmd and the
* direction
* Note: SOF_CTRL_TYPE_VALUE_COMP_* is not used and supported currently
* for ctrl_type
*/
if (cdata->cmd == SOF_CTRL_CMD_BINARY) {
ipc_cmd = set ? SOF_IPC_COMP_SET_DATA : SOF_IPC_COMP_GET_DATA;
ctrl_type = set ? SOF_CTRL_TYPE_DATA_SET : SOF_CTRL_TYPE_DATA_GET;
} else {
ipc_cmd = set ? SOF_IPC_COMP_SET_VALUE : SOF_IPC_COMP_GET_VALUE;
ctrl_type = set ? SOF_CTRL_TYPE_VALUE_CHAN_SET : SOF_CTRL_TYPE_VALUE_CHAN_GET;
}
cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd;
cdata->type = ctrl_type;
cdata->comp_id = scontrol->comp_id;
cdata->msg_index = 0;
/* calculate header and data size */
switch (cdata->type) {
case SOF_CTRL_TYPE_VALUE_CHAN_GET:
case SOF_CTRL_TYPE_VALUE_CHAN_SET:
cdata->num_elems = scontrol->num_channels;
msg_bytes = scontrol->num_channels *
sizeof(struct sof_ipc_ctrl_value_chan);
msg_bytes += sizeof(struct sof_ipc_ctrl_data);
break;
case SOF_CTRL_TYPE_DATA_GET:
case SOF_CTRL_TYPE_DATA_SET:
cdata->num_elems = cdata->data->size;
msg_bytes = cdata->data->size;
msg_bytes += sizeof(struct sof_ipc_ctrl_data) +
sizeof(struct sof_abi_hdr);
break;
default:
return -EINVAL;
}
cdata->rhdr.hdr.size = msg_bytes;
cdata->elems_remaining = 0;
return iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set);
}
static void snd_sof_refresh_control(struct snd_sof_control *scontrol)
@ -49,7 +108,7 @@ static void snd_sof_refresh_control(struct snd_sof_control *scontrol)
/* refresh the component data from DSP */
scontrol->comp_data_dirty = false;
ret = snd_sof_ipc_set_get_comp_data(scontrol, false);
ret = sof_ipc3_set_get_kcontrol_data(scontrol, false);
if (ret < 0) {
dev_err(scomp->dev, "Failed to get control data: %d\n", ret);
@ -97,7 +156,7 @@ static bool sof_ipc3_volume_put(struct snd_sof_control *scontrol,
/* notify DSP of mixer updates */
if (pm_runtime_active(scomp->dev)) {
int ret = snd_sof_ipc_set_get_comp_data(scontrol, true);
int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true);
if (ret < 0) {
dev_err(scomp->dev, "Failed to set mixer updates for %s\n",
@ -145,7 +204,7 @@ static bool sof_ipc3_switch_put(struct snd_sof_control *scontrol,
/* notify DSP of mixer updates */
if (pm_runtime_active(scomp->dev)) {
int ret = snd_sof_ipc_set_get_comp_data(scontrol, true);
int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true);
if (ret < 0) {
dev_err(scomp->dev, "Failed to set mixer updates for %s\n",
@ -193,7 +252,7 @@ static bool sof_ipc3_enum_put(struct snd_sof_control *scontrol,
/* notify DSP of enum updates */
if (pm_runtime_active(scomp->dev)) {
int ret = snd_sof_ipc_set_get_comp_data(scontrol, true);
int ret = sof_ipc3_set_get_kcontrol_data(scontrol, true);
if (ret < 0) {
dev_err(scomp->dev, "Failed to set enum updates for %s\n",
@ -265,7 +324,7 @@ static int sof_ipc3_bytes_put(struct snd_sof_control *scontrol,
/* notify DSP of byte control updates */
if (pm_runtime_active(scomp->dev))
return snd_sof_ipc_set_get_comp_data(scontrol, true);
return sof_ipc3_set_get_kcontrol_data(scontrol, true);
return 0;
}
@ -379,7 +438,7 @@ static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol,
/* notify DSP of byte control updates */
if (pm_runtime_active(scomp->dev))
return snd_sof_ipc_set_get_comp_data(scontrol, true);
return sof_ipc3_set_get_kcontrol_data(scontrol, true);
return 0;
}
@ -409,7 +468,7 @@ static int sof_ipc3_bytes_ext_volatile_get(struct snd_sof_control *scontrol,
cdata->data->abi = SOF_ABI_VERSION;
/* get all the component data from DSP */
ret = snd_sof_ipc_set_get_comp_data(scontrol, false);
ret = sof_ipc3_set_get_kcontrol_data(scontrol, false);
if (ret < 0)
return ret;
@ -578,6 +637,60 @@ static void sof_ipc3_control_update(struct snd_sof_dev *sdev, void *ipc_control_
snd_ctl_notify_one(swidget->scomp->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, kc, 0);
}
static int sof_ipc3_widget_kcontrol_setup(struct snd_sof_dev *sdev,
struct snd_sof_widget *swidget)
{
struct snd_sof_control *scontrol;
int ret;
/* set up all controls for the widget */
list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
if (scontrol->comp_id == swidget->comp_id) {
/* set kcontrol data in DSP */
ret = sof_ipc3_set_get_kcontrol_data(scontrol, true);
if (ret < 0) {
dev_err(sdev->dev,
"kcontrol %d set up failed for widget %s\n",
scontrol->comp_id, swidget->widget->name);
return ret;
}
/*
* Read back the data from the DSP for static widgets.
* This is particularly useful for binary kcontrols
* associated with static pipeline widgets to initialize
* the data size to match that in the DSP.
*/
if (swidget->dynamic_pipeline_widget)
continue;
ret = sof_ipc3_set_get_kcontrol_data(scontrol, false);
if (ret < 0)
dev_warn(sdev->dev,
"kcontrol %d read failed for widget %s\n",
scontrol->comp_id, swidget->widget->name);
}
return 0;
}
static int
sof_ipc3_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size)
{
int i;
/* init the volume table */
scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL);
if (!scontrol->volume_table)
return -ENOMEM;
/* populate the volume table */
for (i = 0; i < size ; i++)
scontrol->volume_table[i] = vol_compute_gain(i, tlv);
return 0;
}
const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops = {
.volume_put = sof_ipc3_volume_put,
.volume_get = sof_ipc3_volume_get,
@ -591,4 +704,6 @@ const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops = {
.bytes_ext_get = sof_ipc3_bytes_ext_get,
.bytes_ext_volatile_get = sof_ipc3_bytes_ext_volatile_get,
.update = sof_ipc3_control_update,
.widget_kcontrol_setup = sof_ipc3_widget_kcontrol_setup,
.set_up_volume_table = sof_ipc3_set_up_volume_table,
};

View File

@ -8,7 +8,7 @@
//
#include <sound/pcm_params.h>
#include "ipc3-ops.h"
#include "ipc3-priv.h"
#include "ops.h"
#include "sof-priv.h"
#include "sof-audio.h"
@ -34,8 +34,7 @@ static int sof_ipc3_pcm_hw_free(struct snd_soc_component *component,
stream.comp_id = spcm->stream[substream->stream].comp_id;
/* send IPC to the DSP */
return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
sizeof(stream), &reply, sizeof(reply));
return sof_ipc_tx_message(sdev->ipc, &stream, sizeof(stream), &reply, sizeof(reply));
}
static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component,
@ -116,10 +115,13 @@ static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component,
pcm.params.no_stream_position = 1;
}
if (platform_params->cont_update_posn)
pcm.params.cont_update_posn = 1;
dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag);
/* send hw_params IPC to the DSP */
ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
ret = sof_ipc_tx_message(sdev->ipc, &pcm, sizeof(pcm),
&ipc_params_reply, sizeof(ipc_params_reply));
if (ret < 0) {
dev_err(component->dev, "HW params ipc failed for stream %d\n",
@ -175,8 +177,7 @@ static int sof_ipc3_pcm_trigger(struct snd_soc_component *component,
}
/* send IPC to the DSP */
return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
sizeof(stream), &reply, sizeof(reply));
return sof_ipc_tx_message(sdev->ipc, &stream, sizeof(stream), &reply, sizeof(reply));
}
static void ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name,
@ -346,10 +347,10 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min, channels->max);
break;
case SOF_DAI_AMD_DMIC:
rate->min = private->dai_config->acpdmic.fsync_rate;
rate->max = private->dai_config->acpdmic.fsync_rate;
channels->min = private->dai_config->acpdmic.tdm_slots;
channels->max = private->dai_config->acpdmic.tdm_slots;
rate->min = private->dai_config->acpdmic.pdm_rate;
rate->max = private->dai_config->acpdmic.pdm_rate;
channels->min = private->dai_config->acpdmic.pdm_ch;
channels->max = private->dai_config->acpdmic.pdm_ch;
dev_dbg(component->dev,
"AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max);

View File

@ -11,16 +11,20 @@
#include <sound/pcm_params.h>
#include "sof-priv.h"
#include "sof-audio.h"
#include "ipc3-ops.h"
#include "ipc3-priv.h"
#include "ops.h"
/* Full volume for default values */
#define VOL_ZERO_DB BIT(VOLUME_FWL)
/* size of tplg ABI in bytes */
#define SOF_IPC3_TPLG_ABI_SIZE 3
struct sof_widget_data {
int ctrl_type;
int ipc_cmd;
struct sof_abi_hdr *pdata;
void *pdata;
size_t pdata_size;
struct snd_sof_control *control;
};
@ -262,6 +266,16 @@ static const struct sof_topology_token afe_tokens[] = {
offsetof(struct sof_ipc_dai_mtk_afe_params, format)},
};
/* ACPDMIC */
static const struct sof_topology_token acpdmic_tokens[] = {
{SOF_TKN_AMD_ACPDMIC_RATE,
SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc_dai_acpdmic_params, pdm_rate)},
{SOF_TKN_AMD_ACPDMIC_CH,
SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc_dai_acpdmic_params, pdm_ch)},
};
/* Core tokens */
static const struct sof_topology_token core_tokens[] = {
{SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
@ -296,6 +310,7 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = {
[SOF_ESAI_TOKENS] = {"ESAI tokens", esai_tokens, ARRAY_SIZE(esai_tokens)},
[SOF_SAI_TOKENS] = {"SAI tokens", sai_tokens, ARRAY_SIZE(sai_tokens)},
[SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)},
[SOF_ACPDMIC_TOKENS] = {"ACPDMIC tokens", acpdmic_tokens, ARRAY_SIZE(acpdmic_tokens)},
};
/**
@ -784,16 +799,26 @@ static int sof_get_control_data(struct snd_soc_component *scomp,
}
cdata = wdata[i].control->ipc_control_data;
wdata[i].pdata = cdata->data;
if (!wdata[i].pdata)
return -EINVAL;
/* make sure data is valid - data can be updated at runtime */
if (widget->dobj.widget.kcontrol_type[i] == SND_SOC_TPLG_TYPE_BYTES &&
wdata[i].pdata->magic != SOF_ABI_MAGIC)
return -EINVAL;
if (widget->dobj.widget.kcontrol_type[i] == SND_SOC_TPLG_TYPE_BYTES) {
/* make sure data is valid - data can be updated at runtime */
if (cdata->data->magic != SOF_ABI_MAGIC)
return -EINVAL;
*size += wdata[i].pdata->size;
wdata[i].pdata = cdata->data->data;
wdata[i].pdata_size = cdata->data->size;
} else {
/* points to the control data union */
wdata[i].pdata = cdata->chanv;
/*
* wdata[i].control->size is calculated with struct_size
* and includes the size of struct sof_ipc_ctrl_data
*/
wdata[i].pdata_size = wdata[i].control->size -
sizeof(struct sof_ipc_ctrl_data);
}
*size += wdata[i].pdata_size;
/* get data type */
switch (cdata->cmd) {
@ -876,10 +901,12 @@ static int sof_process_load(struct snd_soc_component *scomp,
*/
if (ipc_data_size) {
for (i = 0; i < widget->num_kcontrols; i++) {
memcpy(&process->data[offset],
wdata[i].pdata->data,
wdata[i].pdata->size);
offset += wdata[i].pdata->size;
if (!wdata[i].pdata_size)
continue;
memcpy(&process->data[offset], wdata[i].pdata,
wdata[i].pdata_size);
offset += wdata[i].pdata_size;
}
}
@ -1104,20 +1131,22 @@ static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, struct snd_so
struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
struct sof_dai_private_data *private = dai->private;
u32 size = sizeof(*config);
int ret;
/* handle master/slave and inverted clocks */
sof_dai_set_format(hw_config, config);
/* init IPC */
memset(&config->acpdmic, 0, sizeof(config->acpdmic));
config->hdr.size = size;
config->acpdmic.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
config->acpdmic.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
/* parse the required set of ACPDMIC tokens based on num_hw_cfgs */
ret = sof_update_ipc_object(scomp, &config->acpdmic, SOF_ACPDMIC_TOKENS, slink->tuples,
slink->num_tuples, size, slink->num_hw_configs);
if (ret < 0)
return ret;
dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n",
config->dai_index, config->acpdmic.tdm_slots,
config->acpdmic.fsync_rate);
config->dai_index, config->acpdmic.pdm_ch,
config->acpdmic.pdm_rate);
dai->number_configs = 1;
dai->current_config = 0;
@ -1423,8 +1452,8 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
if (ret < 0)
goto free;
dev_dbg(scomp->dev, "%s dai %s: type %d index %d\n",
__func__, swidget->widget->name, comp_dai->type, comp_dai->dai_index);
dev_dbg(scomp->dev, "dai %s: type %d index %d\n",
swidget->widget->name, comp_dai->type, comp_dai->dai_index);
sof_dbg_comp_config(scomp, &comp_dai->config);
/* now update DAI config */
@ -1551,8 +1580,7 @@ static int sof_ipc3_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
sroute->sink_widget->widget->name);
/* send ipc */
ret = sof_ipc_tx_message(sdev->ipc, connect.hdr.cmd, &connect, sizeof(connect),
&reply, sizeof(reply));
ret = sof_ipc_tx_message(sdev->ipc, &connect, sizeof(connect), &reply, sizeof(reply));
if (ret < 0)
dev_err(sdev->dev, "%s: route %s -> %s failed\n", __func__,
sroute->src_widget->widget->name, sroute->sink_widget->widget->name);
@ -1565,24 +1593,23 @@ static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_
struct sof_ipc_ctrl_data *cdata;
int ret;
if (scontrol->max_size < (sizeof(*cdata) + sizeof(struct sof_abi_hdr))) {
dev_err(sdev->dev, "%s: insufficient size for a bytes control: %zu.\n",
__func__, scontrol->max_size);
return -EINVAL;
}
if (scontrol->priv_size > scontrol->max_size - sizeof(*cdata)) {
dev_err(sdev->dev,
"%s: bytes data size %zu exceeds max %zu.\n", __func__,
scontrol->priv_size, scontrol->max_size - sizeof(*cdata));
return -EINVAL;
}
scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
if (!scontrol->ipc_control_data)
return -ENOMEM;
if (scontrol->max_size < sizeof(*cdata) ||
scontrol->max_size < sizeof(struct sof_abi_hdr)) {
ret = -EINVAL;
goto err;
}
/* init the get/put bytes data */
if (scontrol->priv_size > scontrol->max_size - sizeof(*cdata)) {
dev_err(sdev->dev, "err: bytes data size %zu exceeds max %zu.\n",
scontrol->priv_size, scontrol->max_size - sizeof(*cdata));
ret = -EINVAL;
goto err;
}
scontrol->size = sizeof(struct sof_ipc_ctrl_data) + scontrol->priv_size;
cdata = scontrol->ipc_control_data;
@ -1592,6 +1619,7 @@ static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_
if (scontrol->priv_size > 0) {
memcpy(cdata->data, scontrol->priv, scontrol->priv_size);
kfree(scontrol->priv);
scontrol->priv = NULL;
if (cdata->data->magic != SOF_ABI_MAGIC) {
dev_err(sdev->dev, "Wrong ABI magic 0x%08x.\n", cdata->data->magic);
@ -1616,6 +1644,7 @@ static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_
return 0;
err:
kfree(scontrol->ipc_control_data);
scontrol->ipc_control_data = NULL;
return ret;
}
@ -1697,7 +1726,7 @@ static int sof_ipc3_control_free(struct snd_sof_dev *sdev, struct snd_sof_contro
fcomp.id = scontrol->comp_id;
/* send IPC to the DSP */
return sof_ipc_tx_message(sdev->ipc, fcomp.hdr.cmd, &fcomp, sizeof(fcomp), NULL, 0);
return sof_ipc_tx_message(sdev->ipc, &fcomp, sizeof(fcomp), NULL, 0);
}
/* send pcm params ipc */
@ -1749,7 +1778,7 @@ static int sof_ipc3_keyword_detect_pcm_params(struct snd_sof_widget *swidget, in
}
/* send IPC to the DSP */
ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
ret = sof_ipc_tx_message(sdev->ipc, &pcm, sizeof(pcm),
&ipc_params_reply, sizeof(ipc_params_reply));
if (ret < 0)
dev_err(scomp->dev, "%s: PCM params failed for %s\n", __func__,
@ -1773,8 +1802,7 @@ static int sof_ipc3_keyword_detect_trigger(struct snd_sof_widget *swidget, int c
stream.comp_id = swidget->comp_id;
/* send IPC to the DSP */
ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
sizeof(stream), &reply, sizeof(reply));
ret = sof_ipc_tx_message(sdev->ipc, &stream, sizeof(stream), &reply, sizeof(reply));
if (ret < 0)
dev_err(scomp->dev, "%s: Failed to trigger %s\n", __func__, swidget->widget->name);
@ -1902,8 +1930,7 @@ static int sof_ipc3_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_w
ready.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_COMPLETE;
ready.comp_id = swidget->comp_id;
ret = sof_ipc_tx_message(sdev->ipc, ready.hdr.cmd, &ready, sizeof(ready), &reply,
sizeof(reply));
ret = sof_ipc_tx_message(sdev->ipc, &ready, sizeof(ready), &reply, sizeof(reply));
if (ret < 0)
return ret;
@ -1939,7 +1966,7 @@ static int sof_ipc3_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
break;
}
ret = sof_ipc_tx_message(sdev->ipc, ipc_free.hdr.cmd, &ipc_free, sizeof(ipc_free),
ret = sof_ipc_tx_message(sdev->ipc, &ipc_free, sizeof(ipc_free),
&reply, sizeof(reply));
if (ret < 0)
dev_err(sdev->dev, "failed to free widget %s\n", swidget->widget->name);
@ -2003,7 +2030,7 @@ static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *
/* only send the IPC if the widget is set up in the DSP */
if (swidget->use_count > 0) {
ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
ret = sof_ipc_tx_message(sdev->ipc, config, config->hdr.size,
&reply, sizeof(reply));
if (ret < 0)
dev_err(sdev->dev, "Failed to set dai config for %s\n", dai->name);
@ -2028,7 +2055,7 @@ static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
struct sof_dai_private_data *dai_data = dai->private;
struct sof_ipc_comp *comp = &dai_data->comp_dai->comp;
ret = sof_ipc_tx_message(sdev->ipc, comp->hdr.cmd, dai_data->comp_dai,
ret = sof_ipc_tx_message(sdev->ipc, dai_data->comp_dai,
comp->hdr.size, &reply, sizeof(reply));
break;
}
@ -2037,8 +2064,8 @@ static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
struct sof_ipc_pipe_new *pipeline;
pipeline = swidget->private;
ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
sizeof(*pipeline), &reply, sizeof(reply));
ret = sof_ipc_tx_message(sdev->ipc, pipeline, sizeof(*pipeline),
&reply, sizeof(reply));
break;
}
default:
@ -2046,7 +2073,7 @@ static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
struct sof_ipc_cmd_hdr *hdr;
hdr = swidget->private;
ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, swidget->private, hdr->size,
ret = sof_ipc_tx_message(sdev->ipc, swidget->private, hdr->size,
&reply, sizeof(reply));
break;
}
@ -2249,6 +2276,18 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
list_for_each_entry(sroute, &sdev->route_list, list)
sroute->setup = false;
/*
* before suspending, make sure the refcounts are all zeroed out. There's no way
* to recover at this point but this will help root cause bad sequences leading to
* more issues on resume
*/
list_for_each_entry(swidget, &sdev->widget_list, list) {
if (swidget->use_count != 0) {
dev_err(sdev->dev, "%s: widget %s is still in use: count %d\n",
__func__, swidget->widget->name, swidget->use_count);
}
}
return 0;
}
@ -2280,6 +2319,45 @@ static int sof_ipc3_dai_get_clk(struct snd_sof_dev *sdev, struct snd_sof_dai *da
return -EINVAL;
}
static int sof_ipc3_parse_manifest(struct snd_soc_component *scomp, int index,
struct snd_soc_tplg_manifest *man)
{
u32 size = le32_to_cpu(man->priv.size);
u32 abi_version;
/* backward compatible with tplg without ABI info */
if (!size) {
dev_dbg(scomp->dev, "No topology ABI info\n");
return 0;
}
if (size != SOF_IPC3_TPLG_ABI_SIZE) {
dev_err(scomp->dev, "%s: Invalid topology ABI size: %u\n",
__func__, size);
return -EINVAL;
}
dev_info(scomp->dev,
"Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n",
man->priv.data[0], man->priv.data[1], man->priv.data[2],
SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH);
abi_version = SOF_ABI_VER(man->priv.data[0], man->priv.data[1], man->priv.data[2]);
if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) {
dev_err(scomp->dev, "%s: Incompatible topology ABI version\n", __func__);
return -EINVAL;
}
if (IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS) &&
SOF_ABI_VERSION_MINOR(abi_version) > SOF_ABI_MINOR) {
dev_err(scomp->dev, "%s: Topology ABI is more recent than kernel\n", __func__);
return -EINVAL;
}
return 0;
}
/* token list for each topology object */
static enum sof_tokens host_token_list[] = {
SOF_CORE_TOKENS,
@ -2390,4 +2468,5 @@ const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
.dai_get_clk = sof_ipc3_dai_get_clk,
.set_up_all_pipelines = sof_ipc3_set_up_all_pipelines,
.tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines,
.parse_manifest = sof_ipc3_parse_manifest,
};

File diff suppressed because it is too large Load Diff

View File

@ -11,690 +11,9 @@
//
#include <linux/firmware.h>
#include <sound/sof.h>
#include <sound/sof/ext_manifest.h>
#include "sof-priv.h"
#include "ops.h"
static int get_ext_windows(struct snd_sof_dev *sdev,
const struct sof_ipc_ext_data_hdr *ext_hdr)
{
const struct sof_ipc_window *w =
container_of(ext_hdr, struct sof_ipc_window, ext_hdr);
if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS)
return -EINVAL;
if (sdev->info_window) {
if (memcmp(sdev->info_window, w, ext_hdr->hdr.size)) {
dev_err(sdev->dev, "error: mismatch between window descriptor from extended manifest and mailbox");
return -EINVAL;
}
return 0;
}
/* keep a local copy of the data */
sdev->info_window = devm_kmemdup(sdev->dev, w, ext_hdr->hdr.size,
GFP_KERNEL);
if (!sdev->info_window)
return -ENOMEM;
return 0;
}
static int get_cc_info(struct snd_sof_dev *sdev,
const struct sof_ipc_ext_data_hdr *ext_hdr)
{
int ret;
const struct sof_ipc_cc_version *cc =
container_of(ext_hdr, struct sof_ipc_cc_version, ext_hdr);
if (sdev->cc_version) {
if (memcmp(sdev->cc_version, cc, cc->ext_hdr.hdr.size)) {
dev_err(sdev->dev, "error: receive diverged cc_version descriptions");
return -EINVAL;
}
return 0;
}
dev_dbg(sdev->dev, "Firmware info: used compiler %s %d:%d:%d%s used optimization flags %s\n",
cc->name, cc->major, cc->minor, cc->micro, cc->desc,
cc->optim);
/* create read-only cc_version debugfs to store compiler version info */
/* use local copy of the cc_version to prevent data corruption */
if (sdev->first_boot) {
sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size,
GFP_KERNEL);
if (!sdev->cc_version)
return -ENOMEM;
memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size);
ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version,
cc->ext_hdr.hdr.size,
"cc_version", 0444);
/* errors are only due to memory allocation, not debugfs */
if (ret < 0) {
dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
return ret;
}
}
return 0;
}
/* parse the extended FW boot data structures from FW boot message */
static int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset)
{
struct sof_ipc_ext_data_hdr *ext_hdr;
void *ext_data;
int ret = 0;
ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!ext_data)
return -ENOMEM;
/* get first header */
snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data,
sizeof(*ext_hdr));
ext_hdr = ext_data;
while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
/* read in ext structure */
snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM,
offset + sizeof(*ext_hdr),
(void *)((u8 *)ext_data + sizeof(*ext_hdr)),
ext_hdr->hdr.size - sizeof(*ext_hdr));
dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n",
ext_hdr->type, ext_hdr->hdr.size);
/* process structure data */
switch (ext_hdr->type) {
case SOF_IPC_EXT_WINDOW:
ret = get_ext_windows(sdev, ext_hdr);
break;
case SOF_IPC_EXT_CC_INFO:
ret = get_cc_info(sdev, ext_hdr);
break;
case SOF_IPC_EXT_UNUSED:
case SOF_IPC_EXT_PROBE_INFO:
case SOF_IPC_EXT_USER_ABI_INFO:
/* They are supported but we don't do anything here */
break;
default:
dev_info(sdev->dev, "unknown ext header type %d size 0x%x\n",
ext_hdr->type, ext_hdr->hdr.size);
ret = 0;
break;
}
if (ret < 0) {
dev_err(sdev->dev, "error: failed to parse ext data type %d\n",
ext_hdr->type);
break;
}
/* move to next header */
offset += ext_hdr->hdr.size;
snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, ext_data,
sizeof(*ext_hdr));
ext_hdr = ext_data;
}
kfree(ext_data);
return ret;
}
static int ext_man_get_fw_version(struct snd_sof_dev *sdev,
const struct sof_ext_man_elem_header *hdr)
{
const struct sof_ext_man_fw_version *v =
container_of(hdr, struct sof_ext_man_fw_version, hdr);
memcpy(&sdev->fw_ready.version, &v->version, sizeof(v->version));
sdev->fw_ready.flags = v->flags;
/* log ABI versions and check FW compatibility */
return snd_sof_ipc_valid(sdev);
}
static int ext_man_get_windows(struct snd_sof_dev *sdev,
const struct sof_ext_man_elem_header *hdr)
{
const struct sof_ext_man_window *w;
w = container_of(hdr, struct sof_ext_man_window, hdr);
return get_ext_windows(sdev, &w->ipc_window.ext_hdr);
}
static int ext_man_get_cc_info(struct snd_sof_dev *sdev,
const struct sof_ext_man_elem_header *hdr)
{
const struct sof_ext_man_cc_version *cc;
cc = container_of(hdr, struct sof_ext_man_cc_version, hdr);
return get_cc_info(sdev, &cc->cc_version.ext_hdr);
}
static int ext_man_get_dbg_abi_info(struct snd_sof_dev *sdev,
const struct sof_ext_man_elem_header *hdr)
{
const struct ext_man_dbg_abi *dbg_abi =
container_of(hdr, struct ext_man_dbg_abi, hdr);
if (sdev->first_boot)
dev_dbg(sdev->dev,
"Firmware: DBG_ABI %d:%d:%d\n",
SOF_ABI_VERSION_MAJOR(dbg_abi->dbg_abi.abi_dbg_version),
SOF_ABI_VERSION_MINOR(dbg_abi->dbg_abi.abi_dbg_version),
SOF_ABI_VERSION_PATCH(dbg_abi->dbg_abi.abi_dbg_version));
return 0;
}
static int ext_man_get_config_data(struct snd_sof_dev *sdev,
const struct sof_ext_man_elem_header *hdr)
{
const struct sof_ext_man_config_data *config =
container_of(hdr, struct sof_ext_man_config_data, hdr);
const struct sof_config_elem *elem;
int elems_counter;
int elems_size;
int ret = 0;
int i;
/* calculate elements counter */
elems_size = config->hdr.size - sizeof(struct sof_ext_man_elem_header);
elems_counter = elems_size / sizeof(struct sof_config_elem);
dev_dbg(sdev->dev, "%s can hold up to %d config elements\n",
__func__, elems_counter);
for (i = 0; i < elems_counter; ++i) {
elem = &config->elems[i];
dev_dbg(sdev->dev, "%s get index %d token %d val %d\n",
__func__, i, elem->token, elem->value);
switch (elem->token) {
case SOF_EXT_MAN_CONFIG_EMPTY:
/* unused memory space is zero filled - mapped to EMPTY elements */
break;
case SOF_EXT_MAN_CONFIG_IPC_MSG_SIZE:
/* TODO: use ipc msg size from config data */
break;
case SOF_EXT_MAN_CONFIG_MEMORY_USAGE_SCAN:
if (sdev->first_boot && elem->value)
ret = snd_sof_dbg_memory_info_init(sdev);
break;
default:
dev_info(sdev->dev, "Unknown firmware configuration token %d value %d",
elem->token, elem->value);
break;
}
if (ret < 0) {
dev_err(sdev->dev, "error: processing sof_ext_man_config_data failed for token %d value 0x%x, %d\n",
elem->token, elem->value, ret);
return ret;
}
}
return 0;
}
static ssize_t snd_sof_ext_man_size(const struct firmware *fw)
{
const struct sof_ext_man_header *head;
head = (struct sof_ext_man_header *)fw->data;
/*
* assert fw size is big enough to contain extended manifest header,
* it prevents from reading unallocated memory from `head` in following
* step.
*/
if (fw->size < sizeof(*head))
return -EINVAL;
/*
* When fw points to extended manifest,
* then first u32 must be equal SOF_EXT_MAN_MAGIC_NUMBER.
*/
if (head->magic == SOF_EXT_MAN_MAGIC_NUMBER)
return head->full_size;
/* otherwise given fw don't have an extended manifest */
return 0;
}
/* parse extended FW manifest data structures */
static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev,
const struct firmware *fw)
{
const struct sof_ext_man_elem_header *elem_hdr;
const struct sof_ext_man_header *head;
ssize_t ext_man_size;
ssize_t remaining;
uintptr_t iptr;
int ret = 0;
head = (struct sof_ext_man_header *)fw->data;
remaining = head->full_size - head->header_size;
ext_man_size = snd_sof_ext_man_size(fw);
/* Assert firmware starts with extended manifest */
if (ext_man_size <= 0)
return ext_man_size;
/* incompatible version */
if (SOF_EXT_MAN_VERSION_INCOMPATIBLE(SOF_EXT_MAN_VERSION,
head->header_version)) {
dev_err(sdev->dev, "error: extended manifest version 0x%X differ from used 0x%X\n",
head->header_version, SOF_EXT_MAN_VERSION);
return -EINVAL;
}
/* get first extended manifest element header */
iptr = (uintptr_t)fw->data + head->header_size;
while (remaining > sizeof(*elem_hdr)) {
elem_hdr = (struct sof_ext_man_elem_header *)iptr;
dev_dbg(sdev->dev, "found sof_ext_man header type %d size 0x%X\n",
elem_hdr->type, elem_hdr->size);
if (elem_hdr->size < sizeof(*elem_hdr) ||
elem_hdr->size > remaining) {
dev_err(sdev->dev, "error: invalid sof_ext_man header size, type %d size 0x%X\n",
elem_hdr->type, elem_hdr->size);
return -EINVAL;
}
/* process structure data */
switch (elem_hdr->type) {
case SOF_EXT_MAN_ELEM_FW_VERSION:
ret = ext_man_get_fw_version(sdev, elem_hdr);
break;
case SOF_EXT_MAN_ELEM_WINDOW:
ret = ext_man_get_windows(sdev, elem_hdr);
break;
case SOF_EXT_MAN_ELEM_CC_VERSION:
ret = ext_man_get_cc_info(sdev, elem_hdr);
break;
case SOF_EXT_MAN_ELEM_DBG_ABI:
ret = ext_man_get_dbg_abi_info(sdev, elem_hdr);
break;
case SOF_EXT_MAN_ELEM_CONFIG_DATA:
ret = ext_man_get_config_data(sdev, elem_hdr);
break;
case SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA:
ret = snd_sof_dsp_parse_platform_ext_manifest(sdev, elem_hdr);
break;
default:
dev_info(sdev->dev, "unknown sof_ext_man header type %d size 0x%X\n",
elem_hdr->type, elem_hdr->size);
break;
}
if (ret < 0) {
dev_err(sdev->dev, "error: failed to parse sof_ext_man header type %d size 0x%X\n",
elem_hdr->type, elem_hdr->size);
return ret;
}
remaining -= elem_hdr->size;
iptr += elem_hdr->size;
}
if (remaining) {
dev_err(sdev->dev, "error: sof_ext_man header is inconsistent\n");
return -EINVAL;
}
return ext_man_size;
}
/*
* IPC Firmware ready.
*/
static void sof_get_windows(struct snd_sof_dev *sdev)
{
struct sof_ipc_window_elem *elem;
u32 outbox_offset = 0;
u32 stream_offset = 0;
u32 inbox_offset = 0;
u32 outbox_size = 0;
u32 stream_size = 0;
u32 inbox_size = 0;
u32 debug_size = 0;
u32 debug_offset = 0;
int window_offset;
int i;
if (!sdev->info_window) {
dev_err(sdev->dev, "error: have no window info\n");
return;
}
for (i = 0; i < sdev->info_window->num_windows; i++) {
elem = &sdev->info_window->window[i];
window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id);
if (window_offset < 0) {
dev_warn(sdev->dev, "warn: no offset for window %d\n",
elem->id);
continue;
}
switch (elem->type) {
case SOF_IPC_REGION_UPBOX:
inbox_offset = window_offset + elem->offset;
inbox_size = elem->size;
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
inbox_offset,
elem->size, "inbox",
SOF_DEBUGFS_ACCESS_D0_ONLY);
break;
case SOF_IPC_REGION_DOWNBOX:
outbox_offset = window_offset + elem->offset;
outbox_size = elem->size;
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
outbox_offset,
elem->size, "outbox",
SOF_DEBUGFS_ACCESS_D0_ONLY);
break;
case SOF_IPC_REGION_TRACE:
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
window_offset + elem->offset,
elem->size, "etrace",
SOF_DEBUGFS_ACCESS_D0_ONLY);
break;
case SOF_IPC_REGION_DEBUG:
debug_offset = window_offset + elem->offset;
debug_size = elem->size;
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
window_offset + elem->offset,
elem->size, "debug",
SOF_DEBUGFS_ACCESS_D0_ONLY);
break;
case SOF_IPC_REGION_STREAM:
stream_offset = window_offset + elem->offset;
stream_size = elem->size;
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
stream_offset,
elem->size, "stream",
SOF_DEBUGFS_ACCESS_D0_ONLY);
break;
case SOF_IPC_REGION_REGS:
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
window_offset + elem->offset,
elem->size, "regs",
SOF_DEBUGFS_ACCESS_D0_ONLY);
break;
case SOF_IPC_REGION_EXCEPTION:
sdev->dsp_oops_offset = window_offset + elem->offset;
snd_sof_debugfs_add_region_item(sdev, SOF_FW_BLK_TYPE_SRAM,
window_offset + elem->offset,
elem->size, "exception",
SOF_DEBUGFS_ACCESS_D0_ONLY);
break;
default:
dev_err(sdev->dev, "error: get illegal window info\n");
return;
}
}
if (outbox_size == 0 || inbox_size == 0) {
dev_err(sdev->dev, "error: get illegal mailbox window\n");
return;
}
sdev->dsp_box.offset = inbox_offset;
sdev->dsp_box.size = inbox_size;
sdev->host_box.offset = outbox_offset;
sdev->host_box.size = outbox_size;
sdev->stream_box.offset = stream_offset;
sdev->stream_box.size = stream_size;
sdev->debug_box.offset = debug_offset;
sdev->debug_box.size = debug_size;
dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
inbox_offset, inbox_size);
dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
outbox_offset, outbox_size);
dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
stream_offset, stream_size);
dev_dbg(sdev->dev, " debug region 0x%x - size 0x%x\n",
debug_offset, debug_size);
}
/* check for ABI compatibility and create memory windows on first boot */
int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
{
struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
int offset;
int ret;
/* mailbox must be on 4k boundary */
offset = snd_sof_dsp_get_mailbox_offset(sdev);
if (offset < 0) {
dev_err(sdev->dev, "error: have no mailbox offset\n");
return offset;
}
dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n",
msg_id, offset);
/* no need to re-check version/ABI for subsequent boots */
if (!sdev->first_boot)
return 0;
/*
* copy data from the DSP FW ready offset
* Subsequent error handling is not needed for BLK_TYPE_SRAM
*/
ret = snd_sof_dsp_block_read(sdev, SOF_FW_BLK_TYPE_SRAM, offset, fw_ready,
sizeof(*fw_ready));
if (ret) {
dev_err(sdev->dev,
"error: unable to read fw_ready, read from TYPE_SRAM failed\n");
return ret;
}
/* make sure ABI version is compatible */
ret = snd_sof_ipc_valid(sdev);
if (ret < 0)
return ret;
/* now check for extended data */
snd_sof_fw_parse_ext_data(sdev, offset + sizeof(struct sof_ipc_fw_ready));
sof_get_windows(sdev);
return sof_ipc_init_msg_memory(sdev);
}
EXPORT_SYMBOL(sof_fw_ready);
/* generic module parser for mmaped DSPs */
int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev,
struct snd_sof_mod_hdr *module)
{
struct snd_sof_blk_hdr *block;
int count, ret;
u32 offset;
size_t remaining;
dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n",
module->size, module->num_blocks, module->type);
block = (struct snd_sof_blk_hdr *)((u8 *)module + sizeof(*module));
/* module->size doesn't include header size */
remaining = module->size;
for (count = 0; count < module->num_blocks; count++) {
/* check for wrap */
if (remaining < sizeof(*block)) {
dev_err(sdev->dev, "error: not enough data remaining\n");
return -EINVAL;
}
/* minus header size of block */
remaining -= sizeof(*block);
if (block->size == 0) {
dev_warn(sdev->dev,
"warning: block %d size zero\n", count);
dev_warn(sdev->dev, " type 0x%x offset 0x%x\n",
block->type, block->offset);
continue;
}
switch (block->type) {
case SOF_FW_BLK_TYPE_RSRVD0:
case SOF_FW_BLK_TYPE_ROM...SOF_FW_BLK_TYPE_RSRVD14:
continue; /* not handled atm */
case SOF_FW_BLK_TYPE_IRAM:
case SOF_FW_BLK_TYPE_DRAM:
case SOF_FW_BLK_TYPE_SRAM:
offset = block->offset;
break;
default:
dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n",
block->type, count);
return -EINVAL;
}
dev_dbg(sdev->dev,
"block %d type 0x%x size 0x%x ==> offset 0x%x\n",
count, block->type, block->size, offset);
/* checking block->size to avoid unaligned access */
if (block->size % sizeof(u32)) {
dev_err(sdev->dev, "error: invalid block size 0x%x\n",
block->size);
return -EINVAL;
}
ret = snd_sof_dsp_block_write(sdev, block->type, offset,
block + 1, block->size);
if (ret < 0) {
dev_err(sdev->dev, "error: write to block type 0x%x failed\n",
block->type);
return ret;
}
if (remaining < block->size) {
dev_err(sdev->dev, "error: not enough data remaining\n");
return -EINVAL;
}
/* minus body size of block */
remaining -= block->size;
/* next block */
block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block)
+ block->size);
}
return 0;
}
EXPORT_SYMBOL(snd_sof_parse_module_memcpy);
static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw,
size_t fw_offset)
{
struct snd_sof_fw_header *header;
size_t fw_size = fw->size - fw_offset;
if (fw->size <= fw_offset) {
dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
return -EINVAL;
}
/* Read the header information from the data pointer */
header = (struct snd_sof_fw_header *)(fw->data + fw_offset);
/* verify FW sig */
if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) {
dev_err(sdev->dev, "error: invalid firmware signature\n");
return -EINVAL;
}
/* check size is valid */
if (fw_size != header->file_size + sizeof(*header)) {
dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n",
fw_size, header->file_size + sizeof(*header));
return -EINVAL;
}
dev_dbg(sdev->dev, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n",
header->file_size, header->num_modules,
header->abi, sizeof(*header));
return 0;
}
static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw,
size_t fw_offset)
{
struct snd_sof_fw_header *header;
struct snd_sof_mod_hdr *module;
int (*load_module)(struct snd_sof_dev *sof_dev,
struct snd_sof_mod_hdr *hdr);
int ret, count;
size_t remaining;
header = (struct snd_sof_fw_header *)(fw->data + fw_offset);
load_module = sof_ops(sdev)->load_module;
if (!load_module)
return -EINVAL;
/* parse each module */
module = (struct snd_sof_mod_hdr *)(fw->data + fw_offset +
sizeof(*header));
remaining = fw->size - sizeof(*header) - fw_offset;
/* check for wrap */
if (remaining > fw->size) {
dev_err(sdev->dev, "error: fw size smaller than header size\n");
return -EINVAL;
}
for (count = 0; count < header->num_modules; count++) {
/* check for wrap */
if (remaining < sizeof(*module)) {
dev_err(sdev->dev, "error: not enough data remaining\n");
return -EINVAL;
}
/* minus header size of module */
remaining -= sizeof(*module);
/* module */
ret = load_module(sdev, module);
if (ret < 0) {
dev_err(sdev->dev, "error: invalid module %d\n", count);
return ret;
}
if (remaining < module->size) {
dev_err(sdev->dev, "error: not enough data remaining\n");
return -EINVAL;
}
/* minus body size of module */
remaining -= module->size;
module = (struct snd_sof_mod_hdr *)((u8 *)module
+ sizeof(*module) + module->size);
}
return 0;
}
int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *plat_data = sdev->pdata;
@ -726,7 +45,7 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
}
/* check for extended manifest */
ext_man_size = snd_sof_fw_ext_man_parse(sdev, plat_data->fw);
ext_man_size = sdev->ipc->ops->fw_loader->parse_ext_manifest(sdev);
if (ext_man_size > 0) {
/* when no error occurred, drop extended manifest */
plat_data->fw_offset = ext_man_size;
@ -756,7 +75,7 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
return ret;
/* make sure the FW header and file is valid */
ret = check_header(sdev, plat_data->fw, plat_data->fw_offset);
ret = sdev->ipc->ops->fw_loader->validate(sdev);
if (ret < 0) {
dev_err(sdev->dev, "error: invalid FW header\n");
goto error;
@ -770,10 +89,12 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
}
/* parse and load firmware modules to DSP */
ret = load_modules(sdev, plat_data->fw, plat_data->fw_offset);
if (ret < 0) {
dev_err(sdev->dev, "error: invalid FW modules\n");
goto error;
if (sdev->ipc->ops->fw_loader->load_fw_to_dsp) {
ret = sdev->ipc->ops->fw_loader->load_fw_to_dsp(sdev);
if (ret < 0) {
dev_err(sdev->dev, "Firmware loading failed\n");
goto error;
}
}
return 0;
@ -854,6 +175,9 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
dev_dbg(sdev->dev, "firmware boot complete\n");
sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE);
if (sdev->first_boot && sdev->ipc->ops->fw_loader->query_fw_configuration)
return sdev->ipc->ops->fw_loader->query_fw_configuration(sdev);
return 0;
}
EXPORT_SYMBOL(snd_sof_run_firmware);

View File

@ -15,15 +15,27 @@ config SND_SOC_SOF_MTK_COMMON
tristate
select SND_SOC_SOF_OF_DEV
select SND_SOC_SOF
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_XTENSA
select SND_SOC_SOF_COMPRESS
help
This option is not user-selectable but automagically handled by
'select' statements at a higher level
config SND_SOC_SOF_MT8186
tristate "SOF support for MT8186 audio DSP"
select SND_SOC_SOF_MTK_COMMON
depends on MTK_ADSP_IPC
help
This adds support for Sound Open Firmware for Mediatek platforms
using the mt8186 processors.
Say Y if you have such a device.
If unsure select "N".
config SND_SOC_SOF_MT8195
tristate "SOF support for MT8195 audio DSP"
select SND_SOC_SOF_MTK_COMMON
depends on MTK_ADSP_IPC
help
This adds support for Sound Open Firmware for Mediatek platforms
using the mt8195 processors.

View File

@ -1,2 +1,4 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
obj-$(CONFIG_SND_SOC_SOF_MTK_COMMON) += mtk-adsp-common.o
obj-$(CONFIG_SND_SOC_SOF_MT8195) += mt8195/
obj-$(CONFIG_SND_SOC_SOF_MT8186) += mt8186/

View File

@ -7,37 +7,42 @@
#ifndef __MTK_ADSP_HELPER_H__
#define __MTK_ADSP_HELPER_H__
#include <linux/firmware/mediatek/mtk-adsp-ipc.h>
/*
* Global important adsp data structure.
*/
#define DSP_MBOX_NUM 3
struct mtk_adsp_chip_info {
phys_addr_t pa_sram;
phys_addr_t pa_dram; /* adsp dram physical base */
phys_addr_t pa_shared_dram; /* adsp dram physical base */
phys_addr_t pa_cfgreg;
phys_addr_t pa_mboxreg[DSP_MBOX_NUM];
u32 sramsize;
u32 dramsize;
u32 cfgregsize;
u32 shared_size;
void __iomem *va_sram; /* corresponding to pa_sram */
void __iomem *va_dram; /* corresponding to pa_dram */
void __iomem *va_cfgreg;
void __iomem *va_mboxreg[DSP_MBOX_NUM];
void __iomem *shared_sram; /* part of va_sram */
void __iomem *shared_dram; /* part of va_dram */
phys_addr_t adsp_bootup_addr;
int dram_offset; /*dram offset between system and dsp view*/
phys_addr_t pa_secreg;
u32 secregsize;
void __iomem *va_secreg;
phys_addr_t pa_busreg;
u32 busregsize;
void __iomem *va_busreg;
};
struct adsp_priv {
struct device *dev;
struct snd_sof_dev *sdev;
/* DSP IPC handler */
struct mbox_controller *adsp_mbox;
struct mtk_adsp_ipc *dsp_ipc;
struct platform_device *ipc_dev;
struct mtk_adsp_chip_info *adsp;
struct clk **clk;
u32 (*ap2adsp_addr)(u32 addr, void *data);

View File

@ -132,6 +132,13 @@ static int adsp_default_clk_init(struct snd_sof_dev *sdev, bool enable)
return ret;
}
ret = clk_set_parent(priv->clk[CLK_TOP_AUDIO_H],
priv->clk[CLK_TOP_CLK26M]);
if (ret) {
dev_err(dev, "set audio_h_sel failed %d\n", ret);
return ret;
}
ret = adsp_enable_all_clock(sdev);
if (ret) {
dev_err(dev, "failed to adsp_enable_clock: %d\n", ret);

View File

@ -21,7 +21,7 @@ void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr)
/* pull high StatVectorSel to use AltResetVec (set bit4 to 1) */
snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW,
DSP_RESET_SW, DSP_RESET_SW);
STATVECTOR_SEL, STATVECTOR_SEL);
/* toggle DReset & BReset */
/* pull high DReset & BReset */
@ -29,6 +29,9 @@ void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr)
ADSP_BRESET_SW | ADSP_DRESET_SW,
ADSP_BRESET_SW | ADSP_DRESET_SW);
/* delay 10 DSP cycles at 26M about 1us by IP vendor's suggestion */
udelay(1);
/* pull low DReset & BReset */
snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW,
ADSP_BRESET_SW | ADSP_DRESET_SW,
@ -46,11 +49,13 @@ void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr)
void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev)
{
/* Clear to 0 firstly */
snd_sof_dsp_write(sdev, DSP_REG_BAR, DSP_RESET_SW, 0x0);
/* RUN_STALL pull high again to reset */
snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW,
ADSP_RUNSTALL, ADSP_RUNSTALL);
/* pull high DReset & BReset */
snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW,
ADSP_BRESET_SW | ADSP_DRESET_SW,
ADSP_BRESET_SW | ADSP_DRESET_SW);
}

View File

@ -24,9 +24,103 @@
#include "../../sof-of-dev.h"
#include "../../sof-audio.h"
#include "../adsp_helper.h"
#include "../mtk-adsp-common.h"
#include "mt8195.h"
#include "mt8195-clk.h"
static int mt8195_get_mailbox_offset(struct snd_sof_dev *sdev)
{
return MBOX_OFFSET;
}
static int mt8195_get_window_offset(struct snd_sof_dev *sdev, u32 id)
{
return MBOX_OFFSET;
}
static int mt8195_send_msg(struct snd_sof_dev *sdev,
struct snd_sof_ipc_msg *msg)
{
struct adsp_priv *priv = sdev->pdata->hw_pdata;
sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
msg->msg_size);
return mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ);
}
static void mt8195_get_reply(struct snd_sof_dev *sdev)
{
struct snd_sof_ipc_msg *msg = sdev->msg;
struct sof_ipc_reply reply;
int ret = 0;
if (!msg) {
dev_warn(sdev->dev, "unexpected ipc interrupt\n");
return;
}
/* get reply */
sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply));
if (reply.error < 0) {
memcpy(msg->reply_data, &reply, sizeof(reply));
ret = reply.error;
} else {
/* reply has correct size? */
if (reply.hdr.size != msg->reply_size) {
dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n",
msg->reply_size, reply.hdr.size);
ret = -EINVAL;
}
/* read the message */
if (msg->reply_size > 0)
sof_mailbox_read(sdev, sdev->host_box.offset,
msg->reply_data, msg->reply_size);
}
msg->reply_error = ret;
}
static void mt8195_dsp_handle_reply(struct mtk_adsp_ipc *ipc)
{
struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc);
unsigned long flags;
spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
mt8195_get_reply(priv->sdev);
snd_sof_ipc_reply(priv->sdev, 0);
spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
}
static void mt8195_dsp_handle_request(struct mtk_adsp_ipc *ipc)
{
struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc);
u32 p; /* panic code */
int ret;
/* Read the message from the debug box. */
sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4,
&p, sizeof(p));
/* Check to see if the message is a panic code 0x0dead*** */
if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
snd_sof_dsp_panic(priv->sdev, p, true);
} else {
snd_sof_ipc_msgs_rx(priv->sdev);
/* tell DSP cmd is done */
ret = mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_RSP, MTK_ADSP_IPC_OP_RSP);
if (ret)
dev_err(priv->dev, "request send ipc failed");
}
}
static struct mtk_adsp_ipc_ops dsp_ops = {
.handle_reply = mt8195_dsp_handle_reply,
.handle_request = mt8195_dsp_handle_request,
};
static int platform_parse_resource(struct platform_device *pdev, void *data)
{
struct resource *mmio;
@ -51,6 +145,14 @@ static int platform_parse_resource(struct platform_device *pdev, void *data)
dev_dbg(dev, "DMA %pR\n", &res);
adsp->pa_shared_dram = (phys_addr_t)res.start;
adsp->shared_size = resource_size(&res);
if (adsp->pa_shared_dram & DRAM_REMAP_MASK) {
dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n",
(u32)adsp->pa_shared_dram);
return -EINVAL;
}
ret = of_reserved_mem_device_init(dev);
if (ret) {
dev_err(dev, "of_reserved_mem_device_init failed\n");
@ -179,23 +281,18 @@ static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data)
{
struct device *dev = &pdev->dev;
struct mtk_adsp_chip_info *adsp = data;
u32 shared_size;
/* remap shared-dram base to be non-cachable */
shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL;
adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size;
if (adsp->va_dram) {
adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size;
} else {
adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram,
shared_size);
if (!adsp->shared_dram) {
dev_err(dev, "ioremap failed for shared DRAM\n");
return -ENOMEM;
}
adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram,
adsp->shared_size);
if (!adsp->shared_dram) {
dev_err(dev, "failed to ioremap base %pa size %#x\n",
adsp->shared_dram, adsp->shared_size);
return -ENOMEM;
}
dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n",
adsp->shared_dram, &adsp->pa_shared_dram, shared_size);
adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size);
return 0;
}
@ -267,9 +364,11 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev)
goto err_adsp_sram_power_off;
}
sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev,
priv->adsp->pa_dram,
priv->adsp->dramsize);
priv->adsp->va_sram = sdev->bar[SOF_FW_BLK_TYPE_IRAM];
sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap(sdev->dev,
priv->adsp->pa_dram,
priv->adsp->dramsize);
if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n",
&priv->adsp->pa_dram, priv->adsp->dramsize);
@ -285,15 +384,36 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev)
}
sdev->bar[DSP_REG_BAR] = priv->adsp->va_cfgreg;
sdev->bar[DSP_MBOX0_BAR] = priv->adsp->va_mboxreg[0];
sdev->bar[DSP_MBOX1_BAR] = priv->adsp->va_mboxreg[1];
sdev->bar[DSP_MBOX2_BAR] = priv->adsp->va_mboxreg[2];
sdev->mmio_bar = SOF_FW_BLK_TYPE_SRAM;
sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
/* set default mailbox offset for FW ready message */
sdev->dsp_box.offset = mt8195_get_mailbox_offset(sdev);
priv->ipc_dev = platform_device_register_data(&pdev->dev, "mtk-adsp-ipc",
PLATFORM_DEVID_NONE,
pdev, sizeof(*pdev));
if (IS_ERR(priv->ipc_dev)) {
ret = PTR_ERR(priv->ipc_dev);
dev_err(sdev->dev, "failed to register mtk-adsp-ipc device\n");
goto err_adsp_sram_power_off;
}
priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev);
if (!priv->dsp_ipc) {
ret = -EPROBE_DEFER;
dev_err(sdev->dev, "failed to get drvdata\n");
goto exit_pdev_unregister;
}
mtk_adsp_ipc_set_data(priv->dsp_ipc, priv);
priv->dsp_ipc->ops = &dsp_ops;
return 0;
exit_pdev_unregister:
platform_device_unregister(priv->ipc_dev);
err_adsp_sram_power_off:
adsp_sram_power_on(&pdev->dev, false);
exit_clk_disable:
@ -302,10 +422,17 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev)
return ret;
}
static int mt8195_dsp_shutdown(struct snd_sof_dev *sdev)
{
return snd_sof_suspend(sdev->dev);
}
static int mt8195_dsp_remove(struct snd_sof_dev *sdev)
{
struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev);
struct adsp_priv *priv = sdev->pdata->hw_pdata;
platform_device_unregister(priv->ipc_dev);
adsp_sram_power_on(&pdev->dev, false);
adsp_clock_off(sdev);
@ -316,6 +443,19 @@ static int mt8195_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
{
struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev);
int ret;
u32 reset_sw, dbg_pc;
/* wait dsp enter idle, timeout is 1 second */
ret = snd_sof_dsp_read_poll_timeout(sdev, DSP_REG_BAR,
DSP_RESET_SW, reset_sw,
((reset_sw & ADSP_PWAIT) == ADSP_PWAIT),
SUSPEND_DSP_IDLE_POLL_INTERVAL_US,
SUSPEND_DSP_IDLE_TIMEOUT_US);
if (ret < 0) {
dbg_pc = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_PDEBUGPC);
dev_warn(sdev->dev, "dsp not idle, powering off anyway : swrest %#x, pc %#x, ret %d\n",
reset_sw, dbg_pc, ret);
}
/* stall and reset dsp */
sof_hifixdsp_shutdown(sdev);
@ -356,6 +496,39 @@ static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type)
return type;
}
static int mt8195_ipc_msg_data(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream,
void *p, size_t sz)
{
sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz);
return 0;
}
static void mt8195_adsp_dump(struct snd_sof_dev *sdev, u32 flags)
{
u32 dbg_pc, dbg_data, dbg_bus0, dbg_bus1, dbg_inst;
u32 dbg_ls0stat, dbg_ls1stat, faultbus, faultinfo, swrest;
/* dump debug registers */
dbg_pc = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_PDEBUGPC);
dbg_data = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_PDEBUGDATA);
dbg_bus0 = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_PDEBUGBUS0);
dbg_bus1 = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_PDEBUGBUS1);
dbg_inst = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_PDEBUGINST);
dbg_ls0stat = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_PDEBUGLS0STAT);
dbg_ls1stat = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_PDEBUGLS1STAT);
faultbus = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_PFAULTBUS);
faultinfo = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_PFAULTINFO);
swrest = snd_sof_dsp_read(sdev, DSP_REG_BAR, DSP_RESET_SW);
dev_info(sdev->dev, "adsp dump : pc %#x, data %#x, bus0 %#x, bus1 %#x, swrest %#x",
dbg_pc, dbg_data, dbg_bus0, dbg_bus1, swrest);
dev_info(sdev->dev, "dbg_inst %#x, ls0stat %#x, ls1stat %#x, faultbus %#x, faultinfo %#x",
dbg_inst, dbg_ls0stat, dbg_ls1stat, faultbus, faultinfo);
mtk_adsp_dump(sdev, flags);
}
static struct snd_soc_dai_driver mt8195_dai[] = {
{
.name = "SOF_DL2",
@ -388,10 +561,11 @@ static struct snd_soc_dai_driver mt8195_dai[] = {
};
/* mt8195 ops */
static const struct snd_sof_dsp_ops sof_mt8195_ops = {
static struct snd_sof_dsp_ops sof_mt8195_ops = {
/* probe and remove */
.probe = mt8195_dsp_probe,
.remove = mt8195_dsp_remove,
.shutdown = mt8195_dsp_shutdown,
/* DSP core boot */
.run = mt8195_run,
@ -406,17 +580,25 @@ static const struct snd_sof_dsp_ops sof_mt8195_ops = {
.write64 = sof_io_write64,
.read64 = sof_io_read64,
/* ipc */
.send_msg = mt8195_send_msg,
.get_mailbox_offset = mt8195_get_mailbox_offset,
.get_window_offset = mt8195_get_window_offset,
.ipc_msg_data = mt8195_ipc_msg_data,
.set_stream_data_offset = sof_set_stream_data_offset,
/* misc */
.get_bar_index = mt8195_get_bar_index,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
/* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy,
/* Firmware ops */
.dsp_arch_ops = &sof_xtensa_arch_ops,
/* Debug information */
.dbg_dump = mt8195_adsp_dump,
/* DAI drivers */
.drv = mt8195_dai,
.num_drv = ARRAY_SIZE(mt8195_dai),
@ -434,11 +616,20 @@ static const struct snd_sof_dsp_ops sof_mt8195_ops = {
};
static const struct sof_dev_desc sof_of_mt8195_desc = {
.default_fw_path = "mediatek/sof",
.default_tplg_path = "mediatek/sof-tplg",
.default_fw_filename = "sof-mt8195.ri",
.ipc_supported_mask = BIT(SOF_IPC),
.ipc_default = SOF_IPC,
.default_fw_path = {
[SOF_IPC] = "mediatek/sof",
},
.default_tplg_path = {
[SOF_IPC] = "mediatek/sof-tplg",
},
.default_fw_filename = {
[SOF_IPC] = "sof-mt8195.ri",
},
.nocodec_tplg_filename = "sof-mt8195-nocodec.tplg",
.ops = &sof_mt8195_ops,
.ipc_timeout = 1000,
};
static const struct of_device_id sof_of_mt8195_ids[] = {
@ -451,6 +642,7 @@ MODULE_DEVICE_TABLE(of, sof_of_mt8195_ids);
static struct platform_driver snd_sof_of_mt8195_driver = {
.probe = sof_of_probe,
.remove = sof_of_remove,
.shutdown = sof_of_shutdown,
.driver = {
.name = "sof-audio-of-mt8195",
.pm = &sof_of_pm,

View File

@ -34,6 +34,7 @@ struct snd_sof_dev;
#define ADSP_DRESET_SW BIT(1)
#define ADSP_RUNSTALL BIT(3)
#define STATVECTOR_SEL BIT(4)
#define ADSP_PWAIT BIT(16)
#define DSP_PFAULTBUS 0x0028
#define DSP_PFAULTINFO 0x002c
#define DSP_GPR00 0x0030
@ -153,6 +154,10 @@ struct snd_sof_dev;
#define DRAM_REMAP_SHIFT 12
#define DRAM_REMAP_MASK (BIT(DRAM_REMAP_SHIFT) - 1)
/* suspend dsp idle check interval and timeout */
#define SUSPEND_DSP_IDLE_TIMEOUT_US 1000000 /* timeout to wait dsp idle, 1 sec */
#define SUSPEND_DSP_IDLE_POLL_INTERVAL_US 500 /* 0.5 msec */
void sof_hifixdsp_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr);
void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev);
#endif

View File

@ -177,7 +177,7 @@ void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset, bool non_recoverabl
snd_sof_dsp_dbg_dump(sdev, "DSP panic!",
SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
sof_set_fw_state(sdev, SOF_FW_CRASHED);
snd_sof_trace_notify_for_error(sdev);
sof_fw_trace_fw_crashed(sdev);
} else {
snd_sof_dsp_dbg_dump(sdev,
"DSP panic (recovery will be attempted)",

View File

@ -21,6 +21,20 @@
#define sof_ops(sdev) \
((sdev)->pdata->desc->ops)
static inline int sof_ops_init(struct snd_sof_dev *sdev)
{
if (sdev->pdata->desc->ops_init)
return sdev->pdata->desc->ops_init(sdev);
return 0;
}
static inline void sof_ops_free(struct snd_sof_dev *sdev)
{
if (sdev->pdata->desc->ops_free)
sdev->pdata->desc->ops_free(sdev);
}
/* Mandatory operations are verified during probing */
/* init */
@ -367,32 +381,6 @@ static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev,
return sof_ops(sdev)->send_msg(sdev, msg);
}
/* host DMA trace */
static inline int snd_sof_dma_trace_init(struct snd_sof_dev *sdev,
struct sof_ipc_dma_trace_params_ext *dtrace_params)
{
if (sof_ops(sdev)->trace_init)
return sof_ops(sdev)->trace_init(sdev, dtrace_params);
return 0;
}
static inline int snd_sof_dma_trace_release(struct snd_sof_dev *sdev)
{
if (sof_ops(sdev)->trace_release)
return sof_ops(sdev)->trace_release(sdev);
return 0;
}
static inline int snd_sof_dma_trace_trigger(struct snd_sof_dev *sdev, int cmd)
{
if (sof_ops(sdev)->trace_trigger)
return sof_ops(sdev)->trace_trigger(sdev, cmd);
return 0;
}
/* host PCM ops */
static inline int
snd_sof_pcm_platform_open(struct snd_sof_dev *sdev,

View File

@ -82,8 +82,10 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL(snd_sof_pcm_period_elapsed);
int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd,
struct snd_sof_pcm *spcm, int dir)
static int
sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd,
struct snd_sof_pcm *spcm, struct snd_pcm_hw_params *params,
struct snd_sof_platform_stream_params *platform_params, int dir)
{
struct snd_soc_dai *dai;
int ret, j;
@ -102,7 +104,7 @@ int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm
spcm->stream[dir].list = list;
ret = sof_widget_list_setup(sdev, spcm, dir);
ret = sof_widget_list_setup(sdev, spcm, params, platform_params, dir);
if (ret < 0) {
dev_err(sdev->dev, "error: failed widget list set up for pcm %d dir %d\n",
spcm->pcm.pcm_id, dir);
@ -150,9 +152,16 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n",
spcm->pcm.pcm_id, substream->stream);
ret = snd_sof_pcm_platform_hw_params(sdev, substream, params, &platform_params);
if (ret < 0) {
dev_err(component->dev, "platform hw params failed\n");
return ret;
}
/* if this is a repeated hw_params without hw_free, skip setting up widgets */
if (!spcm->stream[substream->stream].list) {
ret = sof_pcm_setup_connected_widgets(sdev, rtd, spcm, substream->stream);
ret = sof_pcm_setup_connected_widgets(sdev, rtd, spcm, params, &platform_params,
substream->stream);
if (ret < 0)
return ret;
}
@ -166,12 +175,6 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
return ret;
}
ret = snd_sof_pcm_platform_hw_params(sdev, substream, params, &platform_params);
if (ret < 0) {
dev_err(component->dev, "platform hw params failed\n");
return ret;
}
if (pcm_ops->hw_params) {
ret = pcm_ops->hw_params(component, substream, params, &platform_params);
if (ret < 0)
@ -347,12 +350,9 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
snd_sof_pcm_platform_trigger(sdev, substream, cmd);
/* free PCM if reset_hw_params is set and the STOP IPC is successful */
if (!ret && reset_hw_params) {
if (!ret && reset_hw_params)
ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream,
free_widget_list);
if (ret < 0)
return ret;
}
return ret;
}
@ -396,7 +396,7 @@ static int sof_pcm_open(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
const struct snd_sof_dsp_ops *ops = sof_ops(sdev);
struct snd_sof_dsp_ops *ops = sof_ops(sdev);
struct snd_sof_pcm *spcm;
struct snd_soc_tplg_stream_caps *caps;
int ret;
@ -604,6 +604,14 @@ static int sof_pcm_probe(struct snd_soc_component *component)
const char *tplg_filename;
int ret;
/*
* make sure the device is pm_runtime_active before loading the
* topology and initiating IPC or bus transactions
*/
ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
/* load the default topology */
sdev->component = component;
@ -621,6 +629,9 @@ static int sof_pcm_probe(struct snd_soc_component *component)
return ret;
}
pm_runtime_mark_last_busy(component->dev);
pm_runtime_put_autosuspend(component->dev);
return ret;
}
@ -671,4 +682,6 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
/* increment module refcount when a pcm is opened */
pd->module_get_upon_open = 1;
pd->legacy_dai_naming = 1;
}

View File

@ -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;
@ -102,11 +105,18 @@ static int sof_resume(struct device *dev, bool runtime_resume)
/*
* Nothing further to be done for platforms that support the low power
* D0 substate.
* D0 substate. Resume trace and return when resuming from
* low-power D0 substate
*/
if (!runtime_resume && sof_ops(sdev)->set_power_state &&
old_state == SOF_DSP_PM_D0)
old_state == SOF_DSP_PM_D0) {
ret = sof_fw_trace_resume(sdev);
if (ret < 0)
/* non fatal */
dev_warn(sdev->dev,
"failed to enable trace after resume %d\n", ret);
return 0;
}
sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
@ -135,8 +145,8 @@ static int sof_resume(struct device *dev, bool runtime_resume)
return ret;
}
/* resume DMA trace, only need send ipc */
ret = snd_sof_init_trace_ipc(sdev);
/* resume DMA trace */
ret = sof_fw_trace_resume(sdev);
if (ret < 0) {
/* non fatal */
dev_warn(sdev->dev,
@ -187,7 +197,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
/* prepare for streams to be resumed properly upon resume */
if (!runtime_suspend) {
ret = sof_set_hw_params_upon_resume(sdev->dev);
ret = snd_sof_dsp_hw_params_upon_resume(sdev);
if (ret < 0) {
dev_err(sdev->dev,
"error: setting hw_params flag during suspend %d\n",
@ -201,6 +211,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
/* Skip to platform-specific suspend if DSP is entering D0 */
if (target_state == SOF_DSP_PM_D0) {
sof_fw_trace_suspend(sdev, pm_state);
/* Notify clients not managed by pm framework about core suspend */
sof_suspend_clients(sdev, pm_state);
goto suspend;
@ -209,8 +220,8 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
if (tplg_ops->tear_down_all_pipelines)
tplg_ops->tear_down_all_pipelines(sdev, false);
/* release trace */
snd_sof_release_trace(sdev);
/* suspend DMA trace */
sof_fw_trace_suspend(sdev, pm_state);
/* Notify clients not managed by pm framework about core suspend */
sof_suspend_clients(sdev, pm_state);
@ -327,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;

Some files were not shown because too many files have changed in this diff Show More