3
0
mirror of https://github.com/Qortal/Brooklyn.git synced 2025-01-30 14:52:17 +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); id = idr_alloc(&apm->graph_idr, graph, graph_id, graph_id + 1, GFP_KERNEL);
if (id < 0) { if (id < 0) {
dev_err(apm->dev, "Unable to allocate graph id (%d)\n", graph_id); dev_err(apm->dev, "Unable to allocate graph id (%d)\n", graph_id);
kfree(graph->graph);
kfree(graph); kfree(graph);
mutex_unlock(&apm->lock); mutex_unlock(&apm->lock);
return ERR_PTR(id); 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 = { static const struct snd_soc_component_driver q6asm_fe_dai_component = {
.name = DRV_NAME, .name = DRV_NAME,
.open = q6asm_dai_open, .open = q6asm_dai_open,
.hw_params = q6asm_dai_hw_params, .hw_params = q6asm_dai_hw_params,
.close = q6asm_dai_close, .close = q6asm_dai_close,
.prepare = q6asm_dai_prepare, .prepare = q6asm_dai_prepare,
.trigger = q6asm_dai_trigger, .trigger = q6asm_dai_trigger,
.pointer = q6asm_dai_pointer, .pointer = q6asm_dai_pointer,
.pcm_construct = q6asm_dai_pcm_new, .pcm_construct = q6asm_dai_pcm_new,
.compress_ops = &q6asm_dai_compress_ops, .compress_ops = &q6asm_dai_compress_ops,
.dapm_widgets = q6asm_dapm_widgets, .dapm_widgets = q6asm_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(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[] = { 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; return 0;
} }
buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_ATOMIC); buf = kcalloc(periods, sizeof(*buf), GFP_ATOMIC);
if (!buf) { if (!buf) {
spin_unlock_irqrestore(&ac->lock, flags); spin_unlock_irqrestore(&ac->lock, flags);
return -ENOMEM; return -ENOMEM;

View File

@ -124,10 +124,10 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime)
/* Enable Headset Jack detection */ /* Enable Headset Jack detection */
if (gpio_is_valid(machine->gpio_hp_det)) { if (gpio_is_valid(machine->gpio_hp_det)) {
snd_soc_card_jack_new(runtime->card, "Headphone Jack", snd_soc_card_jack_new_pins(runtime->card, "Headphone Jack",
SND_JACK_HEADPHONE, &headphone_jack, SND_JACK_HEADPHONE, &headphone_jack,
headphone_jack_pins, headphone_jack_pins,
ARRAY_SIZE(headphone_jack_pins)); ARRAY_SIZE(headphone_jack_pins));
rk_hp_jack_gpio.gpio = machine->gpio_hp_det; rk_hp_jack_gpio.gpio = machine->gpio_hp_det;
snd_soc_jack_add_gpios(&headphone_jack, 1, &rk_hp_jack_gpio); 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) 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 snd_soc_card *card = &snd_soc_card_rk;
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct rk_drvdata *machine; 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, return dev_err_probe(&pdev->dev, ret,
"Soc register card failed\n"); "Soc register card failed\n");
return ret; return 0;
} }
static const struct of_device_id rockchip_sound_of_match[] = { 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. */ /* Enable jack detection. */
ret = snd_soc_card_jack_new(card, "DP Jack", SND_JACK_LINEOUT, ret = snd_soc_card_jack_new(card, "DP Jack", SND_JACK_LINEOUT,
&cdn_dp_card_jack, NULL, 0); &cdn_dp_card_jack);
if (ret) { if (ret) {
dev_err(card->dev, "Can't create DP Jack %d\n", ret); dev_err(card->dev, "Can't create DP Jack %d\n", ret);
return 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 */ /* Enable Headset and 4 Buttons Jack detection */
ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_HEADSET | SND_JACK_LINEOUT |
SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3, SND_JACK_BTN_2 | SND_JACK_BTN_3,
&rockchip_sound_jack, &rockchip_sound_jack,
rockchip_sound_jack_pins, rockchip_sound_jack_pins,
ARRAY_SIZE(rockchip_sound_jack_pins)); ARRAY_SIZE(rockchip_sound_jack_pins));
if (ret) { if (ret) {
dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", 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_gpio.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
@ -54,8 +55,38 @@ struct rk_i2s_dev {
const struct rk_i2s_pins *pins; const struct rk_i2s_pins *pins;
unsigned int bclk_ratio; unsigned int bclk_ratio;
spinlock_t lock; /* tx/rx lock */ 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) static int i2s_runtime_suspend(struct device *dev)
{ {
struct rk_i2s_dev *i2s = dev_get_drvdata(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); 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; unsigned int val = 0;
int retry = 10; int retry = 10;
int ret = 0;
spin_lock(&i2s->lock); spin_lock(&i2s->lock);
if (on) { if (on) {
regmap_update_bits(i2s->regmap, I2S_DMACR, ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE); I2S_DMACR_TDE_ENABLE,
I2S_DMACR_TDE_ENABLE);
regmap_update_bits(i2s->regmap, I2S_XFER, if (ret < 0)
I2S_XFER_TXS_START | I2S_XFER_RXS_START, goto end;
I2S_XFER_TXS_START | I2S_XFER_RXS_START); 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; i2s->tx_start = true;
} else { } else {
i2s->tx_start = false; i2s->tx_start = false;
regmap_update_bits(i2s->regmap, I2S_DMACR, ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE); I2S_DMACR_TDE_ENABLE,
I2S_DMACR_TDE_DISABLE);
if (ret < 0)
goto end;
if (!i2s->rx_start) { if (!i2s->rx_start) {
regmap_update_bits(i2s->regmap, I2S_XFER, ret = regmap_update_bits(i2s->regmap, I2S_XFER,
I2S_XFER_TXS_START | I2S_XFER_TXS_START | I2S_XFER_RXS_START,
I2S_XFER_RXS_START, I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP);
I2S_XFER_TXS_STOP | if (ret < 0)
I2S_XFER_RXS_STOP); goto end;
udelay(150); udelay(150);
regmap_update_bits(i2s->regmap, I2S_CLR, ret = regmap_update_bits(i2s->regmap, I2S_CLR,
I2S_CLR_TXC | I2S_CLR_RXC, I2S_CLR_TXC | I2S_CLR_RXC,
I2S_CLR_TXC | I2S_CLR_RXC); I2S_CLR_TXC | I2S_CLR_RXC);
if (ret < 0)
goto end;
regmap_read(i2s->regmap, I2S_CLR, &val); regmap_read(i2s->regmap, I2S_CLR, &val);
/* Should wait for clear operation to finish */ /* Should wait for clear operation to finish */
@ -133,61 +171,80 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
retry--; retry--;
if (!retry) { if (!retry) {
dev_warn(i2s->dev, "fail to clear\n"); dev_warn(i2s->dev, "fail to clear\n");
ret = -EBUSY;
break; break;
} }
} }
} }
} }
end:
spin_unlock(&i2s->lock); 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; unsigned int val = 0;
int retry = 10; int retry = 10;
int ret = 0;
spin_lock(&i2s->lock); spin_lock(&i2s->lock);
if (on) { if (on) {
regmap_update_bits(i2s->regmap, I2S_DMACR, ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE); I2S_DMACR_RDE_ENABLE,
I2S_DMACR_RDE_ENABLE);
regmap_update_bits(i2s->regmap, I2S_XFER, if (ret < 0)
I2S_XFER_TXS_START | I2S_XFER_RXS_START, goto end;
I2S_XFER_TXS_START | I2S_XFER_RXS_START);
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; i2s->rx_start = true;
} else { } else {
i2s->rx_start = false; i2s->rx_start = false;
regmap_update_bits(i2s->regmap, I2S_DMACR, ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE); I2S_DMACR_RDE_ENABLE,
I2S_DMACR_RDE_DISABLE);
if (ret < 0)
goto end;
if (!i2s->tx_start) { if (!i2s->tx_start) {
regmap_update_bits(i2s->regmap, I2S_XFER, ret = regmap_update_bits(i2s->regmap, I2S_XFER,
I2S_XFER_TXS_START | I2S_XFER_TXS_START | I2S_XFER_RXS_START,
I2S_XFER_RXS_START, I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP);
I2S_XFER_TXS_STOP | if (ret < 0)
I2S_XFER_RXS_STOP); goto end;
udelay(150); udelay(150);
regmap_update_bits(i2s->regmap, I2S_CLR, ret = regmap_update_bits(i2s->regmap, I2S_CLR,
I2S_CLR_TXC | I2S_CLR_RXC, I2S_CLR_TXC | I2S_CLR_RXC,
I2S_CLR_TXC | I2S_CLR_RXC); I2S_CLR_TXC | I2S_CLR_RXC);
if (ret < 0)
goto end;
regmap_read(i2s->regmap, I2S_CLR, &val); regmap_read(i2s->regmap, I2S_CLR, &val);
/* Should wait for clear operation to finish */ /* Should wait for clear operation to finish */
while (val) { while (val) {
regmap_read(i2s->regmap, I2S_CLR, &val); regmap_read(i2s->regmap, I2S_CLR, &val);
retry--; retry--;
if (!retry) { if (!retry) {
dev_warn(i2s->dev, "fail to clear\n"); dev_warn(i2s->dev, "fail to clear\n");
ret = -EBUSY;
break; break;
} }
} }
} }
} }
end:
spin_unlock(&i2s->lock); 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, 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); pm_runtime_get_sync(cpu_dai->dev);
mask = I2S_CKR_MSS_MASK; mask = I2S_CKR_MSS_MASK;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_BP_FP:
/* Set source clock in Master mode */ /* Set source clock in Master mode */
val = I2S_CKR_MSS_MASTER; val = I2S_CKR_MSS_MASTER;
i2s->is_master_mode = true; i2s->is_master_mode = true;
break; break;
case SND_SOC_DAIFMT_CBM_CFM: case SND_SOC_DAIFMT_BC_FC:
val = I2S_CKR_MSS_SLAVE; val = I2S_CKR_MSS_SLAVE;
i2s->is_master_mode = false; i2s->is_master_mode = false;
break; break;
@ -425,17 +482,25 @@ static int rockchip_i2s_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
rockchip_snd_rxctrl(i2s, 1); ret = rockchip_snd_rxctrl(i2s, 1);
else else
rockchip_snd_txctrl(i2s, 1); ret = rockchip_snd_txctrl(i2s, 1);
if (ret < 0)
return ret;
i2s_pinctrl_select_bclk_on(i2s);
break; break;
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
rockchip_snd_rxctrl(i2s, 0); if (!i2s->tx_start)
else i2s_pinctrl_select_bclk_off(i2s);
rockchip_snd_txctrl(i2s, 0); ret = rockchip_snd_rxctrl(i2s, 0);
} else {
if (!i2s->rx_start)
i2s_pinctrl_select_bclk_off(i2s);
ret = rockchip_snd_txctrl(i2s, 0);
}
break; break;
default: default:
ret = -EINVAL; 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 = { static const struct snd_soc_component_driver rockchip_i2s_component = {
.name = DRV_NAME, .name = DRV_NAME,
.legacy_dai_naming = 1,
}; };
static bool rockchip_i2s_wr_reg(struct device *dev, unsigned int reg) 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->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); 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; int ret;
bool is_tdm = i2s_tdm->tdm_mode; bool is_tdm = i2s_tdm->tdm_mode;
ret = pm_runtime_get_sync(cpu_dai->dev); ret = pm_runtime_resume_and_get(cpu_dai->dev);
if (ret < 0 && ret != -EACCES) { if (ret < 0 && ret != -EACCES)
pm_runtime_put_noidle(cpu_dai->dev);
return ret; return ret;
}
mask = I2S_CKR_MSS_MASK; mask = I2S_CKR_MSS_MASK;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBC_CFC: case SND_SOC_DAIFMT_BP_FP:
val = I2S_CKR_MSS_MASTER; val = I2S_CKR_MSS_MASTER;
i2s_tdm->is_master_mode = true; i2s_tdm->is_master_mode = true;
break; break;
case SND_SOC_DAIFMT_CBP_CFP: case SND_SOC_DAIFMT_BC_FC:
val = I2S_CKR_MSS_SLAVE; val = I2S_CKR_MSS_SLAVE;
i2s_tdm->is_master_mode = false; i2s_tdm->is_master_mode = false;
break; 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 = { static const struct snd_soc_component_driver rockchip_i2s_tdm_component = {
.name = DRV_NAME, .name = DRV_NAME,
.legacy_dai_naming = 1,
}; };
static bool rockchip_i2s_tdm_wr_reg(struct device *dev, unsigned int reg) 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 */ /* enable jack detection */
ret = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT, ret = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT,
&rk_hdmi_jack, NULL, 0); &rk_hdmi_jack);
if (ret) { if (ret) {
dev_err(card->dev, "Can't new HDMI Jack %d\n", ret); dev_err(card->dev, "Can't new HDMI Jack %d\n", ret);
return ret; return ret;
@ -345,13 +345,13 @@ static int rk_98090_headset_init(struct snd_soc_component *component)
int ret; int ret;
/* Enable Headset and 4 Buttons Jack detection */ /* Enable Headset and 4 Buttons Jack detection */
ret = snd_soc_card_jack_new(component->card, "Headset Jack", ret = snd_soc_card_jack_new_pins(component->card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_HEADSET |
SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3, SND_JACK_BTN_2 | SND_JACK_BTN_3,
&headset_jack, &headset_jack,
headset_jack_pins, headset_jack_pins,
ARRAY_SIZE(headset_jack_pins)); ARRAY_SIZE(headset_jack_pins));
if (ret) if (ret)
return 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 = { static const struct snd_soc_component_driver rockchip_pdm_component = {
.name = "rockchip-pdm", .name = "rockchip-pdm",
.legacy_dai_naming = 1,
}; };
static int rockchip_pdm_runtime_suspend(struct device *dev) 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); struct rk_pdm_dev *pdm = dev_get_drvdata(dev);
int ret; int ret;
ret = pm_runtime_get_sync(dev); ret = pm_runtime_resume_and_get(dev);
if (ret < 0) { if (ret < 0)
pm_runtime_put(dev);
return ret; return ret;
}
ret = regcache_sync(pdm->regmap); 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_HEADPHONE | SND_JACK_MICROPHONE |
SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3, SND_JACK_BTN_2 | SND_JACK_BTN_3,
&headset_jack, NULL, 0); &headset_jack);
if (ret) { if (ret) {
dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret); dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret);
return 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 = { static const struct snd_soc_component_driver rk_spdif_component = {
.name = "rockchip-spdif", .name = "rockchip-spdif",
.legacy_dai_naming = 1,
}; };
static bool rk_spdif_wr_reg(struct device *dev, unsigned int reg) 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 config SND_SOC_SAMSUNG_NEO1973_WM8753
tristate "Audio support for Openmoko Neo1973 Smartphones (GTA02)" 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_S3C24XX_I2S
select SND_SOC_WM8753 select SND_SOC_WM8753
select SND_SOC_BT_SCO select SND_SOC_BT_SCO
@ -43,7 +44,8 @@ config SND_SOC_SAMSUNG_NEO1973_WM8753
config SND_SOC_SAMSUNG_JIVE_WM8750 config SND_SOC_SAMSUNG_JIVE_WM8750
tristate "SoC I2S Audio support for Jive" 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_SOC_WM8750
select SND_S3C2412_SOC_I2S select SND_S3C2412_SOC_I2S
help help
@ -69,7 +71,7 @@ config SND_SOC_SAMSUNG_SMDK_WM8994
config SND_SOC_SAMSUNG_S3C24XX_UDA134X config SND_SOC_SAMSUNG_S3C24XX_UDA134X
tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" 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_S3C24XX_I2S
select SND_SOC_L3 select SND_SOC_L3
select SND_SOC_UDA134X select SND_SOC_UDA134X
@ -81,21 +83,24 @@ config SND_SOC_SAMSUNG_SIMTEC
config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23 config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23
tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards" 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_S3C24XX_I2S
select SND_SOC_TLV320AIC23_I2C select SND_SOC_TLV320AIC23_I2C
select SND_SOC_SAMSUNG_SIMTEC select SND_SOC_SAMSUNG_SIMTEC
config SND_SOC_SAMSUNG_SIMTEC_HERMES config SND_SOC_SAMSUNG_SIMTEC_HERMES
tristate "SoC I2S Audio support for Simtec Hermes board" 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_S3C24XX_I2S
select SND_SOC_TLV320AIC3X select SND_SOC_TLV320AIC3X
select SND_SOC_SAMSUNG_SIMTEC select SND_SOC_SAMSUNG_SIMTEC
config SND_SOC_SAMSUNG_H1940_UDA1380 config SND_SOC_SAMSUNG_H1940_UDA1380
tristate "Audio support for the HP iPAQ H1940" 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_S3C24XX_I2S
select SND_SOC_UDA1380 select SND_SOC_UDA1380
help help
@ -103,7 +108,8 @@ config SND_SOC_SAMSUNG_H1940_UDA1380
config SND_SOC_SAMSUNG_RX1950_UDA1380 config SND_SOC_SAMSUNG_RX1950_UDA1380
tristate "Audio support for the HP iPAQ RX1950" 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_S3C24XX_I2S
select SND_SOC_UDA1380 select SND_SOC_UDA1380
help 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); struct aries_wm8994_data *priv = snd_soc_card_get_drvdata(card);
int ret, irq; 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)); &aries_dock, dock_pins, ARRAY_SIZE(dock_pins));
if (ret) if (ret)
return ret; return ret;
@ -361,7 +361,7 @@ static int aries_late_probe(struct snd_soc_card *card)
else else
snd_soc_jack_report(&aries_dock, 0, SND_JACK_LINEOUT); 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, SND_JACK_HEADSET | SND_JACK_BTN_0,
&aries_headset, &aries_headset,
jack_pins, ARRAY_SIZE(jack_pins)); jack_pins, ARRAY_SIZE(jack_pins));
@ -432,7 +432,6 @@ static const struct snd_soc_component_driver aries_component = {
.idle_bias_on = 1, .idle_bias_on = 1,
.use_pmdown_time = 1, .use_pmdown_time = 1,
.endianness = 1, .endianness = 1,
.non_legacy_dai_naming = 1,
}; };
static struct snd_soc_dai_driver aries_ext_dai[] = { 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); extcon_np = of_parse_phandle(np, "extcon", 0);
priv->usb_extcon = extcon_find_edev_by_node(extcon_np); priv->usb_extcon = extcon_find_edev_by_node(extcon_np);
of_node_put(extcon_np);
if (IS_ERR(priv->usb_extcon)) if (IS_ERR(priv->usb_extcon))
return dev_err_probe(dev, PTR_ERR(priv->usb_extcon), return dev_err_probe(dev, PTR_ERR(priv->usb_extcon),
"Failed to get extcon device"); "Failed to get extcon device");
of_node_put(extcon_np);
priv->adc = devm_iio_channel_get(dev, "headset-detect"); priv->adc = devm_iio_channel_get(dev, "headset-detect");
if (IS_ERR(priv->adc)) if (IS_ERR(priv->adc))
@ -628,8 +627,10 @@ static int aries_audio_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
codec = of_get_child_by_name(dev->of_node, "codec"); codec = of_get_child_by_name(dev->of_node, "codec");
if (!codec) if (!codec) {
return -EINVAL; ret = -EINVAL;
goto out;
}
for_each_card_prelinks(card, i, dai_link) { for_each_card_prelinks(card, i, dai_link) {
dai_link->codecs->of_node = of_parse_phandle(codec, 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), 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" }, { "Sub CLK_SYS", NULL, "OPCLK" },
{ "CLKIN", NULL, "OPCLK" }, { "CLKIN", NULL, "OPCLK" },

View File

@ -8,7 +8,7 @@
// Based on version from Arnaud Patard <arnaud.patard@rtp-net.org> // Based on version from Arnaud Patard <arnaud.patard@rtp-net.org>
#include <linux/types.h> #include <linux/types.h>
#include <linux/gpio.h> #include <linux/gpio/consumer.h>
#include <linux/module.h> #include <linux/module.h>
#include <sound/soc.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) 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)); &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), 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; return -EINVAL;
} }
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM: case SND_SOC_DAIFMT_BC_FC:
tmp |= mod_slave; tmp |= mod_slave;
break; break;
case SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_BP_FP:
/* /*
* Set default source clock in Master mode, only when the * Set default source clock in Master mode, only when the
* CLK_I2S_RCLK_SRC clock is not exposed so we ensure any * 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, .suspend = i2s_suspend,
.resume = i2s_resume, .resume = i2s_resume,
.legacy_dai_naming = 1,
}; };
#define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ #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"), 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_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("AMIC", 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), 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, "HPOUT1L" },
{ "Headphone", NULL, "HPOUT1R" }, { "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_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_2 | SND_JACK_BTN_3 |
SND_JACK_BTN_4 | SND_JACK_BTN_5, SND_JACK_BTN_4 | SND_JACK_BTN_5,
&littlemill_headset, NULL, 0); &littlemill_headset);
if (ret) if (ret)
return ret; return ret;

View File

@ -51,10 +51,11 @@ static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
return ret; return ret;
} }
ret = snd_soc_card_jack_new(rtd->card, "Headset", SND_JACK_LINEOUT | ret = snd_soc_card_jack_new_pins(rtd->card, "Headset",
SND_JACK_HEADSET | SND_JACK_BTN_0, SND_JACK_LINEOUT | SND_JACK_HEADSET |
&lowland_headset, lowland_headset_pins, SND_JACK_BTN_0,
ARRAY_SIZE(lowland_headset_pins)); &lowland_headset, lowland_headset_pins,
ARRAY_SIZE(lowland_headset_pins));
if (ret) if (ret)
return ret; return ret;
@ -140,7 +141,7 @@ static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"), 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_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", 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), 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 IN1", NULL, "HPOUT2L" },
{ "Sub IN2", NULL, "HPOUT2R" }, { "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_HEADSET | SND_JACK_MECHANICAL |
SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5, SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5,
&priv->headset_jack, NULL, 0); &priv->headset_jack);
if (ret) if (ret)
return 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); return devm_snd_soc_register_card(dev, &neo1973);
} }
struct platform_driver neo1973_audio = { static struct platform_driver neo1973_audio = {
.driver = { .driver = {
.name = "neo1973-audio", .name = "neo1973-audio",
.pm = &snd_soc_pm_ops, .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; goto exit;
} }
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_BP_FP:
/* Nothing to do, Master by default */ /* Nothing to do, Master by default */
break; break;
default: default:
@ -480,7 +480,8 @@ static struct snd_soc_dai_driver s3c_pcm_dai[] = {
}; };
static const struct snd_soc_component_driver s3c_pcm_component = { 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) 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); &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, static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event) 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) 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)); &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins));
snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), 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); return devm_snd_soc_register_card(dev, &rx1950_asoc);
} }
struct platform_driver rx1950_audio = { static struct platform_driver rx1950_audio = {
.driver = { .driver = {
.name = "rx1950-audio", .name = "rx1950-audio",
.pm = &snd_soc_pm_ops, .pm = &snd_soc_pm_ops,

View File

@ -21,17 +21,6 @@
#include "regs-i2s-v2.h" #include "regs-i2s-v2.h"
#include "s3c-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 #define S3C2412_I2S_DEBUG_CON 0
static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) 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); iismod = readl(i2s->regs + S3C2412_IISMOD);
pr_debug("hw_params r: IISMOD: %x \n", iismod); pr_debug("hw_params r: IISMOD: %x \n", iismod);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM: case SND_SOC_DAIFMT_BC_FC:
i2s->master = 0; i2s->master = 0;
iismod |= S3C2412_IISMOD_SLAVE; iismod |= S3C2412_IISMOD_SLAVE;
break; break;
case SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_BP_FP:
i2s->master = 1; i2s->master = 1;
iismod &= ~S3C2412_IISMOD_SLAVE; iismod &= ~S3C2412_IISMOD_SLAVE;
break; 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 = { static const struct snd_soc_component_driver s3c2412_i2s_component = {
.name = "s3c2412-i2s", .name = "s3c2412-i2s",
.suspend = s3c2412_i2s_suspend, .suspend = s3c2412_i2s_suspend,
.resume = s3c2412_i2s_resume, .resume = s3c2412_i2s_resume,
.legacy_dai_naming = 1,
}; };
static int s3c2412_iis_dev_probe(struct platform_device *pdev) static int s3c2412_iis_dev_probe(struct platform_device *pdev)

View File

@ -12,7 +12,6 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/gpio.h>
#include <linux/module.h> #include <linux/module.h>
#include <sound/soc.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); iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
pr_debug("hw_params r: IISMOD: %x \n", iismod); pr_debug("hw_params r: IISMOD: %x \n", iismod);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM: case SND_SOC_DAIFMT_BC_FC:
iismod |= S3C2410_IISMOD_SLAVE; iismod |= S3C2410_IISMOD_SLAVE;
break; break;
case SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_BP_FP:
iismod &= ~S3C2410_IISMOD_SLAVE; iismod &= ~S3C2410_IISMOD_SLAVE;
break; break;
default: default:
@ -415,9 +414,10 @@ static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
}; };
static const struct snd_soc_component_driver s3c24xx_i2s_component = { static const struct snd_soc_component_driver s3c24xx_i2s_component = {
.name = "s3c24xx-i2s", .name = "s3c24xx-i2s",
.suspend = s3c24xx_i2s_suspend, .suspend = s3c24xx_i2s_suspend,
.resume = s3c24xx_i2s_resume, .resume = s3c24xx_i2s_resume,
.legacy_dai_naming = 1,
}; };
static int s3c24xx_iis_dev_probe(struct platform_device *pdev) 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"); snd_soc_dapm_nc_pin(dapm, "ROUT1");
/* Headphone jack detection */ /* Headphone jack detection */
err = snd_soc_card_jack_new(rtd->card, "Headphone Jack", err = snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack",
SND_JACK_HEADPHONE, &smartq_jack, SND_JACK_HEADPHONE, &smartq_jack,
smartq_jack_pins, smartq_jack_pins,
ARRAY_SIZE(smartq_jack_pins)); ARRAY_SIZE(smartq_jack_pins));
if (err) if (err)
return err; return err;

View File

@ -216,7 +216,7 @@ static int snow_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, ret, return dev_err_probe(&pdev->dev, ret,
"snd_soc_register_card failed\n"); "snd_soc_register_card failed\n");
return ret; return 0;
} }
static int snow_remove(struct platform_device *pdev) 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 = { static const struct snd_soc_component_driver samsung_spdif_component = {
.name = "samsung-spdif", .name = "samsung-spdif",
.suspend = spdif_suspend, .suspend = spdif_suspend,
.resume = spdif_resume, .resume = spdif_resume,
.legacy_dai_naming = 1,
}; };
static int spdif_probe(struct platform_device *pdev) static int spdif_probe(struct platform_device *pdev)
@ -467,8 +468,7 @@ static int spdif_remove(struct platform_device *pdev)
iounmap(spdif->regs); iounmap(spdif->regs);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 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->sclk);
clk_disable_unprepare(spdif->pclk); 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); pr_err("Failed to request HP_SEL GPIO: %d\n", ret);
gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity); gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
ret = snd_soc_card_jack_new(rtd->card, "Headset", SND_JACK_LINEOUT | ret = snd_soc_card_jack_new_pins(rtd->card, "Headset",
SND_JACK_HEADSET | SND_JACK_BTN_0, SND_JACK_LINEOUT | SND_JACK_HEADSET |
&speyside_headset, speyside_headset_pins, SND_JACK_BTN_0,
ARRAY_SIZE(speyside_headset_pins)); &speyside_headset,
speyside_headset_pins,
ARRAY_SIZE(speyside_headset_pins));
if (ret) if (ret)
return ret; return ret;
@ -261,7 +263,7 @@ static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"), 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_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", 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), 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" }, { "IN1RN", NULL, "MICB1" },
{ "IN1RP", NULL, "MICB1" }, { "IN1RP", NULL, "MICB1" },
{ "IN1RN", NULL, "MICB2" }, { "IN1RN", NULL, "MICB2" },

View File

@ -130,7 +130,7 @@ static const struct snd_kcontrol_new controls[] = {
SOC_DAPM_PIN_SWITCH("DMIC"), 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_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", 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), 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, "HPOUTL" },
{ "Headphone", NULL, "HPOUTR" }, { "Headphone", NULL, "HPOUTR" },
@ -189,10 +189,10 @@ static int tobermory_late_probe(struct snd_soc_card *card)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = snd_soc_card_jack_new(card, "Headset", SND_JACK_HEADSET | ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET |
SND_JACK_BTN_0, &tobermory_headset, SND_JACK_BTN_0, &tobermory_headset,
tobermory_headset_pins, tobermory_headset_pins,
ARRAY_SIZE(tobermory_headset_pins)); ARRAY_SIZE(tobermory_headset_pins));
if (ret) if (ret)
return ret; return ret;

View File

@ -47,7 +47,7 @@ config SND_SOC_RCAR
config SND_SOC_RZ config SND_SOC_RZ
tristate "RZ/G2L series SSIF-2 support" tristate "RZ/G2L series SSIF-2 support"
depends on ARCH_R9A07G044 || COMPILE_TEST depends on ARCH_RZG2L || COMPILE_TEST
help help
This option enables RZ/G2L SSIF-2 sound support. 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; int ret;
/* set clock master audio interface */ /* set clock master audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM: case SND_SOC_DAIFMT_BC_FC:
break; break;
case SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_BP_FP:
fsi->clk_master = 1; /* cpu is master */ fsi->clk_master = 1; /* cpu is master */
break; break;
default: 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 = { 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) 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); struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
/* set clock master for audio interface */ /* set clock master for audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBP_CFP: case SND_SOC_DAIFMT_BC_FC:
rdai->clk_master = 0; rdai->clk_master = 0;
break; break;
case SND_SOC_DAIFMT_CBC_CFC: case SND_SOC_DAIFMT_BP_FP:
rdai->clk_master = 1; /* cpu is master */ rdai->clk_master = 1; /* cpu is master */
break; break;
default: default:
@ -1159,6 +1159,7 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name,
struct device_node *capture) struct device_node *capture)
{ {
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *np; struct device_node *np;
int i; int i;
@ -1169,7 +1170,11 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name,
for_each_child_of_node(node, np) { for_each_child_of_node(node, np) {
struct rsnd_mod *mod; 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); mod = mod_get(priv, i);
@ -1183,7 +1188,7 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name,
of_node_put(node); 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]; char node_name[16];
@ -1210,6 +1215,8 @@ int rsnd_node_fixed_index(struct device_node *node, char *name, int idx)
return idx; return idx;
} }
dev_err(dev, "strange node numbering (%s)",
of_node_full_name(node));
return -EINVAL; return -EINVAL;
} }
@ -1221,10 +1228,8 @@ int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name
i = 0; i = 0;
for_each_child_of_node(node, np) { 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) { if (i < 0) {
dev_err(dev, "strange node numbering (%s)",
of_node_full_name(node));
of_node_put(np); of_node_put(np);
return 0; return 0;
} }
@ -1808,11 +1813,12 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
* snd_soc_component * snd_soc_component
*/ */
static const struct snd_soc_component_driver rsnd_soc_component = { static const struct snd_soc_component_driver rsnd_soc_component = {
.name = "rsnd", .name = "rsnd",
.probe = rsnd_debugfs_probe, .probe = rsnd_debugfs_probe,
.hw_params = rsnd_hw_params, .hw_params = rsnd_hw_params,
.hw_free = rsnd_hw_free, .hw_free = rsnd_hw_free,
.pointer = rsnd_pointer, .pointer = rsnd_pointer,
.legacy_dai_naming = 1,
}; };
static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, 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_cmd_remove,
rsnd_adg_remove, rsnd_adg_remove,
}; };
int ret = 0, i; int i;
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
for_each_rsnd_dai(rdai, priv, i) { for_each_rsnd_dai(rdai, priv, i) {
ret |= rsnd_dai_call(remove, &rdai->playback, priv); int ret;
ret |= rsnd_dai_call(remove, &rdai->capture, priv);
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++) for (i = 0; i < ARRAY_SIZE(remove_func); i++)
remove_func[i](priv); remove_func[i](priv);
return ret; return 0;
} }
static int __maybe_unused rsnd_suspend(struct device *dev) 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 dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name,
struct rsnd_mod *mod, char *x) 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 dma_chan *chan = NULL;
struct device_node *np; struct device_node *np;
int i = 0; int i = 0;
for_each_child_of_node(of_node, np) { 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)) if (i == rsnd_mod_id_raw(mod) && (!chan))
chan = of_dma_request_slave_channel(np, x); 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 *playback,
struct device_node *capture); struct device_node *capture);
int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name); 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); int rsnd_channel_normalization(int chan);
#define rsnd_runtime_channel_original(io) \ #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)) if (!of_device_is_available(np))
goto skip; 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); 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 device_node *capture)
{ {
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *node; struct device_node *node;
struct device_node *np; struct device_node *np;
int i; int i;
@ -1117,7 +1118,11 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
for_each_child_of_node(node, np) { for_each_child_of_node(node, np) {
struct rsnd_mod *mod; 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); 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)) if (!of_device_is_available(np))
goto skip; 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); 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; shift = 1;
offset = 1; offset = 1;
break; break;
default:
return;
} }
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
@ -102,6 +104,8 @@ bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod)
shift = 1; shift = 1;
offset = 1; offset = 1;
break; break;
default:
goto out;
} }
for (i = 0; i < 4; i++) { 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); rsnd_mod_write(mod, reg, val);
} }
out:
return error; return error;
} }
@ -415,6 +419,7 @@ static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
.name = SSIU_NAME, .name = SSIU_NAME,
.dma_req = rsnd_ssiu_dma_req, .dma_req = rsnd_ssiu_dma_req,
.init = rsnd_ssiu_init_gen2, .init = rsnd_ssiu_init_gen2,
.quit = rsnd_ssiu_quit,
.start = rsnd_ssiu_start_gen2, .start = rsnd_ssiu_start_gen2,
.stop = rsnd_ssiu_stop_gen2, .stop = rsnd_ssiu_stop_gen2,
.get_status = rsnd_ssiu_get_status, .get_status = rsnd_ssiu_get_status,
@ -460,6 +465,7 @@ void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
struct device_node *capture) struct device_node *capture)
{ {
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); 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 device_node *node = rsnd_ssiu_of_node(priv);
struct rsnd_dai_stream *io_p = &rdai->playback; struct rsnd_dai_stream *io_p = &rdai->playback;
struct rsnd_dai_stream *io_c = &rdai->capture; 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) { for_each_child_of_node(node, np) {
struct rsnd_mod *mod; 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); mod = rsnd_ssiu_mod_get(priv, i);

View File

@ -59,9 +59,7 @@
#define SSIFSR_RDC_MASK 0x3f #define SSIFSR_RDC_MASK 0x3f
#define SSIFSR_RDC_SHIFT 8 #define SSIFSR_RDC_SHIFT 8
#define SSIFSR_TDC(x) (((x) & 0x1f) << 24)
#define SSIFSR_TDE BIT(16) #define SSIFSR_TDE BIT(16)
#define SSIFSR_RDC(x) (((x) & 0x1f) << 8)
#define SSIFSR_RDF BIT(0) #define SSIFSR_RDF BIT(0)
#define SSIOFR_LRCONT BIT(8) #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); struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBC_CFC: case SND_SOC_DAIFMT_BP_FP:
break; break;
default: default:
dev_err(ssi->dev, "Codec should be clk and frame consumer\n"); 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 = { static const struct snd_soc_component_driver rz_ssi_soc_component = {
.name = "rz-ssi", .name = "rz-ssi",
.open = rz_ssi_pcm_open, .open = rz_ssi_pcm_open,
.pointer = rz_ssi_pcm_pointer, .pointer = rz_ssi_pcm_pointer,
.pcm_construct = rz_ssi_pcm_new, .pcm_construct = rz_ssi_pcm_new,
.legacy_dai_naming = 1,
}; };
static int rz_ssi_probe(struct platform_device *pdev) static int rz_ssi_probe(struct platform_device *pdev)
@ -978,22 +977,24 @@ static int rz_ssi_probe(struct platform_device *pdev)
/* Error Interrupt */ /* Error Interrupt */
ssi->irq_int = platform_get_irq_byname(pdev, "int_req"); ssi->irq_int = platform_get_irq_byname(pdev, "int_req");
if (ssi->irq_int < 0) if (ssi->irq_int < 0) {
return dev_err_probe(&pdev->dev, -ENODEV, rz_ssi_release_dma_channels(ssi);
"Unable to get SSI int_req IRQ\n"); return ssi->irq_int;
}
ret = devm_request_irq(&pdev->dev, ssi->irq_int, &rz_ssi_interrupt, ret = devm_request_irq(&pdev->dev, ssi->irq_int, &rz_ssi_interrupt,
0, dev_name(&pdev->dev), ssi); 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, return dev_err_probe(&pdev->dev, ret,
"irq request error (int_req)\n"); "irq request error (int_req)\n");
}
if (!rz_ssi_is_dma_enabled(ssi)) { if (!rz_ssi_is_dma_enabled(ssi)) {
/* Tx and Rx interrupts (pio only) */ /* Tx and Rx interrupts (pio only) */
ssi->irq_tx = platform_get_irq_byname(pdev, "dma_tx"); ssi->irq_tx = platform_get_irq_byname(pdev, "dma_tx");
if (ssi->irq_tx < 0) if (ssi->irq_tx < 0)
return dev_err_probe(&pdev->dev, -ENODEV, return ssi->irq_tx;
"Unable to get SSI dma_tx IRQ\n");
ret = devm_request_irq(&pdev->dev, ssi->irq_tx, ret = devm_request_irq(&pdev->dev, ssi->irq_tx,
&rz_ssi_interrupt, 0, &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"); ssi->irq_rx = platform_get_irq_byname(pdev, "dma_rx");
if (ssi->irq_rx < 0) if (ssi->irq_rx < 0)
return dev_err_probe(&pdev->dev, -ENODEV, return ssi->irq_rx;
"Unable to get SSI dma_rx IRQ\n");
ret = devm_request_irq(&pdev->dev, ssi->irq_rx, ret = devm_request_irq(&pdev->dev, ssi->irq_rx,
&rz_ssi_interrupt, 0, &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); ssi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(ssi->rstc)) if (IS_ERR(ssi->rstc)) {
return PTR_ERR(ssi->rstc); ret = PTR_ERR(ssi->rstc);
goto err_reset;
}
reset_control_deassert(ssi->rstc); reset_control_deassert(ssi->rstc);
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
ret = pm_runtime_resume_and_get(&pdev->dev); ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret < 0) { if (ret < 0) {
pm_runtime_disable(ssi->dev); dev_err(&pdev->dev, "pm_runtime_resume_and_get failed\n");
reset_control_assert(ssi->rstc); goto err_pm;
return dev_err_probe(ssi->dev, ret, "pm_runtime_resume_and_get failed\n");
} }
ret = devm_snd_soc_register_component(&pdev->dev, &rz_ssi_soc_component, ret = devm_snd_soc_register_component(&pdev->dev, &rz_ssi_soc_component,
rz_ssi_soc_dai, rz_ssi_soc_dai,
ARRAY_SIZE(rz_ssi_soc_dai)); ARRAY_SIZE(rz_ssi_soc_dai));
if (ret < 0) { 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"); 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; 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 = { const struct snd_soc_component_driver siu_component = {
.name = DRV_NAME, .name = DRV_NAME,
.open = siu_pcm_open, .open = siu_pcm_open,
.close = siu_pcm_close, .close = siu_pcm_close,
.prepare = siu_pcm_prepare, .prepare = siu_pcm_prepare,
.trigger = siu_pcm_trigger, .trigger = siu_pcm_trigger,
.pointer = siu_pcm_pointer_dma, .pointer = siu_pcm_pointer_dma,
.pcm_construct = siu_pcm_new, .pcm_construct = siu_pcm_new,
.pcm_destruct = siu_pcm_free, .pcm_destruct = siu_pcm_free,
.legacy_dai_naming = 1,
}; };
EXPORT_SYMBOL_GPL(siu_component); 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; return -EINVAL;
} }
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM: case SND_SOC_DAIFMT_BC_FC:
break; break;
case SND_SOC_DAIFMT_CBS_CFM: case SND_SOC_DAIFMT_BP_FC:
ssicr |= CR_SCK_MASTER; ssicr |= CR_SCK_MASTER;
break; break;
case SND_SOC_DAIFMT_CBM_CFS: case SND_SOC_DAIFMT_BC_FP:
ssicr |= CR_SWS_MASTER; ssicr |= CR_SWS_MASTER;
break; break;
case SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_BP_FP:
ssicr |= CR_SWS_MASTER | CR_SCK_MASTER; ssicr |= CR_SWS_MASTER | CR_SCK_MASTER;
break; break;
default: default:
@ -377,7 +377,8 @@ static struct snd_soc_dai_driver sh4_ssi_dai[] = {
}; };
static const struct snd_soc_component_driver sh4_ssi_component = { 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) 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 When selected, the probe is handled in two steps, for example to
avoid lockdeps if request_module is used in the probe. 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/amd/Kconfig"
source "sound/soc/sof/imx/Kconfig" source "sound/soc/sof/imx/Kconfig"
source "sound/soc/sof/intel/Kconfig" source "sound/soc/sof/intel/Kconfig"

View File

@ -1,8 +1,18 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) # 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\ 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\ control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o
ipc3-topology.o ipc3.o ipc3-control.o ipc3-pcm.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),) ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),)
snd-sof-objs += sof-client.o snd-sof-objs += sof-client.o
endif endif

View File

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

View File

@ -46,12 +46,14 @@
#define ACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0xC3C #define ACPAXI2AXI_ATU_BASE_ADDR_GRP_8 0xC3C
#define ACPAXI2AXI_ATU_CTRL 0xC40 #define ACPAXI2AXI_ATU_CTRL 0xC40
#define ACP_SOFT_RESET 0x1000 #define ACP_SOFT_RESET 0x1000
#define ACP_CONTROL 0x1004
#define ACP_I2S_PIN_CONFIG 0x1400 #define ACP_I2S_PIN_CONFIG 0x1400
/* Registers from ACP_PGFSM block */ /* Registers from ACP_PGFSM block */
#define ACP_PGFSM_CONTROL 0x141C #define ACP_PGFSM_CONTROL 0x141C
#define ACP_PGFSM_STATUS 0x1420 #define ACP_PGFSM_STATUS 0x1420
#define ACP_CLKMUX_SEL 0x1424
/* Registers from ACP_INTR block */ /* Registers from ACP_INTR block */
#define ACP_EXTERNAL_INTR_ENB 0x1800 #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); 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 sof_ipc_dma_trace_params_ext *dtrace_params)
{ {
struct acp_dsp_stream *stream; struct acp_dsp_stream *stream;
@ -46,7 +46,7 @@ int acp_sof_trace_init(struct snd_sof_dev *sdev,
if (!stream) if (!stream)
return -ENODEV; return -ENODEV;
stream->dmab = &sdev->dmatb; stream->dmab = dmab;
stream->num_pages = NUM_PAGES; stream->num_pages = NUM_PAGES;
ret = acp_dsp_stream_config(sdev, stream); 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; 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; struct snd_sof_dev *sdev = adata->dev;
int timeout; int timeout;
u32 data; 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--) { for (timeout = ACP_PSP_TIMEOUT_COUNTER; timeout > 0; timeout--) {
msleep(20); 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) if (data & MBOX_READY_MASK)
return 0; return 0;
} }
dev_err(sdev->dev, "FW validation timedout: status %x\n", data & MBOX_STATUS_MASK); dev_err(sdev->dev, "PSP error status %x\n", data & MBOX_STATUS_MASK);
return -ETIMEDOUT;
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, 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; return ret;
} }
ret = psp_fw_validate(adata); ret = psp_send_cmd(adata, MBOX_ACP_SHA_DMA_COMMAND);
if (ret) if (ret)
return 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"); dev_err(sdev->dev, "ACP power on failed\n");
return ret; return ret;
} }
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x01);
/* Reset */ /* Reset */
return acp_reset(sdev); 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) int amd_sof_acp_probe(struct snd_sof_dev *sdev)
{ {
struct pci_dev *pci = to_pci_dev(sdev->dev); struct pci_dev *pci = to_pci_dev(sdev->dev);

View File

@ -57,8 +57,10 @@
#define ACP_SHA_STAT 0x8000 #define ACP_SHA_STAT 0x8000
#define ACP_PSP_TIMEOUT_COUNTER 5 #define ACP_PSP_TIMEOUT_COUNTER 5
#define ACP_EXT_INTR_ERROR_STAT 0x20000000 #define ACP_EXT_INTR_ERROR_STAT 0x20000000
#define MP0_C2PMSG_26_REG 0x03810570 #define MP0_C2PMSG_114_REG 0x3810AC8
#define MBOX_ACP_SHA_DMA_COMMAND 0x330000 #define MP0_C2PMSG_73_REG 0x3810A24
#define MBOX_ACP_SHA_DMA_COMMAND 0x70000
#define MBOX_DELAY 1000
#define MBOX_READY_MASK 0x80000000 #define MBOX_READY_MASK 0x80000000
#define MBOX_STATUS_MASK 0xFFFF #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_pcm_hw_params *params,
struct snd_sof_platform_stream_params *platform_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 */ /* Machine configuration */
int snd_amd_acp_find_config(struct pci_dev *pci); int snd_amd_acp_find_config(struct pci_dev *pci);
/* Trace */ /* 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); struct sof_ipc_dma_trace_params_ext *dtrace_params);
int acp_sof_trace_release(struct snd_sof_dev *sdev); 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 { struct sof_amd_acp_desc {
unsigned int host_bridge_id; 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 = { static const struct sof_dev_desc renoir_desc = {
.machines = snd_soc_acpi_amd_sof_machines, .machines = snd_soc_acpi_amd_sof_machines,
.use_acpi_target_states = true,
.resindex_lpe_base = 0, .resindex_lpe_base = 0,
.resindex_pcicfg_base = -1, .resindex_pcicfg_base = -1,
.resindex_imr_base = -1, .resindex_imr_base = -1,
.irqindex_host_ipc = -1, .irqindex_host_ipc = -1,
.chip_info = &renoir_chip_info, .chip_info = &renoir_chip_info,
.default_fw_path = "amd/sof", .ipc_supported_mask = BIT(SOF_IPC),
.default_tplg_path = "amd/sof-tplg", .ipc_default = SOF_IPC,
.default_fw_filename = "sof-rn.ri", .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", .nocodec_tplg_filename = "sof-acp.tplg",
.ops = &sof_renoir_ops, .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); res = devm_kzalloc(&pci->dev, sizeof(struct resource) * ARRAY_SIZE(renoir_res), GFP_KERNEL);
if (!res) { if (!res) {
sof_pci_remove(pci); sof_pci_remove(pci);
platform_device_unregister(dmic_dev);
return -ENOMEM; return -ENOMEM;
} }
@ -157,6 +167,9 @@ static struct pci_driver snd_sof_pci_amd_rn_driver = {
.id_table = rn_pci_ids, .id_table = rn_pci_ids,
.probe = acp_pci_rn_probe, .probe = acp_pci_rn_probe,
.remove = acp_pci_rn_remove, .remove = acp_pci_rn_remove,
.driver = {
.pm = &sof_pci_pm,
},
}; };
module_pci_driver(snd_sof_pci_amd_rn_driver); 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 */ /* 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 and remove */
.probe = amd_sof_acp_probe, .probe = amd_sof_acp_probe,
.remove = amd_sof_acp_remove, .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_read = acp_dsp_block_read,
.block_write = acp_dsp_block_write, .block_write = acp_dsp_block_write,
/* Module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */ /*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .load_firmware = snd_sof_load_firmware_memcpy,
.pre_fw_run = acp_dsp_pre_fw_run, .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, .ipc_msg_data = acp_sof_ipc_msg_data,
.get_mailbox_offset = acp_sof_ipc_get_mailbox_offset, .get_mailbox_offset = acp_sof_ipc_get_mailbox_offset,
.irq_thread = acp_sof_ipc_irq_thread, .irq_thread = acp_sof_ipc_irq_thread,
.fw_ready = sof_fw_ready,
/* DAI drivers */ /* DAI drivers */
.drv = renoir_sof_dai, .drv = renoir_sof_dai,
@ -177,6 +173,10 @@ const struct snd_sof_dsp_ops sof_renoir_ops = {
/* Trace Logger */ /* Trace Logger */
.trace_init = acp_sof_trace_init, .trace_init = acp_sof_trace_init,
.trace_release = acp_sof_trace_release, .trace_release = acp_sof_trace_release,
/* PM */
.suspend = amd_sof_acp_suspend,
.resume = amd_sof_acp_resume,
}; };
EXPORT_SYMBOL(sof_renoir_ops); 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; stream.comp_id = spcm->stream[cstream->direction].comp_id;
if (spcm->prepared[cstream->direction]) { if (spcm->prepared[cstream->direction]) {
ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, ret = sof_ipc_tx_message(sdev->ipc, &stream, sizeof(stream),
&stream, sizeof(stream),
&reply, sizeof(reply)); &reply, sizeof(reply));
if (!ret) if (!ret)
spcm->prepared[cstream->direction] = false; 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_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_compr_runtime *crtd = cstream->runtime; struct snd_compr_runtime *crtd = cstream->runtime;
struct sof_ipc_pcm_params_reply ipc_params_reply; 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 snd_compr_tstamp *tstamp;
struct sof_ipc_pcm_params pcm; struct sof_ipc_pcm_params *pcm;
struct snd_sof_pcm *spcm; struct snd_sof_pcm *spcm;
size_t ext_data_size;
int ret; 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; tstamp = crtd->private_data;
spcm = snd_sof_find_spcm_dai(component, rtd); 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) if (!spcm)
return -EINVAL; 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.type = SNDRV_DMA_TYPE_DEV_SG;
cstream->dma_buffer.dev.dev = sdev->dev; cstream->dma_buffer.dev.dev = sdev->dev;
ret = snd_compr_malloc_pages(cstream, crtd->buffer_size); ret = snd_compr_malloc_pages(cstream, crtd->buffer_size);
if (ret < 0) if (ret < 0)
return ret; goto out;
ret = create_page_table(component, cstream, crtd->dma_area, crtd->dma_bytes); ret = create_page_table(component, cstream, crtd->dma_area, crtd->dma_bytes);
if (ret < 0) 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->comp_id = spcm->stream[cstream->direction].comp_id;
pcm.hdr.size = sizeof(pcm); pcm->params.hdr.size = sizeof(pcm->params) + ext_data_size;
pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS; pcm->params.buffer.phy_addr = spcm->stream[cstream->direction].page_table.addr;
pcm->params.buffer.size = crtd->dma_bytes;
pcm.comp_id = spcm->stream[cstream->direction].comp_id; pcm->params.direction = cstream->direction;
pcm.params.hdr.size = sizeof(pcm.params); pcm->params.channels = params->codec.ch_out;
pcm.params.buffer.phy_addr = spcm->stream[cstream->direction].page_table.addr; pcm->params.rate = params->codec.sample_rate;
pcm.params.buffer.size = crtd->dma_bytes; pcm->params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
pcm.params.direction = cstream->direction; pcm->params.frame_fmt = SOF_IPC_FRAME_S32_LE;
pcm.params.channels = params->codec.ch_out; pcm->params.sample_container_bytes =
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; 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)); &ipc_params_reply, sizeof(ipc_params_reply));
if (ret < 0) { if (ret < 0) {
dev_err(component->dev, "error ipc failed\n"); dev_err(component->dev, "error ipc failed\n");
return ret; goto out;
} }
tstamp->byte_offset = sdev->stream_box.offset + ipc_params_reply.posn_offset; 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; spcm->prepared[cstream->direction] = true;
return 0; out:
kfree(pcm);
return ret;
} }
static int sof_compr_get_params(struct snd_soc_component *component, 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; break;
} }
return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, return sof_ipc_tx_message(sdev->ipc, &stream, sizeof(stream),
&stream, sizeof(stream),
&reply, sizeof(reply)); &reply, sizeof(reply));
} }

View File

@ -15,36 +15,6 @@
#include "sof-priv.h" #include "sof-priv.h"
#include "sof-audio.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, int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) 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); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; 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) if (tplg_ops->control->switch_put)
return tplg_ops->control->switch_put(scontrol, ucontrol); 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; const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
int ret, err; int ret, err;
ret = pm_runtime_get_sync(scomp->dev); ret = pm_runtime_resume_and_get(scomp->dev);
if (ret < 0 && ret != -EACCES) { if (ret < 0 && ret != -EACCES) {
dev_err_ratelimited(scomp->dev, "%s: failed to resume %d\n", __func__, ret); dev_err_ratelimited(scomp->dev, "%s: failed to resume %d\n", __func__, ret);
pm_runtime_put_noidle(scomp->dev);
return ret; return ret;
} }

View File

@ -189,7 +189,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
ret = snd_sof_probe(sdev); ret = snd_sof_probe(sdev);
if (ret < 0) { if (ret < 0) {
dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret); 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); 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)) { if (sof_debug_check_flag(SOF_DBG_ENABLE_TRACE)) {
sdev->dtrace_is_supported = true; sdev->fw_trace_is_supported = true;
/* init DMA trace */ /* init firmware tracing */
ret = snd_sof_init_trace(sdev); ret = sof_fw_trace_init(sdev);
if (ret < 0) { if (ret < 0) {
/* non fatal */ /* non fatal */
dev_warn(sdev->dev, dev_warn(sdev->dev, "failed to initialize firmware tracing %d\n",
"warning: failed to initialize trace %d\n",
ret); ret);
} }
} else { } else {
@ -308,7 +307,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
sof_machine_err: sof_machine_err:
snd_sof_machine_unregister(sdev, plat_data); snd_sof_machine_unregister(sdev, plat_data);
fw_trace_err: fw_trace_err:
snd_sof_free_trace(sdev); sof_fw_trace_free(sdev);
fw_run_err: fw_run_err:
snd_sof_fw_unload(sdev); snd_sof_fw_unload(sdev);
fw_load_err: fw_load_err:
@ -318,6 +317,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
snd_sof_free_debug(sdev); snd_sof_free_debug(sdev);
dsp_err: dsp_err:
snd_sof_remove(sdev); snd_sof_remove(sdev);
probe_err:
sof_ops_free(sdev);
/* all resources freed, update state to match */ /* all resources freed, update state to match */
sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED); 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) int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
{ {
struct snd_sof_dev *sdev; struct snd_sof_dev *sdev;
int ret;
sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL); sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL);
if (!sdev) if (!sdev)
@ -357,11 +359,24 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
sdev->first_boot = true; sdev->first_boot = true;
dev_set_drvdata(dev, sdev); 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 */ /* check all mandatory ops */
if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run || 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)->block_read || !sof_ops(sdev)->block_write ||
!sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware || !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"); dev_err(dev, "error: missing mandatory ops\n");
return -EINVAL; return -EINVAL;
} }
@ -434,7 +449,7 @@ int snd_sof_device_remove(struct device *dev)
snd_sof_machine_unregister(sdev, pdata); snd_sof_machine_unregister(sdev, pdata);
if (sdev->fw_state > SOF_FW_BOOT_NOT_STARTED) { 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); ret = snd_sof_dsp_power_down_notify(sdev);
if (ret < 0) if (ret < 0)
dev_warn(dev, "error: %d failed to prepare DSP for device removal", 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); snd_sof_remove(sdev);
} }
sof_ops_free(sdev);
/* release firmware */ /* release firmware */
snd_sof_fw_unload(sdev); 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) if (!reply)
return -ENOMEM; return -ENOMEM;
ret = pm_runtime_get_sync(sdev->dev); ret = pm_runtime_resume_and_get(sdev->dev);
if (ret < 0 && ret != -EACCES) { if (ret < 0 && ret != -EACCES) {
pm_runtime_put_noidle(sdev->dev);
dev_err(sdev->dev, "error: enabling device failed: %d\n", ret); dev_err(sdev->dev, "error: enabling device failed: %d\n", ret);
goto error; 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_mark_last_busy(sdev->dev);
pm_runtime_put_autosuspend(sdev->dev); pm_runtime_put_autosuspend(sdev->dev);
if (ret < 0 || reply->rhdr.error < 0) { 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++) { 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", 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].zone, reply->elems[i].id,
reply->elems[i].used, reply->elems[i].free); reply->elems[i].used, reply->elems[i].free);
if (ret < 0) if (ret < 0)
goto error; goto error;
len += ret; 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) 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; const struct snd_sof_debugfs_map *map;
int i; int i;
int err; 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) || if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) ||
sof_debug_check_flag(SOF_DBG_RETAIN_CTX)) { 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 */ /* dump vital information to the logs */
snd_sof_ipc_dump(sdev); snd_sof_ipc_dump(sdev);
snd_sof_dsp_dbg_dump(sdev, "Firmware exception", snd_sof_dsp_dbg_dump(sdev, msg, SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); sof_fw_trace_fw_crashed(sdev);
snd_sof_trace_notify_for_error(sdev);
} }
EXPORT_SYMBOL(snd_sof_handle_fw_exception); EXPORT_SYMBOL(snd_sof_handle_fw_exception);

View File

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

View File

@ -487,7 +487,7 @@ static int imx8_dsp_set_power_state(struct snd_sof_dev *sdev,
} }
/* i.MX8 ops */ /* 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 and remove */
.probe = imx8_probe, .probe = imx8_probe,
.remove = imx8_remove, .remove = imx8_remove,
@ -504,16 +504,14 @@ static const struct snd_sof_dsp_ops sof_imx8_ops = {
/* ipc */ /* ipc */
.send_msg = imx8_send_msg, .send_msg = imx8_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = imx8_get_mailbox_offset, .get_mailbox_offset = imx8_get_mailbox_offset,
.get_window_offset = imx8_get_window_offset, .get_window_offset = imx8_get_window_offset,
.ipc_msg_data = sof_ipc_msg_data, .ipc_msg_data = sof_ipc_msg_data,
.set_stream_data_offset = sof_set_stream_data_offset, .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, .get_bar_index = imx8_get_bar_index,
/* firmware loading */ /* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .load_firmware = snd_sof_load_firmware_memcpy,
@ -550,7 +548,7 @@ static const struct snd_sof_dsp_ops sof_imx8_ops = {
}; };
/* i.MX8X 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 and remove */
.probe = imx8_probe, .probe = imx8_probe,
.remove = imx8_remove, .remove = imx8_remove,
@ -567,16 +565,14 @@ static const struct snd_sof_dsp_ops sof_imx8x_ops = {
/* ipc */ /* ipc */
.send_msg = imx8_send_msg, .send_msg = imx8_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = imx8_get_mailbox_offset, .get_mailbox_offset = imx8_get_mailbox_offset,
.get_window_offset = imx8_get_window_offset, .get_window_offset = imx8_get_window_offset,
.ipc_msg_data = sof_ipc_msg_data, .ipc_msg_data = sof_ipc_msg_data,
.set_stream_data_offset = sof_set_stream_data_offset, .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, .get_bar_index = imx8_get_bar_index,
/* firmware loading */ /* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .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 = { static struct sof_dev_desc sof_of_imx8qxp_desc = {
.default_fw_path = "imx/sof", .ipc_supported_mask = BIT(SOF_IPC),
.default_tplg_path = "imx/sof-tplg", .ipc_default = SOF_IPC,
.default_fw_filename = "sof-imx8x.ri", .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", .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
.ops = &sof_imx8x_ops, .ops = &sof_imx8x_ops,
}; };
static struct sof_dev_desc sof_of_imx8qm_desc = { static struct sof_dev_desc sof_of_imx8qm_desc = {
.default_fw_path = "imx/sof", .ipc_supported_mask = BIT(SOF_IPC),
.default_tplg_path = "imx/sof-tplg", .ipc_default = SOF_IPC,
.default_fw_filename = "sof-imx8.ri", .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", .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
.ops = &sof_imx8_ops, .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 */ /* 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 and remove */
.probe = imx8m_probe, .probe = imx8m_probe,
.remove = imx8m_remove, .remove = imx8m_remove,
@ -430,16 +430,14 @@ static const struct snd_sof_dsp_ops sof_imx8m_ops = {
/* ipc */ /* ipc */
.send_msg = imx8m_send_msg, .send_msg = imx8m_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = imx8m_get_mailbox_offset, .get_mailbox_offset = imx8m_get_mailbox_offset,
.get_window_offset = imx8m_get_window_offset, .get_window_offset = imx8m_get_window_offset,
.ipc_msg_data = sof_ipc_msg_data, .ipc_msg_data = sof_ipc_msg_data,
.set_stream_data_offset = sof_set_stream_data_offset, .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, .get_bar_index = imx8m_get_bar_index,
/* firmware loading */ /* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .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 = { static struct sof_dev_desc sof_of_imx8mp_desc = {
.default_fw_path = "imx/sof", .ipc_supported_mask = BIT(SOF_IPC),
.default_tplg_path = "imx/sof-tplg", .ipc_default = SOF_IPC,
.default_fw_filename = "sof-imx8m.ri", .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", .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
.ops = &sof_imx8m_ops, .ops = &sof_imx8m_ops,
}; };

View File

@ -40,6 +40,7 @@ if SND_SOC_SOF_ACPI
config SND_SOC_SOF_BAYTRAIL config SND_SOC_SOF_BAYTRAIL
tristate "SOF support for Baytrail, Braswell and Cherrytrail" tristate "SOF support for Baytrail, Braswell and Cherrytrail"
default SND_SOC_SOF_ACPI default SND_SOC_SOF_ACPI
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_COMMON select SND_SOC_SOF_INTEL_COMMON
select SND_SOC_SOF_INTEL_ATOM_HIFI_EP select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
select SND_SOC_SOF_ACPI_DEV select SND_SOC_SOF_ACPI_DEV
@ -60,6 +61,7 @@ config SND_SOC_SOF_BAYTRAIL
config SND_SOC_SOF_BROADWELL config SND_SOC_SOF_BROADWELL
tristate "SOF support for Broadwell" tristate "SOF support for Broadwell"
default SND_SOC_SOF_ACPI default SND_SOC_SOF_ACPI
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_COMMON select SND_SOC_SOF_INTEL_COMMON
select SND_SOC_SOF_INTEL_HIFI_EP_IPC select SND_SOC_SOF_INTEL_HIFI_EP_IPC
select SND_SOC_SOF_ACPI_DEV select SND_SOC_SOF_ACPI_DEV
@ -85,6 +87,7 @@ config SND_SOC_SOF_MERRIFIELD
tristate "SOF support for Tangier/Merrifield" tristate "SOF support for Tangier/Merrifield"
default SND_SOC_SOF_PCI default SND_SOC_SOF_PCI
select SND_SOC_SOF_PCI_DEV select SND_SOC_SOF_PCI_DEV
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_ATOM_HIFI_EP select SND_SOC_SOF_INTEL_ATOM_HIFI_EP
help help
This adds support for Sound Open Firmware for Intel(R) platforms 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 config SND_SOC_SOF_INTEL_APL
tristate tristate
select SND_SOC_SOF_HDA_COMMON select SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_IPC4
config SND_SOC_SOF_APOLLOLAKE config SND_SOC_SOF_APOLLOLAKE
tristate "SOF support for Apollolake" tristate "SOF support for Apollolake"
@ -120,6 +125,8 @@ config SND_SOC_SOF_INTEL_CNL
tristate tristate
select SND_SOC_SOF_HDA_COMMON select SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_IPC4
config SND_SOC_SOF_CANNONLAKE config SND_SOC_SOF_CANNONLAKE
tristate "SOF support for Cannonlake" tristate "SOF support for Cannonlake"
@ -154,6 +161,8 @@ config SND_SOC_SOF_INTEL_ICL
tristate tristate
select SND_SOC_SOF_HDA_COMMON select SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_IPC4
config SND_SOC_SOF_ICELAKE config SND_SOC_SOF_ICELAKE
tristate "SOF support for Icelake" tristate "SOF support for Icelake"
@ -179,6 +188,8 @@ config SND_SOC_SOF_INTEL_TGL
tristate tristate
select SND_SOC_SOF_HDA_COMMON select SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_INTEL_IPC4
config SND_SOC_SOF_TIGERLAKE config SND_SOC_SOF_TIGERLAKE
tristate "SOF support for Tigerlake" tristate "SOF support for Tigerlake"
@ -210,6 +221,22 @@ config SND_SOC_SOF_ALDERLAKE
Say Y if you have such a device. Say Y if you have such a device.
If unsure select "N". 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 config SND_SOC_SOF_HDA_COMMON
tristate tristate
select SND_SOC_SOF_INTEL_COMMON select SND_SOC_SOF_INTEL_COMMON
@ -260,7 +287,7 @@ config SND_SOC_SOF_HDA
'select' statements at a higher level. 'select' statements at a higher level.
config SND_SOC_SOF_HDA_PROBES config SND_SOC_SOF_HDA_PROBES
bool tristate
select SND_SOC_SOF_DEBUG_PROBES select SND_SOC_SOF_DEBUG_PROBES
help help
The option enables the data probing for Intel(R) Skylake and newer 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 \ 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-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \
hda-dai.o hda-bus.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-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-probes.o
snd-sof-intel-hda-objs := hda-codec.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-cnl-objs := pci-cnl.o
snd-sof-pci-intel-icl-objs := pci-icl.o snd-sof-pci-intel-icl-objs := pci-icl.o
snd-sof-pci-intel-tgl-objs := pci-tgl.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_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_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_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_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_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 * Hardware interface for audio DSP on Apollolake and GeminiLake
*/ */
#include <sound/sof/ext_manifest4.h>
#include "../ipc4-priv.h"
#include "../sof-priv.h" #include "../sof-priv.h"
#include "hda.h" #include "hda.h"
#include "../sof-audio.h" #include "../sof-audio.h"
@ -26,108 +28,62 @@ static const struct snd_sof_debugfs_map apl_dsp_debugfs[] = {
}; };
/* apollolake ops */ /* 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/remove/shutdown */
.probe = hda_dsp_probe, sof_apl_ops.shutdown = hda_dsp_shutdown;
.remove = hda_dsp_remove,
.shutdown = hda_dsp_shutdown,
/* Register IO */ if (sdev->pdata->ipc_type == SOF_IPC) {
.write = sof_io_write, /* doorbell */
.read = sof_io_read, sof_apl_ops.irq_thread = hda_dsp_ipc_irq_thread;
.write64 = sof_io_write64,
.read64 = sof_io_read64,
/* Block IO */ /* ipc */
.block_read = sof_block_read, sof_apl_ops.send_msg = hda_dsp_ipc_send_msg;
.block_write = sof_block_write, }
/* Mailbox IO */ if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
.mailbox_read = sof_mailbox_read, struct sof_ipc4_fw_data *ipc4_data;
.mailbox_write = sof_mailbox_write,
/* doorbell */ sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
.irq_thread = hda_dsp_ipc_irq_thread, if (!sdev->private)
return -ENOMEM;
/* ipc */ ipc4_data = sdev->private;
.send_msg = hda_dsp_ipc_send_msg, ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
.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, /* doorbell */
.set_stream_data_offset = hda_set_stream_data_offset, sof_apl_ops.irq_thread = hda_dsp_ipc4_irq_thread;
/* machine driver */ /* ipc */
.machine_select = hda_machine_select, sof_apl_ops.send_msg = hda_dsp_ipc4_send_msg;
.machine_register = sof_machine_register, }
.machine_unregister = sof_machine_unregister,
.set_mach_params = hda_set_mach_params, /* set DAI driver ops */
hda_set_dai_drv_ops(sdev, &sof_apl_ops);
/* debug */ /* debug */
.debug_map = apl_dsp_debugfs, sof_apl_ops.debug_map = apl_dsp_debugfs;
.debug_map_count = ARRAY_SIZE(apl_dsp_debugfs), sof_apl_ops.debug_map_count = ARRAY_SIZE(apl_dsp_debugfs);
.dbg_dump = hda_dsp_dump, sof_apl_ops.ipc_dump = hda_ipc_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,
/* firmware run */ /* firmware run */
.run = hda_dsp_cl_boot_firmware, sof_apl_ops.run = hda_dsp_cl_boot_firmware;
/* pre/post fw run */ /* pre/post fw run */
.pre_fw_run = hda_dsp_pre_fw_run, sof_apl_ops.post_fw_run = hda_dsp_post_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 */ /* dsp core get/put */
.core_get = hda_dsp_core_get, sof_apl_ops.core_get = hda_dsp_core_get;
/* trace callback */ return 0;
.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,
}; };
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 = { const struct sof_intel_dsp_desc apl_chip_info = {
/* Apollolake */ /* Apollolake */
@ -139,9 +95,13 @@ const struct sof_intel_dsp_desc apl_chip_info = {
.ipc_ack = HDA_DSP_REG_HIPCIE, .ipc_ack = HDA_DSP_REG_HIPCIE,
.ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE,
.ipc_ctl = HDA_DSP_REG_HIPCCTL, .ipc_ctl = HDA_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 150, .rom_init_timeout = 150,
.ssp_count = APL_SSP_COUNT, .ssp_count = APL_SSP_COUNT,
.ssp_base_offset = APL_SSP_BASE_OFFSET, .ssp_base_offset = APL_SSP_BASE_OFFSET,
.quirks = SOF_INTEL_PROCEN_FMT_QUIRK, .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); 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 *ssp_str)
{ {
const char *tplg_filename = NULL; const char *tplg_filename = NULL;
char *filename; const char *split_ext;
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) if (!filename)
return NULL; return NULL;
/* this assumes a .tplg extension */ /* this assumes a .tplg extension */
split_ext = strsep(&filename, "."); tmp = filename;
if (split_ext) { split_ext = strsep(&tmp, ".");
if (split_ext)
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s-%s.tplg", "%s-%s.tplg",
split_ext, ssp_str); split_ext, ssp_str);
if (!tplg_filename) kfree(filename);
return NULL;
}
return tplg_filename; return tplg_filename;
} }

View File

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

View File

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

View File

@ -15,6 +15,9 @@
* Hardware interface for audio DSP on Cannonlake. * 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 "../ops.h"
#include "hda.h" #include "hda.h"
#include "hda-ipc.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_host_done(struct snd_sof_dev *sdev);
static void cnl_ipc_dsp_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) irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
{ {
struct snd_sof_dev *sdev = 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,
CNL_DSP_REG_HIPCCTL_DONE, 0); 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 */ /* handle immediate reply from DSP core */
hda_dsp_ipc_get_reply(sdev); hda_dsp_ipc_get_reply(sdev);
snd_sof_ipc_reply(sdev, msg); 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; ipc_irq = true;
} }
@ -176,6 +252,22 @@ static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg,
return false; 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) 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; 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 */ /* 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/remove/shutdown */
.probe = hda_dsp_probe, sof_cnl_ops.shutdown = hda_dsp_shutdown;
.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,
/* ipc */ /* ipc */
.send_msg = cnl_ipc_send_msg, if (sdev->pdata->ipc_type == SOF_IPC) {
.fw_ready = sof_fw_ready, /* doorbell */
.get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset, sof_cnl_ops.irq_thread = cnl_ipc_irq_thread;
.get_window_offset = hda_dsp_ipc_get_window_offset,
.ipc_msg_data = hda_ipc_msg_data, /* ipc */
.set_stream_data_offset = hda_set_stream_data_offset, sof_cnl_ops.send_msg = cnl_ipc_send_msg;
}
/* machine driver */ if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
.machine_select = hda_machine_select, struct sof_ipc4_fw_data *ipc4_data;
.machine_register = sof_machine_register,
.machine_unregister = sof_machine_unregister, sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
.set_mach_params = hda_set_mach_params, 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 */
.debug_map = cnl_dsp_debugfs, sof_cnl_ops.debug_map = cnl_dsp_debugfs;
.debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs), sof_cnl_ops.debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs);
.dbg_dump = hda_dsp_dump, sof_cnl_ops.ipc_dump = cnl_ipc_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,
/* pre/post fw run */ /* pre/post fw run */
.pre_fw_run = hda_dsp_pre_fw_run, sof_cnl_ops.post_fw_run = hda_dsp_post_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,
/* firmware run */ /* firmware run */
.run = hda_dsp_cl_boot_firmware, sof_cnl_ops.run = hda_dsp_cl_boot_firmware;
/* trace callback */ /* dsp core get/put */
.trace_init = hda_dsp_trace_init, sof_cnl_ops.core_get = hda_dsp_core_get;
.trace_release = hda_dsp_trace_release,
.trace_trigger = hda_dsp_trace_trigger,
/* client ops */ return 0;
.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,
}; };
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 = { const struct sof_intel_dsp_desc cnl_chip_info = {
/* Cannonlake */ /* Cannonlake */
@ -357,12 +404,16 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
.ipc_ack = CNL_DSP_REG_HIPCIDA, .ipc_ack = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL, .ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300, .rom_init_timeout = 300,
.ssp_count = CNL_SSP_COUNT, .ssp_count = CNL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET, .ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE, .sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE, .sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq, .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); 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 = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL, .ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300, .rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT, .ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET, .ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE, .sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE, .sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq, .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); 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/pcm_params.h>
#include <sound/hdaudio_ext.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-priv.h"
#include "../sof-audio.h" #include "../sof-audio.h"
#include "hda.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) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
struct hda_pipe_params { struct hda_pipe_params {
@ -50,8 +63,8 @@ static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
} }
static struct hdac_ext_stream * static struct hdac_ext_stream *
hda_link_stream_assign(struct hdac_bus *bus, hda_link_stream_assign(struct hdac_bus *bus,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct sof_intel_hda_stream *hda_stream; struct sof_intel_hda_stream *hda_stream;
@ -113,12 +126,8 @@ static struct hdac_ext_stream *
} }
if (res) { if (res) {
/* /* Make sure that host and link DMA is decoupled. */
* Decouple host and link DMA. The decoupled flag snd_hdac_ext_stream_decouple_locked(bus, res, true);
* is updated in snd_hdac_ext_stream_decouple().
*/
if (!res->decoupled)
snd_hdac_ext_stream_decouple_locked(bus, res, true);
res->link_locked = 1; res->link_locked = 1;
res->link_substream = substream; res->link_substream = substream;
@ -128,6 +137,40 @@ static struct hdac_ext_stream *
return res; 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, static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
struct hda_pipe_params *params) 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; struct hdac_ext_link *link;
unsigned int format_val; unsigned int format_val;
snd_hdac_ext_stream_decouple(bus, hext_stream, true);
snd_hdac_ext_link_stream_reset(hext_stream); snd_hdac_ext_link_stream_reset(hext_stream);
format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch, 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; return 0;
} }
static int hda_link_dai_widget_update(struct sof_intel_hda_stream *hda_stream, static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dapm_widget *w, struct snd_pcm_hw_params *params)
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)
{ {
struct hdac_stream *hstream = substream->runtime->private_data; struct hdac_stream *hstream = substream->runtime->private_data;
struct hdac_bus *bus = hstream->bus;
struct hdac_ext_stream *hext_stream; struct hdac_ext_stream *hext_stream;
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 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 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 hda_pipe_params p_params = {0};
struct snd_soc_dapm_widget *w; struct hdac_bus *bus = hstream->bus;
struct hdac_ext_link *link; 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(cpu_dai, substream);
hext_stream = snd_soc_dai_get_dma_data(dai, substream);
if (!hext_stream) { if (!hext_stream) {
hext_stream = hda_link_stream_assign(bus, substream); hext_stream = hda_link_stream_assign(bus, substream);
if (!hext_stream) if (!hext_stream)
return -EBUSY; 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); link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
if (!link) if (!link)
return -EINVAL; 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); return hda_link_dma_params(hext_stream, &p_params);
} }
static int hda_link_pcm_prepare(struct snd_pcm_substream *substream, static int hda_link_dma_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 snd_sof_dev *sdev =
snd_soc_component_get_drvdata(dai->component);
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
int stream = substream->stream; int stream = substream->stream;
if (hext_stream->link_prepared) return hda_link_dma_hw_params(substream, &rtd->dpcm[stream].hw_params);
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);
} }
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_sof_widget *swidget = w->dobj.private;
struct snd_soc_component *component = swidget->scomp; 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; return ret;
} }
static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
int cmd, struct snd_soc_dai *dai)
{ {
struct hdac_ext_stream *hext_stream = struct hdac_ext_stream *hext_stream =
snd_soc_dai_get_dma_data(dai, substream); snd_soc_dai_get_dma_data(dai, substream);
struct sof_intel_hda_stream *hda_stream; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
struct snd_soc_pcm_runtime *rtd; struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dapm_widget *w; int stream = substream->stream;
struct hdac_ext_link *link;
struct hdac_stream *hstream;
struct hdac_bus *bus;
int stream_tag;
int ret; int ret;
hstream = substream->runtime->private_data; if (hext_stream && hext_stream->link_prepared)
bus = hstream->bus; return 0;
rtd = asoc_substream_to_rtd(substream);
link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name); dev_dbg(sdev->dev, "prepare stream dir %d\n", substream->stream);
if (!link)
return -EINVAL;
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); 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) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@ -311,95 +480,121 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
break; break;
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP: 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;
/* ret = sof_ipc4_set_pipeline_state(sdev, swidget->pipeline_id,
* free DAI widget during stop/suspend to keep widget use_count's balanced. SOF_IPC4_PIPE_PAUSED);
*/
ret = hda_link_dai_widget_update(hda_stream, w, DMA_CHAN_INVALID, false);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { pipeline->state = SOF_IPC4_PIPE_PAUSED;
stream_tag = hdac_stream(hext_stream)->stream_tag;
snd_hdac_ext_link_clear_stream_id(link, stream_tag); 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; break;
}
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 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) if (ret < 0)
return ret; return ret;
pipeline->state = SOF_IPC4_PIPE_PAUSED;
snd_hdac_ext_link_stream_clear(hext_stream);
break; break;
}
default: default:
dev_err(sdev->dev, "%s: unknown trigger command %d\n", __func__, cmd);
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
} }
static int hda_link_hw_free(struct snd_pcm_substream *substream, static int hda_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) 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; int ret;
hstream = substream->runtime->private_data; ret = hda_link_dma_hw_free(substream);
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);
if (ret < 0) if (ret < 0)
return ret; return ret;
link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name); return hda_dai_hw_free_ipc(substream->stream, dai);
if (!link) }
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { static const struct snd_soc_dai_ops ipc3_hda_dai_ops = {
stream_tag = hdac_stream(hext_stream)->stream_tag; .hw_params = hda_dai_hw_params,
snd_hdac_ext_link_clear_stream_id(link, stream_tag); .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; return 0;
} }
static const struct snd_soc_dai_ops hda_link_dai_ops = { static const struct snd_soc_dai_ops ipc4_hda_dai_ops = {
.hw_params = hda_link_hw_params, .hw_params = hda_dai_hw_params,
.hw_free = hda_link_hw_free, .hw_free = hda_dai_hw_free,
.trigger = hda_link_pcm_trigger, .trigger = ipc4_hda_dai_trigger,
.prepare = hda_link_pcm_prepare, .prepare = hda_dai_prepare,
}; };
#endif #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; struct snd_soc_dapm_widget *w;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) w = snd_soc_dai_get_widget(dai, substream->stream);
w = dai->playback_widget;
else
w = dai->capture_widget;
if (setup) if (setup)
return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE, NULL); 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); return ssp_dai_setup(substream, dai, true);
} }
static int ssp_dai_trigger(struct snd_pcm_substream *substream, static int ipc3_ssp_dai_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai) int cmd, struct snd_soc_dai *dai)
{ {
if (cmd != SNDRV_PCM_TRIGGER_SUSPEND) if (cmd != SNDRV_PCM_TRIGGER_SUSPEND)
return 0; return 0;
@ -507,15 +699,137 @@ static void ssp_dai_shutdown(struct snd_pcm_substream *substream,
kfree(dma_data); 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, .startup = ssp_dai_startup,
.hw_params = ssp_dai_hw_params, .hw_params = ssp_dai_hw_params,
.prepare = ssp_dai_prepare, .prepare = ssp_dai_prepare,
.trigger = ssp_dai_trigger, .trigger = ipc3_ssp_dai_trigger,
.hw_free = ssp_dai_hw_free, .hw_free = ssp_dai_hw_free,
.shutdown = ssp_dai_shutdown, .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. * common dai driver for skl+ platforms.
* some products who use this DAI array only physically have a subset of * 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[] = { struct snd_soc_dai_driver skl_dai[] = {
{ {
.name = "SSP0 Pin", .name = "SSP0 Pin",
.ops = &ssp_dai_ops,
.playback = { .playback = {
.channels_min = 1, .channels_min = 1,
.channels_max = 8, .channels_max = 8,
@ -536,7 +849,6 @@ struct snd_soc_dai_driver skl_dai[] = {
}, },
{ {
.name = "SSP1 Pin", .name = "SSP1 Pin",
.ops = &ssp_dai_ops,
.playback = { .playback = {
.channels_min = 1, .channels_min = 1,
.channels_max = 8, .channels_max = 8,
@ -548,7 +860,6 @@ struct snd_soc_dai_driver skl_dai[] = {
}, },
{ {
.name = "SSP2 Pin", .name = "SSP2 Pin",
.ops = &ssp_dai_ops,
.playback = { .playback = {
.channels_min = 1, .channels_min = 1,
.channels_max = 8, .channels_max = 8,
@ -560,7 +871,6 @@ struct snd_soc_dai_driver skl_dai[] = {
}, },
{ {
.name = "SSP3 Pin", .name = "SSP3 Pin",
.ops = &ssp_dai_ops,
.playback = { .playback = {
.channels_min = 1, .channels_min = 1,
.channels_max = 8, .channels_max = 8,
@ -572,7 +882,6 @@ struct snd_soc_dai_driver skl_dai[] = {
}, },
{ {
.name = "SSP4 Pin", .name = "SSP4 Pin",
.ops = &ssp_dai_ops,
.playback = { .playback = {
.channels_min = 1, .channels_min = 1,
.channels_max = 8, .channels_max = 8,
@ -584,7 +893,6 @@ struct snd_soc_dai_driver skl_dai[] = {
}, },
{ {
.name = "SSP5 Pin", .name = "SSP5 Pin",
.ops = &ssp_dai_ops,
.playback = { .playback = {
.channels_min = 1, .channels_min = 1,
.channels_max = 8, .channels_max = 8,
@ -611,7 +919,6 @@ struct snd_soc_dai_driver skl_dai[] = {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
{ {
.name = "iDisp1 Pin", .name = "iDisp1 Pin",
.ops = &hda_link_dai_ops,
.playback = { .playback = {
.channels_min = 1, .channels_min = 1,
.channels_max = 8, .channels_max = 8,
@ -619,7 +926,6 @@ struct snd_soc_dai_driver skl_dai[] = {
}, },
{ {
.name = "iDisp2 Pin", .name = "iDisp2 Pin",
.ops = &hda_link_dai_ops,
.playback = { .playback = {
.channels_min = 1, .channels_min = 1,
.channels_max = 8, .channels_max = 8,
@ -627,7 +933,6 @@ struct snd_soc_dai_driver skl_dai[] = {
}, },
{ {
.name = "iDisp3 Pin", .name = "iDisp3 Pin",
.ops = &hda_link_dai_ops,
.playback = { .playback = {
.channels_min = 1, .channels_min = 1,
.channels_max = 8, .channels_max = 8,
@ -635,7 +940,6 @@ struct snd_soc_dai_driver skl_dai[] = {
}, },
{ {
.name = "iDisp4 Pin", .name = "iDisp4 Pin",
.ops = &hda_link_dai_ops,
.playback = { .playback = {
.channels_min = 1, .channels_min = 1,
.channels_max = 8, .channels_max = 8,
@ -643,7 +947,6 @@ struct snd_soc_dai_driver skl_dai[] = {
}, },
{ {
.name = "Analog CPU DAI", .name = "Analog CPU DAI",
.ops = &hda_link_dai_ops,
.playback = { .playback = {
.channels_min = 1, .channels_min = 1,
.channels_max = 16, .channels_max = 16,
@ -655,7 +958,6 @@ struct snd_soc_dai_driver skl_dai[] = {
}, },
{ {
.name = "Digital CPU DAI", .name = "Digital CPU DAI",
.ops = &hda_link_dai_ops,
.playback = { .playback = {
.channels_min = 1, .channels_min = 1,
.channels_max = 16, .channels_max = 16,
@ -667,7 +969,6 @@ struct snd_soc_dai_driver skl_dai[] = {
}, },
{ {
.name = "Alt Analog CPU DAI", .name = "Alt Analog CPU DAI",
.ops = &hda_link_dai_ops,
.playback = { .playback = {
.channels_min = 1, .channels_min = 1,
.channels_max = 16, .channels_max = 16,
@ -679,3 +980,22 @@ struct snd_soc_dai_driver skl_dai[] = {
}, },
#endif #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. * 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; unsigned int cpa;
u32 adspcs; u32 adspcs;
int ret; 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 */ /* update bits */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS,
HDA_DSP_ADSPCS_SPA_MASK(core_mask), 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; pm_gate.flags = flags;
/* send pm_gate ipc to dsp */ /* send pm_gate ipc to dsp */
return sof_ipc_tx_message_no_pm(sdev->ipc, pm_gate.hdr.cmd, return sof_ipc_tx_message_no_pm(sdev->ipc, &pm_gate, sizeof(pm_gate),
&pm_gate, sizeof(pm_gate), &reply, &reply, sizeof(reply));
sizeof(reply));
} }
static int hda_dsp_update_d0i3c_register(struct snd_sof_dev *sdev, u8 value) 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 * when the DSP enters D0I3 while the system is in S0
* for debug purpose. * for debug purpose.
*/ */
if (!sdev->dtrace_is_supported || if (!sdev->fw_trace_is_supported ||
!hda_enable_trace_D0I3_S0 || !hda_enable_trace_D0I3_S0 ||
sdev->system_suspend_target != SOF_SUSPEND_NONE) sdev->system_suspend_target != SOF_SUSPEND_NONE)
flags = HDA_PM_NO_DMA_TRACE; flags = HDA_PM_NO_DMA_TRACE;
@ -610,6 +617,13 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
#endif #endif
int ret, j; 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); hda_sdw_int_enable(sdev, false);
/* disable IPC interrupts */ /* disable IPC interrupts */
@ -736,7 +750,7 @@ int hda_dsp_resume(struct snd_sof_dev *sdev)
if (hlink->ref_count) { if (hlink->ref_count) {
ret = snd_hdac_ext_bus_link_power_up(hlink); ret = snd_hdac_ext_bus_link_power_up(hlink);
if (ret < 0) { if (ret < 0) {
dev_dbg(sdev->dev, dev_err(sdev->dev,
"error %d in %s: failed to power up links", "error %d in %s: failed to power up links",
ret, __func__); ret, __func__);
return ret; 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 */ /* no link can be powered in s0ix state */
ret = snd_hdac_ext_bus_link_power_down_all(bus); ret = snd_hdac_ext_bus_link_power_down_all(bus);
if (ret < 0) { if (ret < 0) {
dev_dbg(sdev->dev, dev_err(sdev->dev,
"error %d in %s: failed to power down links", "error %d in %s: failed to power down links",
ret, __func__); ret, __func__);
return ret; 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) int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
{ {
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) int ret;
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;
/* set internal flag for BE */ /* make sure all DAI resources are freed */
list_for_each_entry(s, &bus->stream_list, list) { ret = hda_dsp_dais_suspend(sdev);
hext_stream = stream_to_hdac_ext_stream(s); if (ret < 0)
dev_warn(sdev->dev, "%s: failure in hda_dsp_dais_suspend\n", __func__);
/* return ret;
* 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;
} }
void hda_dsp_d0i3_work(struct work_struct *work) 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) int hda_dsp_core_get(struct snd_sof_dev *sdev, int core)
{ {
struct sof_ipc_pm_core_config pm_core_config = { const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
.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),
};
int ret, ret1; int ret, ret1;
/* power up core */ /* 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) if (sdev->fw_state != SOF_FW_BOOT_COMPLETE || core == SOF_DSP_PRIMARY_CORE)
return 0; 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 */ /* Now notify DSP for secondary cores */
ret = sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd, ret = pm_ops->set_core_state(sdev, core, true);
&pm_core_config, sizeof(pm_core_config),
&pm_core_config, sizeof(pm_core_config));
if (ret < 0) { if (ret < 0) {
dev_err(sdev->dev, "failed to enable secondary core '%d' failed with %d\n", dev_err(sdev->dev, "failed to enable secondary core '%d' failed with %d\n",
core, ret); core, ret);

View File

@ -15,6 +15,7 @@
* Hardware interface for generic Intel audio DSP HDA IP * Hardware interface for generic Intel audio DSP HDA IP
*/ */
#include <sound/sof/ipc4/header.h>
#include "../ops.h" #include "../ops.h"
#include "hda.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; 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) void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
{ {
struct snd_sof_ipc_msg *msg = sdev->msg; 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 */ /* IPC handler thread */
irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) 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 * place, the message might not yet be marked as expecting a
* reply. * 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 */ /* handle immediate reply from DSP core */
hda_dsp_ipc_get_reply(sdev); hda_dsp_ipc_get_reply(sdev);
snd_sof_ipc_reply(sdev, msg); snd_sof_ipc_reply(sdev, msg);
/* set the done bit */ /* set the done bit */
hda_dsp_ipc_dsp_done(sdev); 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; ipc_irq = true;
} }

View File

@ -24,8 +24,6 @@
#include "../sof-priv.h" #include "../sof-priv.h"
#include "hda.h" #include "hda.h"
#define HDA_CL_STREAM_FORMAT 0x40
static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev) static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev)
{ {
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 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, struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format,
unsigned int size, struct snd_dma_buffer *dmab, unsigned int size, struct snd_dma_buffer *dmab,
int direction) int direction)
{ {
struct hdac_ext_stream *hext_stream; struct hdac_ext_stream *hext_stream;
struct hdac_stream *hstream; 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 * first boot sequence has some extra steps.
* status on core 1, so power up core 1 also momentarily, keep it in * power on all host managed cores and only unstall/run the boot core to boot the
* reset/stall and then turn it off * 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; struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc; 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; unsigned long mask;
char *dump_msg; char *dump_msg;
u32 flags, j;
int ret; int ret;
/* step 1: power up corex */ /* 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 (ret < 0) {
if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n"); 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); hda_ssp_set_cbp_cfp(sdev);
/* step 2: purge FW request */ /* step 2: Send ROM_CONTROL command (stream_tag is ignored for IMR boot) */
snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, ipc_hdr = chip->ipc_req_mask | HDA_DSP_ROM_IPC_CONTROL;
chip->ipc_req_mask | (HDA_DSP_IPC_PURGE_FW | if (!imr_boot)
((stream_tag - 1) << 9))); 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 */ /* 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 (ret < 0) {
if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS) if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
dev_err(sdev->dev, 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 */ /* step 6: enable IPC interrupts */
hda_dsp_ipc_int_enable(sdev); 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, 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) ((status & HDA_DSP_ROM_STS_MASK)
== HDA_DSP_ROM_INIT), == target_status),
HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_REG_POLL_INTERVAL_US,
chip->rom_init_timeout * chip->rom_init_timeout *
USEC_PER_MSEC); 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) if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
dev_err(sdev->dev, dev_err(sdev->dev,
"error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", "%s: timeout with rom_status_reg (%#x) read\n",
__func__); __func__, chip->rom_status_reg);
err: err:
flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL; 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, int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
struct hdac_ext_stream *hext_stream) struct hdac_ext_stream *hext_stream)
{ {
struct hdac_stream *hstream = &hext_stream->hstream; struct hdac_stream *hstream = &hext_stream->hstream;
int sd_offset = SOF_STREAM_SD_OFFSET(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; 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; unsigned int reg;
int ret, status; 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, 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) ((reg & HDA_DSP_ROM_STS_MASK)
== HDA_DSP_ROM_FW_ENTERED), == HDA_DSP_ROM_FW_ENTERED),
HDA_DSP_REG_POLL_INTERVAL_US, 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) { if (status < 0) {
dev_err(sdev->dev, dev_err(sdev->dev,
"error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", "%s: timeout with rom_status_reg (%#x) read\n",
__func__); __func__, chip->rom_status_reg);
} }
ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP); 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_ext_stream *iccmax_stream;
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
struct firmware stripped_firmware; struct firmware stripped_firmware;
struct snd_dma_buffer dmab_bdl;
int ret, ret1; int ret, ret1;
u8 original_gb; 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; stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset;
/* prepare capture stream for ICCMAX */ /* prepare capture stream for ICCMAX */
iccmax_stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, iccmax_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size,
&sdev->dmab_bdl, SNDRV_PCM_STREAM_CAPTURE); &dmab_bdl, SNDRV_PCM_STREAM_CAPTURE);
if (IS_ERR(iccmax_stream)) { if (IS_ERR(iccmax_stream)) {
dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n"); dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n");
return PTR_ERR(iccmax_stream); 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. * Perform iccmax stream cleanup. This should be done even if firmware loading fails.
* If the cleanup also fails, we return the initial error * 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) { if (ret1 < 0) {
dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n"); 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) 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_info;
const struct sof_intel_dsp_desc *chip = hda->desc;
unsigned long mask;
u32 j;
int ret; int ret;
/* power up & unstall/run the cores to run the firmware */ chip_info = get_chip_info(sdev->pdata);
ret = hda_dsp_enable_core(sdev, chip->init_core_mask); if (chip_info->cl_init)
if (ret < 0) { ret = chip_info->cl_init(sdev, 0, true);
dev_err(sdev->dev, "dsp core start failed %d\n", ret); else
return -EIO; ret = -EINVAL;
}
/* set enabled cores mask and increment ref count for cores in init_core_mask */ if (!ret)
sdev->enabled_cores_mask |= chip->init_core_mask; hda_sdw_process_wakeen(sdev);
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);
return ret; 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; const struct sof_intel_dsp_desc *chip_info;
struct hdac_ext_stream *hext_stream; struct hdac_ext_stream *hext_stream;
struct firmware stripped_firmware; struct firmware stripped_firmware;
struct snd_dma_buffer dmab;
int ret, ret1, i; int ret, ret1, i;
if ((sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT) && if (hda->imrboot_supported && !sdev->first_boot && !hda->skip_imr_boot) {
!(sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT)) &&
!sdev->first_boot) {
dev_dbg(sdev->dev, "IMR restore supported, booting from IMR directly\n"); 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; 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); init_waitqueue_head(&sdev->boot_wait);
/* prepare DMA for code loader stream */ /* prepare DMA for code loader stream */
hext_stream = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, hext_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT,
&sdev->dmab, SNDRV_PCM_STREAM_PLAYBACK); stripped_firmware.size,
&dmab, SNDRV_PCM_STREAM_PLAYBACK);
if (IS_ERR(hext_stream)) { if (IS_ERR(hext_stream)) {
dev_err(sdev->dev, "error: dma prepare for fw loading failed\n"); dev_err(sdev->dev, "error: dma prepare for fw loading failed\n");
return PTR_ERR(hext_stream); return PTR_ERR(hext_stream);
} }
memcpy(sdev->dmab.area, stripped_firmware.data, memcpy(dmab.area, stripped_firmware.data,
stripped_firmware.size); stripped_firmware.size);
/* try ROM init a few times before giving up */ /* 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); "Attempting iteration %d of Core En/ROM load...\n", i);
hda->boot_iteration = i + 1; 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 */ /* don't retry anymore if successful */
if (!ret) if (!ret)
@ -473,12 +478,15 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
* Continue with code loading and firmware boot * Continue with code loading and firmware boot
*/ */
hda->boot_iteration = HDA_FW_BOOT_ATTEMPTS; hda->boot_iteration = HDA_FW_BOOT_ATTEMPTS;
ret = cl_copy_fw(sdev, hext_stream); ret = hda_cl_copy_fw(sdev, hext_stream);
if (!ret) if (!ret) {
dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); 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", snd_sof_dsp_dbg_dump(sdev, "Firmware download failed",
SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX); SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX);
hda->skip_imr_boot = true;
}
cleanup: 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. * This should be done even if firmware loading fails.
* If the cleanup also fails, we return the initial error * 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) { if (ret1 < 0) {
dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); 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; int ret;
if (sdev->first_boot) { if (sdev->first_boot) {
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
ret = hda_sdw_startup(sdev); ret = hda_sdw_startup(sdev);
if (ret < 0) { if (ret < 0) {
dev_err(sdev->dev, dev_err(sdev->dev,
"error: could not startup SoundWire links\n"); "error: could not startup SoundWire links\n");
return ret; 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); 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; goto found;
} }
switch (sof_hda_position_quirk) { pos = hda_dsp_stream_get_position(hstream, substream->stream, true);
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;
found: found:
pos = bytes_to_frames(substream->runtime, pos); 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; return cstream->runtime->private_data;
} }
static int hda_probes_compr_assign(struct sof_client_dev *cdev, static int hda_probes_compr_startup(struct sof_client_dev *cdev,
struct snd_compr_stream *cstream, struct snd_compr_stream *cstream,
struct snd_soc_dai *dai, u32 *stream_id) struct snd_soc_dai *dai, u32 *stream_id)
{ {
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
struct hdac_ext_stream *hext_stream; struct hdac_ext_stream *hext_stream;
@ -45,9 +45,9 @@ static int hda_probes_compr_assign(struct sof_client_dev *cdev,
return 0; return 0;
} }
static int hda_probes_compr_free(struct sof_client_dev *cdev, static int hda_probes_compr_shutdown(struct sof_client_dev *cdev,
struct snd_compr_stream *cstream, struct snd_compr_stream *cstream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream); struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream);
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 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 */ /* SOF client implementation */
static const struct sof_probes_host_ops hda_probes_ops = { static const struct sof_probes_host_ops hda_probes_ops = {
.assign = hda_probes_compr_assign, .startup = hda_probes_compr_startup,
.free = hda_probes_compr_free, .shutdown = hda_probes_compr_shutdown,
.set_params = hda_probes_compr_set_params, .set_params = hda_probes_compr_set_params,
.trigger = hda_probes_compr_trigger, .trigger = hda_probes_compr_trigger,
.pointer = hda_probes_compr_pointer, .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; int remain, ioc;
period_bytes = hstream->period_bytes; 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) if (!period_bytes)
period_bytes = hstream->bufsize; period_bytes = hstream->bufsize;
periods = hstream->bufsize / period_bytes; 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; remain = hstream->bufsize % period_bytes;
if (remain) 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); HDA_VS_INTEL_EM2_L1SEN, HDA_VS_INTEL_EM2_L1SEN);
if (!found) { 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); __func__, stream_tag);
return -ENODEV; return -ENODEV;
} }
@ -411,6 +411,11 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
return -ENODEV; return -ENODEV;
} }
if (!dmab) {
dev_err(sdev->dev, "error: no dma buffer allocated!\n");
return -ENODEV;
}
if (hstream->posbuf) if (hstream->posbuf)
*hstream->posbuf = 0; *hstream->posbuf = 0;
@ -485,16 +490,16 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
return -ENODEV; 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) { if (!dmab) {
dev_err(sdev->dev, "error: no dma buffer allocated!\n"); dev_err(sdev->dev, "error: no dma buffer allocated!\n");
return -ENODEV; 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 */ /* clear stream status */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
SOF_HDA_CL_DMA_SD_INT_MASK | SOF_HDA_CL_DMA_SD_INT_MASK |
@ -707,12 +712,13 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
} }
static void 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; u64 prev_pos, pos, num_bytes;
div64_u64_rem(hstream->curr_pos, buffer_size, &prev_pos); 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) if (pos < prev_pos)
num_bytes = (buffer_size - prev_pos) + 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) { if (s->substream && sof_hda->no_ipc_position) {
snd_sof_pcm_period_elapsed(s->substream); snd_sof_pcm_period_elapsed(s->substream);
} else if (s->cstream) { } else if (s->cstream) {
hda_dsp_set_bytes_transferred(s, hda_dsp_compr_bytes_transferred(s, s->cstream->direction);
s->cstream->runtime->buffer_size);
snd_compr_fragment_elapsed(s->cstream); 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); 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; 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_ipc_dma_trace_params_ext *dtrace_params)
{ {
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; 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 * initialize capture stream, set BDL address and return corresponding
* stream tag which will be sent to the firmware by IPC message. * 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) { if (ret < 0) {
dev_err(sdev->dev, "error: hdac trace init failed: %d\n", ret); dev_err(sdev->dev, "error: hdac trace init failed: %d\n", ret);
hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_CAPTURE, 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); 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, .params_stream = sdw_params_stream,
.free_stream = sdw_free_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 { struct hda_dsp_msg_code {
u32 code; u32 code;
const char *msg; const char *text;
}; };
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG) #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"); MODULE_PARM_DESC(use_common_hdmi, "SOF HDA use common HDMI codec driver");
#endif #endif
static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = { static const struct hda_dsp_msg_code hda_dsp_rom_fw_error_texts[] = {
{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"},
{HDA_DSP_ROM_CSE_ERROR, "error: cse error"}, {HDA_DSP_ROM_CSE_ERROR, "error: cse error"},
{HDA_DSP_ROM_CSE_WRONG_RESPONSE, "error: cse wrong response"}, {HDA_DSP_ROM_CSE_WRONG_RESPONSE, "error: cse wrong response"},
{HDA_DSP_ROM_IMR_TO_SMALL, "error: IMR too small"}, {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"}, {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; int i;
status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, for (i = 0; i < array_size; i++) {
HDA_DSP_SRAM_REG_ROM_STATUS); if (code == msg_code[i].code)
return msg_code[i].text;
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;
}
} }
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 */ /* 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, 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, static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, const char *level,
u32 flags) u32 flags)
{ {
const struct sof_intel_dsp_desc *chip;
char msg[128]; char msg[128];
int len = 0; int len = 0;
u32 value; u32 value;
int i; int i;
chip = get_chip_info(sdev->pdata);
for (i = 0; i < HDA_EXT_ROM_STATUS_SIZE; i++) { 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); value = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg + i * 0x4);
len += snprintf(msg + len, sizeof(msg) - len, " 0x%x", value); len += scnprintf(msg + len, sizeof(msg) - len, " 0x%x", value);
} }
dev_printk(level, sdev->dev, "extended rom status: %s", msg); 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]; u32 stack[HDA_DSP_STACK_DUMP_SIZE];
/* print ROM/FW status */ /* print ROM/FW status */
hda_dsp_get_status(sdev, level); hda_dsp_get_state(sdev, level);
if (flags & SOF_DBG_DUMP_REGS) { if (flags & SOF_DBG_DUMP_REGS) {
u32 status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_STATUS); 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) void hda_ipc_irq_dump(struct snd_sof_dev *sdev)
{ {
struct hdac_bus *bus = sof_to_bus(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) 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; struct nhlt_acpi_table *nhlt;
int dmic_num = 0; int dmic_num = 0;
nhlt = intel_nhlt_init(sdev->dev); nhlt = hdev->nhlt;
if (nhlt) { if (nhlt)
dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt); dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt);
intel_nhlt_free(nhlt);
}
/* allow for module parameter override */ /* allow for module parameter override */
if (dmic_num_override != -1) { 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) 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; struct nhlt_acpi_table *nhlt;
int ssp_mask = 0; int ssp_mask = 0;
nhlt = intel_nhlt_init(sdev->dev); nhlt = hdev->nhlt;
if (!nhlt) if (!nhlt)
return ssp_mask; return ssp_mask;
@ -623,7 +745,6 @@ static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev)
if (ssp_mask) if (ssp_mask)
dev_info(sdev->dev, "NHLT_DEVICE_I2S detected, ssp_mask %#x\n", ssp_mask); dev_info(sdev->dev, "NHLT_DEVICE_I2S detected, ssp_mask %#x\n", ssp_mask);
} }
intel_nhlt_free(nhlt);
return ssp_mask; return ssp_mask;
} }
@ -655,13 +776,12 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
return tplg_filename; return tplg_filename;
} }
static int dmic_topology_fixup(struct snd_sof_dev *sdev, static int dmic_detect_topology_fixup(struct snd_sof_dev *sdev,
const char **tplg_filename, const char **tplg_filename,
const char *idisp_str, const char *idisp_str,
int *dmic_found) int *dmic_found,
bool tplg_fixup)
{ {
const char *default_tplg_filename = *tplg_filename;
const char *fixed_tplg_filename;
const char *dmic_str; const char *dmic_str;
int dmic_num; int dmic_num;
@ -687,14 +807,19 @@ static int dmic_topology_fixup(struct snd_sof_dev *sdev,
break; break;
} }
fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename, if (tplg_fixup) {
idisp_str, dmic_str); const char *default_tplg_filename = *tplg_filename;
if (!fixed_tplg_filename) const char *fixed_tplg_filename;
return -ENOMEM;
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); dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num);
*dmic_found = dmic_num; *dmic_found = dmic_num;
*tplg_filename = fixed_tplg_filename;
return 0; return 0;
} }
@ -816,7 +941,7 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context)
if (hda_dsp_check_stream_irq(sdev)) if (hda_dsp_check_stream_irq(sdev))
hda_dsp_stream_threaded_handler(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); sof_ops(sdev)->irq_thread(irq, sdev);
if (hda_dsp_check_sdw_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); INIT_DELAYED_WORK(&hdev->d0i3_work, hda_dsp_d0i3_work);
hdev->nhlt = intel_nhlt_init(sdev->dev);
return 0; return 0;
free_ipc_irq: 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; const struct sof_intel_dsp_desc *chip = hda->desc;
struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_bus *bus = sof_to_bus(sdev);
struct pci_dev *pci = to_pci_dev(sdev->dev); 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 any attempt for DSP D0I3 */
cancel_delayed_work_sync(&hda->d0i3_work); 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 * - one external HDAudio codec
*/ */
if (!*mach && codec_num <= 2) { if (!*mach && codec_num <= 2) {
bool tplg_fixup;
hda_mach = snd_soc_acpi_intel_hda_machines; hda_mach = snd_soc_acpi_intel_hda_machines;
dev_info(bus->dev, "using HDA machine driver %s now\n", 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 = ""; idisp_str = "";
/* topology: use the info from hda_machines */ /* topology: use the info from hda_machines */
tplg_filename = hda_mach->sof_tplg_filename; if (pdata->tplg_filename) {
ret = dmic_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num); 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) if (ret < 0)
return; 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) { if (mach && mach->link_mask) {
int dmic_num = 0; int dmic_num = 0;
bool tplg_fixup;
const char *tplg_filename;
mach->mach_params.links = mach->links; mach->mach_params.links = mach->links;
mach->mach_params.link_mask = mach->link_mask; mach->mach_params.link_mask = mach->link_mask;
mach->mach_params.platform = dev_name(sdev->dev); 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 * 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 * link 2 and 3, or link 1 and 2, thus we only try to enable dmics
* are true: * if all conditions are true:
* a) link 2 and 3 are not used by SoundWire * a) 2 or fewer links are used by SoundWire
* b) the NHLT table reports the presence of microphones * b) the NHLT table reports the presence of microphones
*/ */
if (!(mach->link_mask & GENMASK(3, 2))) { if (hweight_long(mach->link_mask) <= 2) {
const char *tplg_filename = mach->sof_tplg_filename;
int ret; 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) if (ret < 0)
return NULL; return NULL;
pdata->tplg_filename = tplg_filename;
} }
if (tplg_fixup)
pdata->tplg_filename = tplg_filename;
mach->mach_params.dmic_num = dmic_num; mach->mach_params.dmic_num = dmic_num;
dev_dbg(sdev->dev, 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); mach = snd_soc_acpi_find_machine(desc->machines);
if (mach) { if (mach) {
bool add_extension = false; bool add_extension = false;
bool tplg_fixup = false;
/* /*
* If tplg file name is overridden, use it instead of * If tplg file name is overridden, use it instead of
* the one set in mach table * the one set in mach table
*/ */
if (!sof_pdata->tplg_filename) if (!sof_pdata->tplg_filename) {
sof_pdata->tplg_filename = mach->sof_tplg_filename; sof_pdata->tplg_filename = mach->sof_tplg_filename;
tplg_fixup = true;
}
/* report to machine driver if any DMICs are found */ /* report to machine driver if any DMICs are found */
mach->mach_params.dmic_num = check_dmic_num(sdev); 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) { mach->mach_params.dmic_num) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s%d%s", "%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 */ /* report SSP link mask to machine driver */
mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev); 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) { mach->mach_params.i2s_link_mask) {
const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);
int ssp_num; int ssp_num;
if (hweight_long(mach->mach_params.i2s_link_mask) > 1 && 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 */ /* fls returns 1-based results, SSPs indices are 0-based */
ssp_num = fls(mach->mach_params.i2s_link_mask) - 1; 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, tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s%d", "%s%s%d",
sof_pdata->tplg_filename, sof_pdata->tplg_filename,
@ -1396,7 +1555,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
add_extension = true; add_extension = true;
} }
if (add_extension) { if (tplg_fixup && add_extension) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s", "%s%s",
sof_pdata->tplg_filename, sof_pdata->tplg_filename,

View File

@ -187,6 +187,69 @@
#define HDA_DSP_STACK_DUMP_SIZE 32 #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 */ /* ROM status/error values */
#define HDA_DSP_ROM_STS_MASK GENMASK(23, 0) #define HDA_DSP_ROM_STS_MASK GENMASK(23, 0)
#define HDA_DSP_ROM_INIT 0x1 #define HDA_DSP_ROM_INIT 0x1
@ -210,7 +273,9 @@
#define HDA_DSP_ROM_USER_EXCEPTION 0xBEEF0000 #define HDA_DSP_ROM_USER_EXCEPTION 0xBEEF0000
#define HDA_DSP_ROM_UNEXPECTED_RESET 0xDECAF000 #define HDA_DSP_ROM_UNEXPECTED_RESET 0xDECAF000
#define HDA_DSP_ROM_NULL_FW_ENTRY 0x4c4c4e55 #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 */ /* various timeout values */
#define HDA_DSP_PU_TIMEOUT 50 #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_INTERVAL_US 500 /* 0.5 msec */
#define HDA_DSP_REG_POLL_RETRY_COUNT 50 #define HDA_DSP_REG_POLL_RETRY_COUNT 50
#define HDA_DSP_ADSPIC_IPC 1 #define HDA_DSP_ADSPIC_IPC BIT(0)
#define HDA_DSP_ADSPIS_IPC 1 #define HDA_DSP_ADSPIS_IPC BIT(0)
/* Intel HD Audio General DSP Registers */ /* Intel HD Audio General DSP Registers */
#define HDA_DSP_GEN_BASE 0x0 #define HDA_DSP_GEN_BASE 0x0
@ -268,8 +333,8 @@
/* HIPCTE */ /* HIPCTE */
#define HDA_DSP_REG_HIPCTE_MSG_MASK 0x3FFFFFFF #define HDA_DSP_REG_HIPCTE_MSG_MASK 0x3FFFFFFF
#define HDA_DSP_ADSPIC_CL_DMA 0x2 #define HDA_DSP_ADSPIC_CL_DMA BIT(1)
#define HDA_DSP_ADSPIS_CL_DMA 0x2 #define HDA_DSP_ADSPIS_CL_DMA BIT(1)
/* Delay before scheduling D0i3 entry */ /* Delay before scheduling D0i3 entry */
#define BXT_D0I3_DELAY 5000 #define BXT_D0I3_DELAY 5000
@ -416,6 +481,9 @@ enum sof_hda_D0_substate {
/* represents DSP HDA controller frontend - i.e. host facing control */ /* represents DSP HDA controller frontend - i.e. host facing control */
struct sof_intel_hda_dev { struct sof_intel_hda_dev {
bool imrboot_supported;
bool skip_imr_boot;
int boot_iteration; int boot_iteration;
struct hda_bus hbus; struct hda_bus hbus;
@ -449,6 +517,9 @@ struct sof_intel_hda_dev {
/* FW clock config, 0:HPRO, 1:LPRO */ /* FW clock config, 0:HPRO, 1:LPRO */
bool clk_config_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) 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_probe(struct snd_sof_dev *sdev);
int hda_dsp_remove(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_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_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask);
int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, 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_ipc_irq(struct snd_sof_dev *sdev);
bool hda_dsp_check_stream_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 * struct hdac_ext_stream *
hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags); 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); 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(struct snd_sof_dev *sdev);
int hda_dsp_cl_boot_firmware_iccmax(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 */ /* pre and post fw run ops */
int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev); 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. * 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); struct sof_ipc_dma_trace_params_ext *dtrace_params);
int hda_dsp_trace_release(struct snd_sof_dev *sdev); int hda_dsp_trace_release(struct snd_sof_dev *sdev);
int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd); 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 */ /* common dai driver */
extern struct snd_soc_dai_driver skl_dai[]; extern struct snd_soc_dai_driver skl_dai[];
int hda_dsp_dais_suspend(struct snd_sof_dev *sdev);
/* /*
* Platform Specific HW abstraction Ops. * Platform Specific HW abstraction Ops.
*/ */
extern const struct snd_sof_dsp_ops sof_apl_ops; extern struct snd_sof_dsp_ops sof_hda_common_ops;
extern const struct snd_sof_dsp_ops sof_cnl_ops;
extern const struct snd_sof_dsp_ops sof_tgl_ops; extern struct snd_sof_dsp_ops sof_apl_ops;
extern const struct snd_sof_dsp_ops sof_icl_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 apl_chip_info;
extern const struct sof_intel_dsp_desc cnl_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 icl_chip_info;
extern const struct sof_intel_dsp_desc tgl_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 tglh_chip_info;
extern const struct sof_intel_dsp_desc ehl_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 jsl_chip_info;
extern const struct sof_intel_dsp_desc adls_chip_info; extern const struct sof_intel_dsp_desc adls_chip_info;
extern const struct sof_intel_dsp_desc mtl_chip_info;
/* Probes support */ /* Probes support */
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) #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; 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 #endif

View File

@ -56,11 +56,18 @@ static int icl_dsp_post_fw_run(struct snd_sof_dev *sdev)
int ret; int ret;
if (sdev->first_boot) { if (sdev->first_boot) {
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
ret = hda_sdw_startup(sdev); ret = hda_sdw_startup(sdev);
if (ret < 0) { if (ret < 0) {
dev_err(sdev->dev, "error: could not startup SoundWire links\n"); dev_err(sdev->dev, "error: could not startup SoundWire links\n");
return ret; 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); hda_sdw_int_enable(sdev, true);
@ -88,109 +95,44 @@ static int icl_dsp_post_fw_run(struct snd_sof_dev *sdev)
} }
/* Icelake ops */ /* 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/remove/shutdown */
.probe = hda_dsp_probe, sof_icl_ops.shutdown = hda_dsp_shutdown;
.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 */ /* doorbell */
.irq_thread = cnl_ipc_irq_thread, sof_icl_ops.irq_thread = cnl_ipc_irq_thread;
/* ipc */ /* ipc */
.send_msg = cnl_ipc_send_msg, sof_icl_ops.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,
/* debug */ /* debug */
.debug_map = icl_dsp_debugfs, sof_icl_ops.debug_map = icl_dsp_debugfs;
.debug_map_count = ARRAY_SIZE(icl_dsp_debugfs), sof_icl_ops.debug_map_count = ARRAY_SIZE(icl_dsp_debugfs);
.dbg_dump = hda_dsp_dump, sof_icl_ops.ipc_dump = cnl_ipc_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,
/* pre/post fw run */ /* pre/post fw run */
.pre_fw_run = hda_dsp_pre_fw_run, sof_icl_ops.post_fw_run = icl_dsp_post_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,
/* firmware run */ /* firmware run */
.run = hda_dsp_cl_boot_firmware_iccmax, sof_icl_ops.run = hda_dsp_cl_boot_firmware_iccmax;
.stall = icl_dsp_core_stall, sof_icl_ops.stall = icl_dsp_core_stall;
/* trace callback */ /* dsp core get/put */
.trace_init = hda_dsp_trace_init, sof_icl_ops.core_get = hda_dsp_core_get;
.trace_release = hda_dsp_trace_release,
.trace_trigger = hda_dsp_trace_trigger,
/* client ops */ /* set DAI driver ops */
.register_ipc_clients = hda_register_clients, hda_set_dai_drv_ops(sdev, &sof_icl_ops);
.unregister_ipc_clients = hda_unregister_clients,
/* DAI drivers */ return 0;
.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,
}; };
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 = { const struct sof_intel_dsp_desc icl_chip_info = {
/* Icelake */ /* Icelake */
@ -202,11 +144,15 @@ const struct sof_intel_dsp_desc icl_chip_info = {
.ipc_ack = CNL_DSP_REG_HIPCIDA, .ipc_ack = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL, .ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300, .rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT, .ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET, .ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE, .sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE, .sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq, .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); 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, .resindex_imr_base = -1,
.irqindex_host_ipc = -1, .irqindex_host_ipc = -1,
.chip_info = &apl_chip_info, .chip_info = &apl_chip_info,
.default_fw_path = "intel/sof", .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.default_tplg_path = "intel/sof-tplg", .ipc_default = SOF_IPC,
.default_fw_filename = "sof-apl.ri", .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", .nocodec_tplg_filename = "sof-apl-nocodec.tplg",
.ops = &sof_apl_ops, .ops = &sof_apl_ops,
.ops_init = sof_apl_ops_init,
.ops_free = hda_ops_free,
}; };
static const struct sof_dev_desc glk_desc = { static const struct sof_dev_desc glk_desc = {
@ -42,11 +55,23 @@ static const struct sof_dev_desc glk_desc = {
.resindex_imr_base = -1, .resindex_imr_base = -1,
.irqindex_host_ipc = -1, .irqindex_host_ipc = -1,
.chip_info = &apl_chip_info, .chip_info = &apl_chip_info,
.default_fw_path = "intel/sof", .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.default_tplg_path = "intel/sof-tplg", .ipc_default = SOF_IPC,
.default_fw_filename = "sof-glk.ri", .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", .nocodec_tplg_filename = "sof-glk-nocodec.tplg",
.ops = &sof_apl_ops, .ops = &sof_apl_ops,
.ops_init = sof_apl_ops_init,
}; };
/* PCI IDs */ /* PCI IDs */

View File

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

View File

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

View File

@ -28,11 +28,23 @@ static const struct sof_dev_desc tgl_desc = {
.resindex_imr_base = -1, .resindex_imr_base = -1,
.irqindex_host_ipc = -1, .irqindex_host_ipc = -1,
.chip_info = &tgl_chip_info, .chip_info = &tgl_chip_info,
.default_fw_path = "intel/sof", .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.default_tplg_path = "intel/sof-tplg", .ipc_default = SOF_IPC,
.default_fw_filename = "sof-tgl.ri", .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", .nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
.ops = &sof_tgl_ops, .ops = &sof_tgl_ops,
.ops_init = sof_tgl_ops_init,
}; };
static const struct sof_dev_desc tglh_desc = { static const struct sof_dev_desc tglh_desc = {
@ -44,11 +56,24 @@ static const struct sof_dev_desc tglh_desc = {
.resindex_imr_base = -1, .resindex_imr_base = -1,
.irqindex_host_ipc = -1, .irqindex_host_ipc = -1,
.chip_info = &tglh_chip_info, .chip_info = &tglh_chip_info,
.default_fw_path = "intel/sof", .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.default_tplg_path = "intel/sof-tplg", .ipc_default = SOF_IPC,
.default_fw_filename = "sof-tgl-h.ri", .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", .nocodec_tplg_filename = "sof-tgl-nocodec.tplg",
.ops = &sof_tgl_ops, .ops = &sof_tgl_ops,
.ops_init = sof_tgl_ops_init,
.ops_free = hda_ops_free,
}; };
static const struct sof_dev_desc ehl_desc = { static const struct sof_dev_desc ehl_desc = {
@ -59,11 +84,23 @@ static const struct sof_dev_desc ehl_desc = {
.resindex_imr_base = -1, .resindex_imr_base = -1,
.irqindex_host_ipc = -1, .irqindex_host_ipc = -1,
.chip_info = &ehl_chip_info, .chip_info = &ehl_chip_info,
.default_fw_path = "intel/sof", .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.default_tplg_path = "intel/sof-tplg", .ipc_default = SOF_IPC,
.default_fw_filename = "sof-ehl.ri", .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", .nocodec_tplg_filename = "sof-ehl-nocodec.tplg",
.ops = &sof_tgl_ops, .ops = &sof_tgl_ops,
.ops_init = sof_tgl_ops_init,
}; };
static const struct sof_dev_desc adls_desc = { static const struct sof_dev_desc adls_desc = {
@ -75,11 +112,23 @@ static const struct sof_dev_desc adls_desc = {
.resindex_imr_base = -1, .resindex_imr_base = -1,
.irqindex_host_ipc = -1, .irqindex_host_ipc = -1,
.chip_info = &adls_chip_info, .chip_info = &adls_chip_info,
.default_fw_path = "intel/sof", .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.default_tplg_path = "intel/sof-tplg", .ipc_default = SOF_IPC,
.default_fw_filename = "sof-adl-s.ri", .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", .nocodec_tplg_filename = "sof-adl-nocodec.tplg",
.ops = &sof_tgl_ops, .ops = &sof_tgl_ops,
.ops_init = sof_tgl_ops_init,
}; };
static const struct sof_dev_desc adl_desc = { static const struct sof_dev_desc adl_desc = {
@ -91,11 +140,23 @@ static const struct sof_dev_desc adl_desc = {
.resindex_imr_base = -1, .resindex_imr_base = -1,
.irqindex_host_ipc = -1, .irqindex_host_ipc = -1,
.chip_info = &tgl_chip_info, .chip_info = &tgl_chip_info,
.default_fw_path = "intel/sof", .ipc_supported_mask = BIT(SOF_IPC) | BIT(SOF_INTEL_IPC4),
.default_tplg_path = "intel/sof-tplg", .ipc_default = SOF_IPC,
.default_fw_filename = "sof-adl.ri", .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", .nocodec_tplg_filename = "sof-adl-nocodec.tplg",
.ops = &sof_tgl_ops, .ops = &sof_tgl_ops,
.ops_init = sof_tgl_ops_init,
}; };
/* PCI IDs */ /* PCI IDs */
@ -116,6 +177,12 @@ static const struct pci_device_id sof_pci_ids[] = {
.driver_data = (unsigned long)&adl_desc}, .driver_data = (unsigned long)&adl_desc},
{ PCI_DEVICE(0x8086, 0x51cd), /* ADL-P */ { PCI_DEVICE(0x8086, 0x51cd), /* ADL-P */
.driver_data = (unsigned long)&adl_desc}, .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 */ { PCI_DEVICE(0x8086, 0x51cc), /* ADL-M */
.driver_data = (unsigned long)&adl_desc}, .driver_data = (unsigned long)&adl_desc},
{ PCI_DEVICE(0x8086, 0x54c8), /* ADL-N */ { 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_LICENSE("Dual BSD/GPL");
MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); 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 */ /* LPE base */
base = pci_resource_start(pci, desc->resindex_lpe_base) - IRAM_OFFSET; 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); 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); 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; return ret;
} }
const struct snd_sof_dsp_ops sof_tng_ops = { struct snd_sof_dsp_ops sof_tng_ops = {
/* device init */ /* device init */
.probe = tangier_pci_probe, .probe = tangier_pci_probe,
@ -160,7 +164,6 @@ const struct snd_sof_dsp_ops sof_tng_ops = {
/* ipc */ /* ipc */
.send_msg = atom_send_msg, .send_msg = atom_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = atom_get_mailbox_offset, .get_mailbox_offset = atom_get_mailbox_offset,
.get_window_offset = atom_get_window_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_open = sof_stream_pcm_open,
.pcm_close = sof_stream_pcm_close, .pcm_close = sof_stream_pcm_close,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
/*Firmware loading */ /*Firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .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 = { const struct sof_intel_dsp_desc tng_chip_info = {
.cores_num = 1, .cores_num = 1,
.host_managed_cores_mask = 1, .host_managed_cores_mask = 1,
.hw_ip_version = SOF_INTEL_TANGIER,
}; };
static const struct sof_dev_desc tng_desc = { static const struct sof_dev_desc tng_desc = {
@ -215,9 +216,17 @@ static const struct sof_dev_desc tng_desc = {
.resindex_imr_base = 0, .resindex_imr_base = 0,
.irqindex_host_ipc = -1, .irqindex_host_ipc = -1,
.chip_info = &tng_chip_info, .chip_info = &tng_chip_info,
.default_fw_path = "intel/sof", .ipc_supported_mask = BIT(SOF_IPC),
.default_tplg_path = "intel/sof-tplg", .ipc_default = SOF_IPC,
.default_fw_filename = "sof-byt.ri", .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", .nocodec_tplg_filename = "sof-byt.tplg",
.ops = &sof_tng_ops, .ops = &sof_tng_ops,
}; };

View File

@ -11,6 +11,18 @@
#ifndef __SOF_INTEL_SHIM_H #ifndef __SOF_INTEL_SHIM_H
#define __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 * SHIM registers for BYT, BSW, CHT, BDW
*/ */
@ -164,16 +176,20 @@ struct sof_intel_dsp_desc {
int ipc_ack; int ipc_ack;
int ipc_ack_mask; int ipc_ack_mask;
int ipc_ctl; int ipc_ctl;
int rom_status_reg;
int rom_init_timeout; int rom_init_timeout;
int ssp_count; /* ssp count of the platform */ int ssp_count; /* ssp count of the platform */
int ssp_base_offset; /* base address of the SSPs */ int ssp_base_offset; /* base address of the SSPs */
u32 sdw_shim_base; u32 sdw_shim_base;
u32 sdw_alh_base; u32 sdw_alh_base;
u32 quirks; u32 quirks;
enum sof_intel_hw_ip_version hw_ip_version;
bool (*check_sdw_irq)(struct snd_sof_dev *sdev); 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; extern const struct sof_intel_dsp_desc tng_chip_info;

View File

@ -9,6 +9,8 @@
* Hardware interface for audio DSP on Tigerlake. * Hardware interface for audio DSP on Tigerlake.
*/ */
#include <sound/sof/ext_manifest4.h>
#include "../ipc4-priv.h"
#include "../ops.h" #include "../ops.h"
#include "hda.h" #include "hda.h"
#include "hda-ipc.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) static int tgl_dsp_core_get(struct snd_sof_dev *sdev, int core)
{ {
struct sof_ipc_pm_core_config pm_core_config = { const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
.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),
};
/* power up primary core if not already powered up and return */ /* power up primary core if not already powered up and return */
if (core == SOF_DSP_PRIMARY_CORE) if (core == SOF_DSP_PRIMARY_CORE)
return hda_dsp_enable_core(sdev, BIT(core)); return hda_dsp_enable_core(sdev, BIT(core));
/* notify DSP for secondary cores */ if (pm_ops->set_core_state)
return sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd, return pm_ops->set_core_state(sdev, core, true);
&pm_core_config, sizeof(pm_core_config),
&pm_core_config, sizeof(pm_core_config)); return 0;
} }
static int tgl_dsp_core_put(struct snd_sof_dev *sdev, int core) static int tgl_dsp_core_put(struct snd_sof_dev *sdev, int core)
{ {
struct sof_ipc_pm_core_config pm_core_config = { const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
.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),
};
/* power down primary core and return */ /* power down primary core and return */
if (core == SOF_DSP_PRIMARY_CORE) if (core == SOF_DSP_PRIMARY_CORE)
return hda_dsp_core_reset_power_down(sdev, BIT(core)); return hda_dsp_core_reset_power_down(sdev, BIT(core));
/* notify DSP for secondary cores */ if (pm_ops->set_core_state)
return sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd, return pm_ops->set_core_state(sdev, core, false);
&pm_core_config, sizeof(pm_core_config),
&pm_core_config, sizeof(pm_core_config)); return 0;
} }
/* Tigerlake ops */ /* 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/remove/shutdown */
.probe = hda_dsp_probe, sof_tgl_ops.shutdown = hda_dsp_shutdown;
.remove = hda_dsp_remove,
.shutdown = hda_dsp_shutdown,
/* Register IO */ if (sdev->pdata->ipc_type == SOF_IPC) {
.write = sof_io_write, /* doorbell */
.read = sof_io_read, sof_tgl_ops.irq_thread = cnl_ipc_irq_thread;
.write64 = sof_io_write64,
.read64 = sof_io_read64,
/* Block IO */ /* ipc */
.block_read = sof_block_read, sof_tgl_ops.send_msg = cnl_ipc_send_msg;
.block_write = sof_block_write, }
/* Mailbox IO */ if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
.mailbox_read = sof_mailbox_read, struct sof_ipc4_fw_data *ipc4_data;
.mailbox_write = sof_mailbox_write,
/* doorbell */ sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
.irq_thread = cnl_ipc_irq_thread, if (!sdev->private)
return -ENOMEM;
/* ipc */ ipc4_data = sdev->private;
.send_msg = cnl_ipc_send_msg, ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
.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, /* doorbell */
.set_stream_data_offset = hda_set_stream_data_offset, sof_tgl_ops.irq_thread = cnl_ipc4_irq_thread;
/* machine driver */ /* ipc */
.machine_select = hda_machine_select, sof_tgl_ops.send_msg = cnl_ipc4_send_msg;
.machine_register = sof_machine_register, }
.machine_unregister = sof_machine_unregister,
.set_mach_params = hda_set_mach_params, /* set DAI driver ops */
hda_set_dai_drv_ops(sdev, &sof_tgl_ops);
/* debug */ /* debug */
.debug_map = tgl_dsp_debugfs, sof_tgl_ops.debug_map = tgl_dsp_debugfs;
.debug_map_count = ARRAY_SIZE(tgl_dsp_debugfs), sof_tgl_ops.debug_map_count = ARRAY_SIZE(tgl_dsp_debugfs);
.dbg_dump = hda_dsp_dump, sof_tgl_ops.ipc_dump = cnl_ipc_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,
/* pre/post fw run */ /* pre/post fw run */
.pre_fw_run = hda_dsp_pre_fw_run, sof_tgl_ops.post_fw_run = hda_dsp_post_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,
/* firmware run */ /* firmware run */
.run = hda_dsp_cl_boot_firmware_iccmax, sof_tgl_ops.run = hda_dsp_cl_boot_firmware_iccmax;
/* trace callback */ /* dsp core get/put */
.trace_init = hda_dsp_trace_init, sof_tgl_ops.core_get = tgl_dsp_core_get;
.trace_release = hda_dsp_trace_release, sof_tgl_ops.core_put = tgl_dsp_core_put;
.trace_trigger = hda_dsp_trace_trigger,
/* client ops */ return 0;
.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,
}; };
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 = { const struct sof_intel_dsp_desc tgl_chip_info = {
/* Tigerlake , Alderlake */ /* Tigerlake , Alderlake */
@ -175,12 +119,16 @@ const struct sof_intel_dsp_desc tgl_chip_info = {
.ipc_ack = CNL_DSP_REG_HIPCIDA, .ipc_ack = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL, .ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300, .rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT, .ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET, .ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE, .sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE, .sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq, .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); 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 = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL, .ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300, .rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT, .ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET, .ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE, .sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE, .sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq, .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); 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 = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL, .ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300, .rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT, .ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET, .ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE, .sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE, .sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq, .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); 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 = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL, .ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_status_reg = HDA_DSP_SRAM_REG_ROM_STATUS,
.rom_init_timeout = 300, .rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT, .ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET, .ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE, .sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE, .sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq, .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); 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-priv.h"
#include "sof-audio.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) struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scontrol->scomp);
return volume_map[size - 1]; 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]; list_for_each_entry(swidget, &sdev->widget_list, list) {
} if (swidget->comp_id == scontrol->comp_id) {
widget_found = true;
static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size) break;
{ }
int i;
for (i = 0; i < size; i++) {
if (volume_map[i] >= value)
return i;
} }
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) 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 */ /* refresh the component data from DSP */
scontrol->comp_data_dirty = false; 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) { if (ret < 0) {
dev_err(scomp->dev, "Failed to get control data: %d\n", ret); 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 */ /* notify DSP of mixer updates */
if (pm_runtime_active(scomp->dev)) { 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) { if (ret < 0) {
dev_err(scomp->dev, "Failed to set mixer updates for %s\n", 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 */ /* notify DSP of mixer updates */
if (pm_runtime_active(scomp->dev)) { 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) { if (ret < 0) {
dev_err(scomp->dev, "Failed to set mixer updates for %s\n", 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 */ /* notify DSP of enum updates */
if (pm_runtime_active(scomp->dev)) { 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) { if (ret < 0) {
dev_err(scomp->dev, "Failed to set enum updates for %s\n", 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 */ /* notify DSP of byte control updates */
if (pm_runtime_active(scomp->dev)) 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; return 0;
} }
@ -379,7 +438,7 @@ static int sof_ipc3_bytes_ext_put(struct snd_sof_control *scontrol,
/* notify DSP of byte control updates */ /* notify DSP of byte control updates */
if (pm_runtime_active(scomp->dev)) 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; 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; cdata->data->abi = SOF_ABI_VERSION;
/* get all the component data from DSP */ /* 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) if (ret < 0)
return ret; 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); 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 = { const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops = {
.volume_put = sof_ipc3_volume_put, .volume_put = sof_ipc3_volume_put,
.volume_get = sof_ipc3_volume_get, .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_get = sof_ipc3_bytes_ext_get,
.bytes_ext_volatile_get = sof_ipc3_bytes_ext_volatile_get, .bytes_ext_volatile_get = sof_ipc3_bytes_ext_volatile_get,
.update = sof_ipc3_control_update, .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 <sound/pcm_params.h>
#include "ipc3-ops.h" #include "ipc3-priv.h"
#include "ops.h" #include "ops.h"
#include "sof-priv.h" #include "sof-priv.h"
#include "sof-audio.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; stream.comp_id = spcm->stream[substream->stream].comp_id;
/* send IPC to the DSP */ /* send IPC to the DSP */
return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, return sof_ipc_tx_message(sdev->ipc, &stream, sizeof(stream), &reply, sizeof(reply));
sizeof(stream), &reply, sizeof(reply));
} }
static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component, 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; 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); dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag);
/* send hw_params IPC to the DSP */ /* 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)); &ipc_params_reply, sizeof(ipc_params_reply));
if (ret < 0) { if (ret < 0) {
dev_err(component->dev, "HW params ipc failed for stream %d\n", 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 */ /* send IPC to the DSP */
return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, return sof_ipc_tx_message(sdev->ipc, &stream, sizeof(stream), &reply, sizeof(reply));
sizeof(stream), &reply, sizeof(reply));
} }
static void ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name, 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); channels->min, channels->max);
break; break;
case SOF_DAI_AMD_DMIC: case SOF_DAI_AMD_DMIC:
rate->min = private->dai_config->acpdmic.fsync_rate; rate->min = private->dai_config->acpdmic.pdm_rate;
rate->max = private->dai_config->acpdmic.fsync_rate; rate->max = private->dai_config->acpdmic.pdm_rate;
channels->min = private->dai_config->acpdmic.tdm_slots; channels->min = private->dai_config->acpdmic.pdm_ch;
channels->max = private->dai_config->acpdmic.tdm_slots; channels->max = private->dai_config->acpdmic.pdm_ch;
dev_dbg(component->dev, dev_dbg(component->dev,
"AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max); "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 <sound/pcm_params.h>
#include "sof-priv.h" #include "sof-priv.h"
#include "sof-audio.h" #include "sof-audio.h"
#include "ipc3-ops.h" #include "ipc3-priv.h"
#include "ops.h" #include "ops.h"
/* Full volume for default values */ /* Full volume for default values */
#define VOL_ZERO_DB BIT(VOLUME_FWL) #define VOL_ZERO_DB BIT(VOLUME_FWL)
/* size of tplg ABI in bytes */
#define SOF_IPC3_TPLG_ABI_SIZE 3
struct sof_widget_data { struct sof_widget_data {
int ctrl_type; int ctrl_type;
int ipc_cmd; int ipc_cmd;
struct sof_abi_hdr *pdata; void *pdata;
size_t pdata_size;
struct snd_sof_control *control; 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)}, 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 */ /* Core tokens */
static const struct sof_topology_token core_tokens[] = { static const struct sof_topology_token core_tokens[] = {
{SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, {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_ESAI_TOKENS] = {"ESAI tokens", esai_tokens, ARRAY_SIZE(esai_tokens)},
[SOF_SAI_TOKENS] = {"SAI tokens", sai_tokens, ARRAY_SIZE(sai_tokens)}, [SOF_SAI_TOKENS] = {"SAI tokens", sai_tokens, ARRAY_SIZE(sai_tokens)},
[SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_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; 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) {
if (widget->dobj.widget.kcontrol_type[i] == SND_SOC_TPLG_TYPE_BYTES && /* make sure data is valid - data can be updated at runtime */
wdata[i].pdata->magic != SOF_ABI_MAGIC) if (cdata->data->magic != SOF_ABI_MAGIC)
return -EINVAL; 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 */ /* get data type */
switch (cdata->cmd) { switch (cdata->cmd) {
@ -876,10 +901,12 @@ static int sof_process_load(struct snd_soc_component *scomp,
*/ */
if (ipc_data_size) { if (ipc_data_size) {
for (i = 0; i < widget->num_kcontrols; i++) { for (i = 0; i < widget->num_kcontrols; i++) {
memcpy(&process->data[offset], if (!wdata[i].pdata_size)
wdata[i].pdata->data, continue;
wdata[i].pdata->size);
offset += wdata[i].pdata->size; 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 snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
struct sof_dai_private_data *private = dai->private; struct sof_dai_private_data *private = dai->private;
u32 size = sizeof(*config); u32 size = sizeof(*config);
int ret;
/* handle master/slave and inverted clocks */ /* handle master/slave and inverted clocks */
sof_dai_set_format(hw_config, config); sof_dai_set_format(hw_config, config);
/* init IPC */
memset(&config->acpdmic, 0, sizeof(config->acpdmic));
config->hdr.size = size; config->hdr.size = size;
config->acpdmic.fsync_rate = le32_to_cpu(hw_config->fsync_rate); /* parse the required set of ACPDMIC tokens based on num_hw_cfgs */
config->acpdmic.tdm_slots = le32_to_cpu(hw_config->tdm_slots); 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", dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n",
config->dai_index, config->acpdmic.tdm_slots, config->dai_index, config->acpdmic.pdm_ch,
config->acpdmic.fsync_rate); config->acpdmic.pdm_rate);
dai->number_configs = 1; dai->number_configs = 1;
dai->current_config = 0; dai->current_config = 0;
@ -1423,8 +1452,8 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
if (ret < 0) if (ret < 0)
goto free; goto free;
dev_dbg(scomp->dev, "%s dai %s: type %d index %d\n", dev_dbg(scomp->dev, "dai %s: type %d index %d\n",
__func__, swidget->widget->name, comp_dai->type, comp_dai->dai_index); swidget->widget->name, comp_dai->type, comp_dai->dai_index);
sof_dbg_comp_config(scomp, &comp_dai->config); sof_dbg_comp_config(scomp, &comp_dai->config);
/* now update 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); sroute->sink_widget->widget->name);
/* send ipc */ /* send ipc */
ret = sof_ipc_tx_message(sdev->ipc, connect.hdr.cmd, &connect, sizeof(connect), ret = sof_ipc_tx_message(sdev->ipc, &connect, sizeof(connect), &reply, sizeof(reply));
&reply, sizeof(reply));
if (ret < 0) if (ret < 0)
dev_err(sdev->dev, "%s: route %s -> %s failed\n", __func__, dev_err(sdev->dev, "%s: route %s -> %s failed\n", __func__,
sroute->src_widget->widget->name, sroute->sink_widget->widget->name); 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; struct sof_ipc_ctrl_data *cdata;
int ret; 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); scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
if (!scontrol->ipc_control_data) if (!scontrol->ipc_control_data)
return -ENOMEM; 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; scontrol->size = sizeof(struct sof_ipc_ctrl_data) + scontrol->priv_size;
cdata = scontrol->ipc_control_data; 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) { if (scontrol->priv_size > 0) {
memcpy(cdata->data, scontrol->priv, scontrol->priv_size); memcpy(cdata->data, scontrol->priv, scontrol->priv_size);
kfree(scontrol->priv); kfree(scontrol->priv);
scontrol->priv = NULL;
if (cdata->data->magic != SOF_ABI_MAGIC) { if (cdata->data->magic != SOF_ABI_MAGIC) {
dev_err(sdev->dev, "Wrong ABI magic 0x%08x.\n", cdata->data->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; return 0;
err: err:
kfree(scontrol->ipc_control_data); kfree(scontrol->ipc_control_data);
scontrol->ipc_control_data = NULL;
return ret; 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; fcomp.id = scontrol->comp_id;
/* send IPC to the DSP */ /* 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 */ /* 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 */ /* 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)); &ipc_params_reply, sizeof(ipc_params_reply));
if (ret < 0) if (ret < 0)
dev_err(scomp->dev, "%s: PCM params failed for %s\n", __func__, 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; stream.comp_id = swidget->comp_id;
/* send IPC to the DSP */ /* send IPC to the DSP */
ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, ret = sof_ipc_tx_message(sdev->ipc, &stream, sizeof(stream), &reply, sizeof(reply));
sizeof(stream), &reply, sizeof(reply));
if (ret < 0) if (ret < 0)
dev_err(scomp->dev, "%s: Failed to trigger %s\n", __func__, swidget->widget->name); 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.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_COMPLETE;
ready.comp_id = swidget->comp_id; ready.comp_id = swidget->comp_id;
ret = sof_ipc_tx_message(sdev->ipc, ready.hdr.cmd, &ready, sizeof(ready), &reply, ret = sof_ipc_tx_message(sdev->ipc, &ready, sizeof(ready), &reply, sizeof(reply));
sizeof(reply));
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -1939,7 +1966,7 @@ static int sof_ipc3_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
break; 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)); &reply, sizeof(reply));
if (ret < 0) if (ret < 0)
dev_err(sdev->dev, "failed to free widget %s\n", swidget->widget->name); 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 */ /* only send the IPC if the widget is set up in the DSP */
if (swidget->use_count > 0) { 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)); &reply, sizeof(reply));
if (ret < 0) if (ret < 0)
dev_err(sdev->dev, "Failed to set dai config for %s\n", dai->name); 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_dai_private_data *dai_data = dai->private;
struct sof_ipc_comp *comp = &dai_data->comp_dai->comp; 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)); comp->hdr.size, &reply, sizeof(reply));
break; 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; struct sof_ipc_pipe_new *pipeline;
pipeline = swidget->private; pipeline = swidget->private;
ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline, ret = sof_ipc_tx_message(sdev->ipc, pipeline, sizeof(*pipeline),
sizeof(*pipeline), &reply, sizeof(reply)); &reply, sizeof(reply));
break; break;
} }
default: 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; struct sof_ipc_cmd_hdr *hdr;
hdr = swidget->private; 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)); &reply, sizeof(reply));
break; 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) list_for_each_entry(sroute, &sdev->route_list, list)
sroute->setup = false; 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; 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; 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 */ /* token list for each topology object */
static enum sof_tokens host_token_list[] = { static enum sof_tokens host_token_list[] = {
SOF_CORE_TOKENS, SOF_CORE_TOKENS,
@ -2390,4 +2468,5 @@ const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
.dai_get_clk = sof_ipc3_dai_get_clk, .dai_get_clk = sof_ipc3_dai_get_clk,
.set_up_all_pipelines = sof_ipc3_set_up_all_pipelines, .set_up_all_pipelines = sof_ipc3_set_up_all_pipelines,
.tear_down_all_pipelines = sof_ipc3_tear_down_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 <linux/firmware.h>
#include <sound/sof.h>
#include <sound/sof/ext_manifest.h>
#include "sof-priv.h" #include "sof-priv.h"
#include "ops.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) int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
{ {
struct snd_sof_pdata *plat_data = sdev->pdata; 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 */ /* 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) { if (ext_man_size > 0) {
/* when no error occurred, drop extended manifest */ /* when no error occurred, drop extended manifest */
plat_data->fw_offset = ext_man_size; plat_data->fw_offset = ext_man_size;
@ -756,7 +75,7 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
return ret; return ret;
/* make sure the FW header and file is valid */ /* 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) { if (ret < 0) {
dev_err(sdev->dev, "error: invalid FW header\n"); dev_err(sdev->dev, "error: invalid FW header\n");
goto error; goto error;
@ -770,10 +89,12 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
} }
/* parse and load firmware modules to DSP */ /* parse and load firmware modules to DSP */
ret = load_modules(sdev, plat_data->fw, plat_data->fw_offset); if (sdev->ipc->ops->fw_loader->load_fw_to_dsp) {
if (ret < 0) { ret = sdev->ipc->ops->fw_loader->load_fw_to_dsp(sdev);
dev_err(sdev->dev, "error: invalid FW modules\n"); if (ret < 0) {
goto error; dev_err(sdev->dev, "Firmware loading failed\n");
goto error;
}
} }
return 0; return 0;
@ -854,6 +175,9 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev)
dev_dbg(sdev->dev, "firmware boot complete\n"); dev_dbg(sdev->dev, "firmware boot complete\n");
sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE); 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; return 0;
} }
EXPORT_SYMBOL(snd_sof_run_firmware); EXPORT_SYMBOL(snd_sof_run_firmware);

View File

@ -15,15 +15,27 @@ config SND_SOC_SOF_MTK_COMMON
tristate tristate
select SND_SOC_SOF_OF_DEV select SND_SOC_SOF_OF_DEV
select SND_SOC_SOF select SND_SOC_SOF
select SND_SOC_SOF_IPC3
select SND_SOC_SOF_XTENSA select SND_SOC_SOF_XTENSA
select SND_SOC_SOF_COMPRESS select SND_SOC_SOF_COMPRESS
help help
This option is not user-selectable but automagically handled by This option is not user-selectable but automagically handled by
'select' statements at a higher level '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 config SND_SOC_SOF_MT8195
tristate "SOF support for MT8195 audio DSP" tristate "SOF support for MT8195 audio DSP"
select SND_SOC_SOF_MTK_COMMON select SND_SOC_SOF_MTK_COMMON
depends on MTK_ADSP_IPC
help help
This adds support for Sound Open Firmware for Mediatek platforms This adds support for Sound Open Firmware for Mediatek platforms
using the mt8195 processors. using the mt8195 processors.

View File

@ -1,2 +1,4 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) # 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_MT8195) += mt8195/
obj-$(CONFIG_SND_SOC_SOF_MT8186) += mt8186/

View File

@ -7,37 +7,42 @@
#ifndef __MTK_ADSP_HELPER_H__ #ifndef __MTK_ADSP_HELPER_H__
#define __MTK_ADSP_HELPER_H__ #define __MTK_ADSP_HELPER_H__
#include <linux/firmware/mediatek/mtk-adsp-ipc.h>
/* /*
* Global important adsp data structure. * Global important adsp data structure.
*/ */
#define DSP_MBOX_NUM 3
struct mtk_adsp_chip_info { struct mtk_adsp_chip_info {
phys_addr_t pa_sram; phys_addr_t pa_sram;
phys_addr_t pa_dram; /* adsp dram physical base */ phys_addr_t pa_dram; /* adsp dram physical base */
phys_addr_t pa_shared_dram; /* adsp dram physical base */ phys_addr_t pa_shared_dram; /* adsp dram physical base */
phys_addr_t pa_cfgreg; phys_addr_t pa_cfgreg;
phys_addr_t pa_mboxreg[DSP_MBOX_NUM];
u32 sramsize; u32 sramsize;
u32 dramsize; u32 dramsize;
u32 cfgregsize; u32 cfgregsize;
u32 shared_size;
void __iomem *va_sram; /* corresponding to pa_sram */ void __iomem *va_sram; /* corresponding to pa_sram */
void __iomem *va_dram; /* corresponding to pa_dram */ void __iomem *va_dram; /* corresponding to pa_dram */
void __iomem *va_cfgreg; void __iomem *va_cfgreg;
void __iomem *va_mboxreg[DSP_MBOX_NUM];
void __iomem *shared_sram; /* part of va_sram */ void __iomem *shared_sram; /* part of va_sram */
void __iomem *shared_dram; /* part of va_dram */ void __iomem *shared_dram; /* part of va_dram */
phys_addr_t adsp_bootup_addr; phys_addr_t adsp_bootup_addr;
int dram_offset; /*dram offset between system and dsp view*/ 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 adsp_priv {
struct device *dev; struct device *dev;
struct snd_sof_dev *sdev; struct snd_sof_dev *sdev;
struct mtk_adsp_ipc *dsp_ipc;
/* DSP IPC handler */ struct platform_device *ipc_dev;
struct mbox_controller *adsp_mbox;
struct mtk_adsp_chip_info *adsp; struct mtk_adsp_chip_info *adsp;
struct clk **clk; struct clk **clk;
u32 (*ap2adsp_addr)(u32 addr, void *data); 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; 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); ret = adsp_enable_all_clock(sdev);
if (ret) { if (ret) {
dev_err(dev, "failed to adsp_enable_clock: %d\n", 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) */ /* pull high StatVectorSel to use AltResetVec (set bit4 to 1) */
snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, 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 */ /* toggle DReset & BReset */
/* pull high 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,
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 */ /* pull low DReset & BReset */
snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW,
ADSP_BRESET_SW | ADSP_DRESET_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) 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 */ /* RUN_STALL pull high again to reset */
snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW, snd_sof_dsp_update_bits(sdev, DSP_REG_BAR, DSP_RESET_SW,
ADSP_RUNSTALL, ADSP_RUNSTALL); 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-of-dev.h"
#include "../../sof-audio.h" #include "../../sof-audio.h"
#include "../adsp_helper.h" #include "../adsp_helper.h"
#include "../mtk-adsp-common.h"
#include "mt8195.h" #include "mt8195.h"
#include "mt8195-clk.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) static int platform_parse_resource(struct platform_device *pdev, void *data)
{ {
struct resource *mmio; 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); 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); ret = of_reserved_mem_device_init(dev);
if (ret) { if (ret) {
dev_err(dev, "of_reserved_mem_device_init failed\n"); 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 device *dev = &pdev->dev;
struct mtk_adsp_chip_info *adsp = data; struct mtk_adsp_chip_info *adsp = data;
u32 shared_size;
/* remap shared-dram base to be non-cachable */ /* remap shared-dram base to be non-cachable */
shared_size = TOTAL_SIZE_SHARED_DRAM_FROM_TAIL; adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram,
adsp->pa_shared_dram = adsp->pa_dram + adsp->dramsize - shared_size; adsp->shared_size);
if (adsp->va_dram) { if (!adsp->shared_dram) {
adsp->shared_dram = adsp->va_dram + DSP_DRAM_SIZE - shared_size; dev_err(dev, "failed to ioremap base %pa size %#x\n",
} else { adsp->shared_dram, adsp->shared_size);
adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram, return -ENOMEM;
shared_size);
if (!adsp->shared_dram) {
dev_err(dev, "ioremap failed for shared DRAM\n");
return -ENOMEM;
}
} }
dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n", 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; return 0;
} }
@ -267,9 +364,11 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev)
goto err_adsp_sram_power_off; goto err_adsp_sram_power_off;
} }
sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, priv->adsp->va_sram = sdev->bar[SOF_FW_BLK_TYPE_IRAM];
priv->adsp->pa_dram,
priv->adsp->dramsize); 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]) { if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n", dev_err(sdev->dev, "failed to ioremap base %pa size %#x\n",
&priv->adsp->pa_dram, priv->adsp->dramsize); &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_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->mmio_bar = SOF_FW_BLK_TYPE_SRAM;
sdev->mailbox_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; return 0;
exit_pdev_unregister:
platform_device_unregister(priv->ipc_dev);
err_adsp_sram_power_off: err_adsp_sram_power_off:
adsp_sram_power_on(&pdev->dev, false); adsp_sram_power_on(&pdev->dev, false);
exit_clk_disable: exit_clk_disable:
@ -302,10 +422,17 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev)
return ret; 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) static int mt8195_dsp_remove(struct snd_sof_dev *sdev)
{ {
struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); 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_sram_power_on(&pdev->dev, false);
adsp_clock_off(sdev); 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); struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev);
int ret; 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 */ /* stall and reset dsp */
sof_hifixdsp_shutdown(sdev); sof_hifixdsp_shutdown(sdev);
@ -356,6 +496,39 @@ static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type)
return 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[] = { static struct snd_soc_dai_driver mt8195_dai[] = {
{ {
.name = "SOF_DL2", .name = "SOF_DL2",
@ -388,10 +561,11 @@ static struct snd_soc_dai_driver mt8195_dai[] = {
}; };
/* mt8195 ops */ /* 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 and remove */
.probe = mt8195_dsp_probe, .probe = mt8195_dsp_probe,
.remove = mt8195_dsp_remove, .remove = mt8195_dsp_remove,
.shutdown = mt8195_dsp_shutdown,
/* DSP core boot */ /* DSP core boot */
.run = mt8195_run, .run = mt8195_run,
@ -406,17 +580,25 @@ static const struct snd_sof_dsp_ops sof_mt8195_ops = {
.write64 = sof_io_write64, .write64 = sof_io_write64,
.read64 = sof_io_read64, .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 */ /* misc */
.get_bar_index = mt8195_get_bar_index, .get_bar_index = mt8195_get_bar_index,
/* module loading */
.load_module = snd_sof_parse_module_memcpy,
/* firmware loading */ /* firmware loading */
.load_firmware = snd_sof_load_firmware_memcpy, .load_firmware = snd_sof_load_firmware_memcpy,
/* Firmware ops */ /* Firmware ops */
.dsp_arch_ops = &sof_xtensa_arch_ops, .dsp_arch_ops = &sof_xtensa_arch_ops,
/* Debug information */
.dbg_dump = mt8195_adsp_dump,
/* DAI drivers */ /* DAI drivers */
.drv = mt8195_dai, .drv = mt8195_dai,
.num_drv = ARRAY_SIZE(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 = { static const struct sof_dev_desc sof_of_mt8195_desc = {
.default_fw_path = "mediatek/sof", .ipc_supported_mask = BIT(SOF_IPC),
.default_tplg_path = "mediatek/sof-tplg", .ipc_default = SOF_IPC,
.default_fw_filename = "sof-mt8195.ri", .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", .nocodec_tplg_filename = "sof-mt8195-nocodec.tplg",
.ops = &sof_mt8195_ops, .ops = &sof_mt8195_ops,
.ipc_timeout = 1000,
}; };
static const struct of_device_id sof_of_mt8195_ids[] = { 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 = { static struct platform_driver snd_sof_of_mt8195_driver = {
.probe = sof_of_probe, .probe = sof_of_probe,
.remove = sof_of_remove, .remove = sof_of_remove,
.shutdown = sof_of_shutdown,
.driver = { .driver = {
.name = "sof-audio-of-mt8195", .name = "sof-audio-of-mt8195",
.pm = &sof_of_pm, .pm = &sof_of_pm,

View File

@ -34,6 +34,7 @@ struct snd_sof_dev;
#define ADSP_DRESET_SW BIT(1) #define ADSP_DRESET_SW BIT(1)
#define ADSP_RUNSTALL BIT(3) #define ADSP_RUNSTALL BIT(3)
#define STATVECTOR_SEL BIT(4) #define STATVECTOR_SEL BIT(4)
#define ADSP_PWAIT BIT(16)
#define DSP_PFAULTBUS 0x0028 #define DSP_PFAULTBUS 0x0028
#define DSP_PFAULTINFO 0x002c #define DSP_PFAULTINFO 0x002c
#define DSP_GPR00 0x0030 #define DSP_GPR00 0x0030
@ -153,6 +154,10 @@ struct snd_sof_dev;
#define DRAM_REMAP_SHIFT 12 #define DRAM_REMAP_SHIFT 12
#define DRAM_REMAP_MASK (BIT(DRAM_REMAP_SHIFT) - 1) #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_boot_sequence(struct snd_sof_dev *sdev, u32 boot_addr);
void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev); void sof_hifixdsp_shutdown(struct snd_sof_dev *sdev);
#endif #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!", snd_sof_dsp_dbg_dump(sdev, "DSP panic!",
SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX); SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX);
sof_set_fw_state(sdev, SOF_FW_CRASHED); sof_set_fw_state(sdev, SOF_FW_CRASHED);
snd_sof_trace_notify_for_error(sdev); sof_fw_trace_fw_crashed(sdev);
} else { } else {
snd_sof_dsp_dbg_dump(sdev, snd_sof_dsp_dbg_dump(sdev,
"DSP panic (recovery will be attempted)", "DSP panic (recovery will be attempted)",

View File

@ -21,6 +21,20 @@
#define sof_ops(sdev) \ #define sof_ops(sdev) \
((sdev)->pdata->desc->ops) ((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 */ /* Mandatory operations are verified during probing */
/* init */ /* 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); 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 */ /* host PCM ops */
static inline int static inline int
snd_sof_pcm_platform_open(struct snd_sof_dev *sdev, 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); EXPORT_SYMBOL(snd_sof_pcm_period_elapsed);
int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd, static int
struct snd_sof_pcm *spcm, int dir) 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; struct snd_soc_dai *dai;
int ret, j; 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; 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) { if (ret < 0) {
dev_err(sdev->dev, "error: failed widget list set up for pcm %d dir %d\n", dev_err(sdev->dev, "error: failed widget list set up for pcm %d dir %d\n",
spcm->pcm.pcm_id, dir); 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", dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n",
spcm->pcm.pcm_id, substream->stream); 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 this is a repeated hw_params without hw_free, skip setting up widgets */
if (!spcm->stream[substream->stream].list) { 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) if (ret < 0)
return ret; return ret;
} }
@ -166,12 +175,6 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
return ret; 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) { if (pcm_ops->hw_params) {
ret = pcm_ops->hw_params(component, substream, params, &platform_params); ret = pcm_ops->hw_params(component, substream, params, &platform_params);
if (ret < 0) 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); snd_sof_pcm_platform_trigger(sdev, substream, cmd);
/* free PCM if reset_hw_params is set and the STOP IPC is successful */ /* 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, ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream,
free_widget_list); free_widget_list);
if (ret < 0)
return ret;
}
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_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 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_sof_pcm *spcm;
struct snd_soc_tplg_stream_caps *caps; struct snd_soc_tplg_stream_caps *caps;
int ret; int ret;
@ -604,6 +604,14 @@ static int sof_pcm_probe(struct snd_soc_component *component)
const char *tplg_filename; const char *tplg_filename;
int ret; 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 */ /* load the default topology */
sdev->component = component; sdev->component = component;
@ -621,6 +629,9 @@ static int sof_pcm_probe(struct snd_soc_component *component)
return ret; return ret;
} }
pm_runtime_mark_last_busy(component->dev);
pm_runtime_put_autosuspend(component->dev);
return ret; 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 */ /* increment module refcount when a pcm is opened */
pd->module_get_upon_open = 1; 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; u32 target_dsp_state;
switch (sdev->system_suspend_target) { 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: case SOF_SUSPEND_S3:
/* DSP should be in D3 if the system is suspending to S3 */ /* DSP should be in D3 if the system is suspending to S3 */
target_dsp_state = SOF_DSP_PM_D3; 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 * 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 && 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; return 0;
}
sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE); 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; return ret;
} }
/* resume DMA trace, only need send ipc */ /* resume DMA trace */
ret = snd_sof_init_trace_ipc(sdev); ret = sof_fw_trace_resume(sdev);
if (ret < 0) { if (ret < 0) {
/* non fatal */ /* non fatal */
dev_warn(sdev->dev, 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 */ /* prepare for streams to be resumed properly upon resume */
if (!runtime_suspend) { if (!runtime_suspend) {
ret = sof_set_hw_params_upon_resume(sdev->dev); ret = snd_sof_dsp_hw_params_upon_resume(sdev);
if (ret < 0) { if (ret < 0) {
dev_err(sdev->dev, dev_err(sdev->dev,
"error: setting hw_params flag during suspend %d\n", "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 */ /* Skip to platform-specific suspend if DSP is entering D0 */
if (target_state == SOF_DSP_PM_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 */ /* Notify clients not managed by pm framework about core suspend */
sof_suspend_clients(sdev, pm_state); sof_suspend_clients(sdev, pm_state);
goto suspend; goto suspend;
@ -209,8 +220,8 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
if (tplg_ops->tear_down_all_pipelines) if (tplg_ops->tear_down_all_pipelines)
tplg_ops->tear_down_all_pipelines(sdev, false); tplg_ops->tear_down_all_pipelines(sdev, false);
/* release trace */ /* suspend DMA trace */
snd_sof_release_trace(sdev); sof_fw_trace_suspend(sdev, pm_state);
/* Notify clients not managed by pm framework about core suspend */ /* Notify clients not managed by pm framework about core suspend */
sof_suspend_clients(sdev, pm_state); sof_suspend_clients(sdev, pm_state);
@ -327,8 +338,24 @@ int snd_sof_prepare(struct device *dev)
return 0; return 0;
#if defined(CONFIG_ACPI) #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; 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 #endif
return 0; return 0;

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