mirror of
https://github.com/Qortal/Brooklyn.git
synced 2025-01-30 14:52:17 +00:00
update
This commit is contained in:
parent
26999baf09
commit
13f0645c94
@ -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);
|
||||||
|
@ -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[] = {
|
||||||
|
@ -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;
|
||||||
|
@ -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[] = {
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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" },
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
@ -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 | \
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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" },
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
@ -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" },
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
@ -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) \
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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, ¶ms->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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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 = ¬ification_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);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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 = ¬ification_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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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 */
|
||||||
|
@ -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 */
|
||||||
|
@ -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 */
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
1058
sound/soc/sof/ipc3.c
1058
sound/soc/sof/ipc3.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||||
|
@ -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.
|
||||||
|
@ -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/
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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)",
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user