forked from Minki/linux
Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
This commit is contained in:
commit
c988e26130
@ -14,6 +14,8 @@
|
||||
* @gtscap: gts capabilities pointer
|
||||
* @drsmcap: dma resume capabilities pointer
|
||||
* @hlink_list: link list of HDA links
|
||||
* @lock: lock for link mgmt
|
||||
* @cmd_dma_state: state of cmd DMAs: CORB and RIRB
|
||||
*/
|
||||
struct hdac_ext_bus {
|
||||
struct hdac_bus bus;
|
||||
@ -27,6 +29,9 @@ struct hdac_ext_bus {
|
||||
void __iomem *drsmcap;
|
||||
|
||||
struct list_head hlink_list;
|
||||
|
||||
struct mutex lock;
|
||||
bool cmd_dma_state;
|
||||
};
|
||||
|
||||
int snd_hdac_ext_bus_init(struct hdac_ext_bus *sbus, struct device *dev,
|
||||
@ -142,6 +147,9 @@ struct hdac_ext_link {
|
||||
void __iomem *ml_addr; /* link output stream reg pointer */
|
||||
u32 lcaps; /* link capablities */
|
||||
u16 lsdiid; /* link sdi identifier */
|
||||
|
||||
int ref_count;
|
||||
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
@ -154,6 +162,11 @@ void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
|
||||
void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
|
||||
int stream);
|
||||
|
||||
int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus,
|
||||
struct hdac_ext_link *link);
|
||||
int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
|
||||
struct hdac_ext_link *link);
|
||||
|
||||
/* update register macro */
|
||||
#define snd_hdac_updatel(addr, reg, mask, val) \
|
||||
writel(((readl(addr + reg) & ~(mask)) | (val)), \
|
||||
|
@ -1002,7 +1002,7 @@ struct snd_soc_dai_link {
|
||||
*/
|
||||
const char *platform_name;
|
||||
struct device_node *platform_of_node;
|
||||
int be_id; /* optional ID for machine driver BE identification */
|
||||
int id; /* optional ID for machine driver link identification */
|
||||
|
||||
const struct snd_soc_pcm_stream *params;
|
||||
unsigned int num_params;
|
||||
|
@ -105,6 +105,9 @@ int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev,
|
||||
INIT_LIST_HEAD(&ebus->hlink_list);
|
||||
ebus->idx = idx++;
|
||||
|
||||
mutex_init(&ebus->lock);
|
||||
ebus->cmd_dma_state = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init);
|
||||
|
@ -186,6 +186,9 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
|
||||
hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP);
|
||||
hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID);
|
||||
|
||||
/* since link in On, update the ref */
|
||||
hlink->ref_count = 1;
|
||||
|
||||
list_add_tail(&hlink->list, &ebus->hlink_list);
|
||||
}
|
||||
|
||||
@ -327,3 +330,66 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus)
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all);
|
||||
|
||||
int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus,
|
||||
struct hdac_ext_link *link)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&ebus->lock);
|
||||
|
||||
/*
|
||||
* if we move from 0 to 1, count will be 1 so power up this link
|
||||
* as well, also check the dma status and trigger that
|
||||
*/
|
||||
if (++link->ref_count == 1) {
|
||||
if (!ebus->cmd_dma_state) {
|
||||
snd_hdac_bus_init_cmd_io(&ebus->bus);
|
||||
ebus->cmd_dma_state = true;
|
||||
}
|
||||
|
||||
ret = snd_hdac_ext_bus_link_power_up(link);
|
||||
}
|
||||
|
||||
mutex_unlock(&ebus->lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get);
|
||||
|
||||
int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
|
||||
struct hdac_ext_link *link)
|
||||
{
|
||||
int ret = 0;
|
||||
struct hdac_ext_link *hlink;
|
||||
bool link_up = false;
|
||||
|
||||
mutex_lock(&ebus->lock);
|
||||
|
||||
/*
|
||||
* if we move from 1 to 0, count will be 0
|
||||
* so power down this link as well
|
||||
*/
|
||||
if (--link->ref_count == 0) {
|
||||
ret = snd_hdac_ext_bus_link_power_down(link);
|
||||
|
||||
/*
|
||||
* now check if all links are off, if so turn off
|
||||
* cmd dma as well
|
||||
*/
|
||||
list_for_each_entry(hlink, &ebus->hlink_list, list) {
|
||||
if (hlink->ref_count) {
|
||||
link_up = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!link_up) {
|
||||
snd_hdac_bus_stop_cmd_io(&ebus->bus);
|
||||
ebus->cmd_dma_state = false;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&ebus->lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put);
|
||||
|
@ -1378,10 +1378,18 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec)
|
||||
struct snd_soc_dapm_context *dapm =
|
||||
snd_soc_component_get_dapm(&codec->component);
|
||||
struct hdac_hdmi_pin *pin;
|
||||
struct hdac_ext_link *hlink = NULL;
|
||||
int ret;
|
||||
|
||||
edev->scodec = codec;
|
||||
|
||||
/*
|
||||
* hold the ref while we probe, also no need to drop the ref on
|
||||
* exit, we call pm_runtime_suspend() so that will do for us
|
||||
*/
|
||||
hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev));
|
||||
snd_hdac_ext_bus_link_get(edev->ebus, hlink);
|
||||
|
||||
ret = create_fill_widget_route_map(dapm);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -1480,9 +1488,14 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
|
||||
struct hdac_device *codec = &edev->hdac;
|
||||
struct hdac_hdmi_priv *hdmi_priv;
|
||||
struct snd_soc_dai_driver *hdmi_dais = NULL;
|
||||
struct hdac_ext_link *hlink = NULL;
|
||||
int num_dais = 0;
|
||||
int ret = 0;
|
||||
|
||||
/* hold the ref while we probe */
|
||||
hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev));
|
||||
snd_hdac_ext_bus_link_get(edev->ebus, hlink);
|
||||
|
||||
hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
|
||||
if (hdmi_priv == NULL)
|
||||
return -ENOMEM;
|
||||
@ -1516,8 +1529,12 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
|
||||
}
|
||||
|
||||
/* ASoC specific initialization */
|
||||
return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
|
||||
hdmi_dais, num_dais);
|
||||
ret = snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
|
||||
hdmi_dais, num_dais);
|
||||
|
||||
snd_hdac_ext_bus_link_put(edev->ebus, hlink);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
|
||||
@ -1556,6 +1573,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
|
||||
struct hdac_ext_device *edev = to_hda_ext_device(dev);
|
||||
struct hdac_device *hdac = &edev->hdac;
|
||||
struct hdac_bus *bus = hdac->bus;
|
||||
unsigned long timeout;
|
||||
struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
|
||||
struct hdac_ext_link *hlink = NULL;
|
||||
int err;
|
||||
|
||||
dev_dbg(dev, "Enter: %s\n", __func__);
|
||||
@ -1579,6 +1599,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
|
||||
return err;
|
||||
}
|
||||
|
||||
hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev));
|
||||
snd_hdac_ext_bus_link_put(ebus, hlink);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1587,6 +1610,8 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
|
||||
struct hdac_ext_device *edev = to_hda_ext_device(dev);
|
||||
struct hdac_device *hdac = &edev->hdac;
|
||||
struct hdac_bus *bus = hdac->bus;
|
||||
struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
|
||||
struct hdac_ext_link *hlink = NULL;
|
||||
int err;
|
||||
|
||||
dev_dbg(dev, "Enter: %s\n", __func__);
|
||||
@ -1595,6 +1620,9 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
|
||||
if (!bus)
|
||||
return 0;
|
||||
|
||||
hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev));
|
||||
snd_hdac_ext_bus_link_get(ebus, hlink);
|
||||
|
||||
err = snd_hdac_display_power(bus, true);
|
||||
if (err < 0) {
|
||||
dev_err(bus->dev, "Cannot turn on display power on i915\n");
|
||||
|
@ -58,6 +58,21 @@ config SND_SOC_INTEL_HASWELL_MACH
|
||||
Say Y if you have such a device
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_INTEL_BXT_RT298_MACH
|
||||
tristate "ASoC Audio driver for Broxton with RT298 I2S mode"
|
||||
depends on X86 && ACPI && I2C
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SKYLAKE
|
||||
select SND_SOC_RT298
|
||||
select SND_SOC_DMIC
|
||||
select SND_SOC_HDAC_HDMI
|
||||
select SND_HDA_DSP_LOADER
|
||||
help
|
||||
This adds support for ASoC machine driver for Broxton platforms
|
||||
with RT286 I2S audio codec.
|
||||
Say Y if you have such a device
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_INTEL_BYT_RT5640_MACH
|
||||
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
|
||||
depends on X86_INTEL_LPSS && I2C
|
||||
@ -162,6 +177,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
|
||||
config SND_SOC_INTEL_SKYLAKE
|
||||
tristate
|
||||
select SND_HDA_EXT_CORE
|
||||
select SND_HDA_DSP_LOADER
|
||||
select SND_SOC_TOPOLOGY
|
||||
select SND_SOC_INTEL_SST
|
||||
|
||||
|
@ -195,7 +195,7 @@ static int sst_check_and_send_slot_map(struct sst_data *drv, struct snd_kcontrol
|
||||
|
||||
if (e->w && e->w->power)
|
||||
ret = sst_send_slot_map(drv);
|
||||
else
|
||||
else if (!e->w)
|
||||
dev_err(&drv->pdev->dev, "Slot control: %s doesn't have DAPM widget!!!\n",
|
||||
kcontrol->id.name);
|
||||
return ret;
|
||||
|
@ -2,6 +2,7 @@ snd-soc-sst-haswell-objs := haswell.o
|
||||
snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
|
||||
snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
|
||||
snd-soc-sst-broadwell-objs := broadwell.o
|
||||
snd-soc-sst-bxt-rt298-objs := bxt_rt298.o
|
||||
snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
|
||||
snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o
|
||||
snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
|
||||
@ -14,6 +15,7 @@ snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o
|
||||
|
@ -201,7 +201,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
|
||||
{
|
||||
/* SSP0 - Codec */
|
||||
.name = "Codec",
|
||||
.be_id = 0,
|
||||
.id = 0,
|
||||
.cpu_dai_name = "snd-soc-dummy-dai",
|
||||
.platform_name = "snd-soc-dummy",
|
||||
.no_pcm = 1,
|
||||
|
353
sound/soc/intel/boards/bxt_rt298.c
Normal file
353
sound/soc/intel/boards/bxt_rt298.c
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Intel Broxton-P I2S Machine Driver
|
||||
*
|
||||
* Copyright (C) 2014-2016, Intel Corporation. All rights reserved.
|
||||
*
|
||||
* Modified from:
|
||||
* Intel Skylake I2S Machine driver
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version
|
||||
* 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include "../../codecs/hdac_hdmi.h"
|
||||
#include "../../codecs/rt298.h"
|
||||
|
||||
static struct snd_soc_jack broxton_headset;
|
||||
/* Headset jack detection DAPM pins */
|
||||
|
||||
enum {
|
||||
BXT_DPCM_AUDIO_PB = 0,
|
||||
BXT_DPCM_AUDIO_CP,
|
||||
BXT_DPCM_AUDIO_REF_CP,
|
||||
BXT_DPCM_AUDIO_HDMI1_PB,
|
||||
BXT_DPCM_AUDIO_HDMI2_PB,
|
||||
BXT_DPCM_AUDIO_HDMI3_PB,
|
||||
};
|
||||
|
||||
static struct snd_soc_jack_pin broxton_headset_pins[] = {
|
||||
{
|
||||
.pin = "Mic Jack",
|
||||
.mask = SND_JACK_MICROPHONE,
|
||||
},
|
||||
{
|
||||
.pin = "Headphone Jack",
|
||||
.mask = SND_JACK_HEADPHONE,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new broxton_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Speaker"),
|
||||
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
|
||||
SOC_DAPM_PIN_SWITCH("Mic Jack"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget broxton_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
SND_SOC_DAPM_MIC("Mic Jack", NULL),
|
||||
SND_SOC_DAPM_MIC("DMIC2", NULL),
|
||||
SND_SOC_DAPM_MIC("SoC DMIC", NULL),
|
||||
SND_SOC_DAPM_SPK("HDMI1", NULL),
|
||||
SND_SOC_DAPM_SPK("HDMI2", NULL),
|
||||
SND_SOC_DAPM_SPK("HDMI3", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route broxton_rt298_map[] = {
|
||||
/* speaker */
|
||||
{"Speaker", NULL, "SPOR"},
|
||||
{"Speaker", NULL, "SPOL"},
|
||||
|
||||
/* HP jack connectors - unknown if we have jack detect */
|
||||
{"Headphone Jack", NULL, "HPO Pin"},
|
||||
|
||||
/* other jacks */
|
||||
{"MIC1", NULL, "Mic Jack"},
|
||||
|
||||
/* digital mics */
|
||||
{"DMIC1 Pin", NULL, "DMIC2"},
|
||||
{"DMic", NULL, "SoC DMIC"},
|
||||
|
||||
{"HDMI1", NULL, "hif5 Output"},
|
||||
{"HDMI2", NULL, "hif6 Output"},
|
||||
{"HDMI3", NULL, "hif7 Output"},
|
||||
|
||||
/* CODEC BE connections */
|
||||
{ "AIF1 Playback", NULL, "ssp5 Tx"},
|
||||
{ "ssp5 Tx", NULL, "codec0_out"},
|
||||
|
||||
{ "codec0_in", NULL, "ssp5 Rx" },
|
||||
{ "ssp5 Rx", NULL, "AIF1 Capture" },
|
||||
|
||||
{ "dmic01_hifi", NULL, "DMIC01 Rx" },
|
||||
{ "DMIC01 Rx", NULL, "Capture" },
|
||||
|
||||
{ "hifi3", NULL, "iDisp3 Tx"},
|
||||
{ "iDisp3 Tx", NULL, "iDisp3_out"},
|
||||
{ "hifi2", NULL, "iDisp2 Tx"},
|
||||
{ "iDisp2 Tx", NULL, "iDisp2_out"},
|
||||
{ "hifi1", NULL, "iDisp1 Tx"},
|
||||
{ "iDisp1 Tx", NULL, "iDisp1_out"},
|
||||
|
||||
};
|
||||
|
||||
static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
int ret = 0;
|
||||
|
||||
ret = snd_soc_card_jack_new(rtd->card, "Headset",
|
||||
SND_JACK_HEADSET | SND_JACK_BTN_0,
|
||||
&broxton_headset,
|
||||
broxton_headset_pins, ARRAY_SIZE(broxton_headset_pins));
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rt298_mic_detect(codec, &broxton_headset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *dai = rtd->codec_dai;
|
||||
|
||||
return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id);
|
||||
}
|
||||
|
||||
static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_interval *rate = hw_param_interval(params,
|
||||
SNDRV_PCM_HW_PARAM_RATE);
|
||||
struct snd_interval *channels = hw_param_interval(params,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS);
|
||||
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
|
||||
|
||||
/* The ADSP will covert the FE rate to 48k, stereo */
|
||||
rate->min = rate->max = 48000;
|
||||
channels->min = channels->max = 2;
|
||||
|
||||
/* set SSP5 to 24 bit */
|
||||
snd_mask_none(fmt);
|
||||
snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int broxton_rt298_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL,
|
||||
19200000, SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set codec sysclk configuration\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct snd_soc_ops broxton_rt298_ops = {
|
||||
.hw_params = broxton_rt298_hw_params,
|
||||
};
|
||||
|
||||
/* broxton digital audio interface glue - connects codec <--> CPU */
|
||||
static struct snd_soc_dai_link broxton_rt298_dais[] = {
|
||||
/* Front End DAI links */
|
||||
[BXT_DPCM_AUDIO_PB]
|
||||
{
|
||||
.name = "Bxt Audio Port",
|
||||
.stream_name = "Audio",
|
||||
.cpu_dai_name = "System Pin",
|
||||
.platform_name = "0000:00:0e.0",
|
||||
.nonatomic = 1,
|
||||
.dynamic = 1,
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
|
||||
.dpcm_playback = 1,
|
||||
},
|
||||
[BXT_DPCM_AUDIO_CP]
|
||||
{
|
||||
.name = "Bxt Audio Capture Port",
|
||||
.stream_name = "Audio Record",
|
||||
.cpu_dai_name = "System Pin",
|
||||
.platform_name = "0000:00:0e.0",
|
||||
.nonatomic = 1,
|
||||
.dynamic = 1,
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
[BXT_DPCM_AUDIO_REF_CP]
|
||||
{
|
||||
.name = "Bxt Audio Reference cap",
|
||||
.stream_name = "refcap",
|
||||
.cpu_dai_name = "Reference Pin",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.platform_name = "0000:00:0e.0",
|
||||
.init = NULL,
|
||||
.dpcm_capture = 1,
|
||||
.nonatomic = 1,
|
||||
.dynamic = 1,
|
||||
},
|
||||
[BXT_DPCM_AUDIO_HDMI1_PB]
|
||||
{
|
||||
.name = "Bxt HDMI Port1",
|
||||
.stream_name = "Hdmi1",
|
||||
.cpu_dai_name = "HDMI1 Pin",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.platform_name = "0000:00:0e.0",
|
||||
.dpcm_playback = 1,
|
||||
.init = NULL,
|
||||
.nonatomic = 1,
|
||||
.dynamic = 1,
|
||||
},
|
||||
[BXT_DPCM_AUDIO_HDMI2_PB]
|
||||
{
|
||||
.name = "Bxt HDMI Port2",
|
||||
.stream_name = "Hdmi2",
|
||||
.cpu_dai_name = "HDMI2 Pin",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.platform_name = "0000:00:0e.0",
|
||||
.dpcm_playback = 1,
|
||||
.init = NULL,
|
||||
.nonatomic = 1,
|
||||
.dynamic = 1,
|
||||
},
|
||||
[BXT_DPCM_AUDIO_HDMI3_PB]
|
||||
{
|
||||
.name = "Bxt HDMI Port3",
|
||||
.stream_name = "Hdmi3",
|
||||
.cpu_dai_name = "HDMI3 Pin",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.platform_name = "0000:00:0e.0",
|
||||
.dpcm_playback = 1,
|
||||
.init = NULL,
|
||||
.nonatomic = 1,
|
||||
.dynamic = 1,
|
||||
},
|
||||
/* Back End DAI links */
|
||||
{
|
||||
/* SSP5 - Codec */
|
||||
.name = "SSP5-Codec",
|
||||
.id = 0,
|
||||
.cpu_dai_name = "SSP5 Pin",
|
||||
.platform_name = "0000:00:0e.0",
|
||||
.no_pcm = 1,
|
||||
.codec_name = "i2c-INT343A:00",
|
||||
.codec_dai_name = "rt298-aif1",
|
||||
.init = broxton_rt298_codec_init,
|
||||
.dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS,
|
||||
.ignore_pmdown_time = 1,
|
||||
.be_hw_params_fixup = broxton_ssp5_fixup,
|
||||
.ops = &broxton_rt298_ops,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
{
|
||||
.name = "dmic01",
|
||||
.id = 1,
|
||||
.cpu_dai_name = "DMIC01 Pin",
|
||||
.codec_name = "dmic-codec",
|
||||
.codec_dai_name = "dmic-hifi",
|
||||
.platform_name = "0000:00:0e.0",
|
||||
.ignore_suspend = 1,
|
||||
.dpcm_capture = 1,
|
||||
.no_pcm = 1,
|
||||
},
|
||||
{
|
||||
.name = "iDisp1",
|
||||
.id = 3,
|
||||
.cpu_dai_name = "iDisp1 Pin",
|
||||
.codec_name = "ehdaudio0D2",
|
||||
.codec_dai_name = "intel-hdmi-hifi1",
|
||||
.platform_name = "0000:00:0e.0",
|
||||
.init = broxton_hdmi_init,
|
||||
.dpcm_playback = 1,
|
||||
.no_pcm = 1,
|
||||
},
|
||||
{
|
||||
.name = "iDisp2",
|
||||
.id = 4,
|
||||
.cpu_dai_name = "iDisp2 Pin",
|
||||
.codec_name = "ehdaudio0D2",
|
||||
.codec_dai_name = "intel-hdmi-hifi2",
|
||||
.platform_name = "0000:00:0e.0",
|
||||
.init = broxton_hdmi_init,
|
||||
.dpcm_playback = 1,
|
||||
.no_pcm = 1,
|
||||
},
|
||||
{
|
||||
.name = "iDisp3",
|
||||
.id = 5,
|
||||
.cpu_dai_name = "iDisp3 Pin",
|
||||
.codec_name = "ehdaudio0D2",
|
||||
.codec_dai_name = "intel-hdmi-hifi3",
|
||||
.platform_name = "0000:00:0e.0",
|
||||
.init = broxton_hdmi_init,
|
||||
.dpcm_playback = 1,
|
||||
.no_pcm = 1,
|
||||
},
|
||||
};
|
||||
|
||||
/* broxton audio machine driver for SPT + RT298S */
|
||||
static struct snd_soc_card broxton_rt298 = {
|
||||
.name = "broxton-rt298",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = broxton_rt298_dais,
|
||||
.num_links = ARRAY_SIZE(broxton_rt298_dais),
|
||||
.controls = broxton_controls,
|
||||
.num_controls = ARRAY_SIZE(broxton_controls),
|
||||
.dapm_widgets = broxton_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(broxton_widgets),
|
||||
.dapm_routes = broxton_rt298_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(broxton_rt298_map),
|
||||
.fully_routed = true,
|
||||
};
|
||||
|
||||
static int broxton_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
broxton_rt298.dev = &pdev->dev;
|
||||
|
||||
return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298);
|
||||
}
|
||||
|
||||
static struct platform_driver broxton_audio = {
|
||||
.probe = broxton_audio_probe,
|
||||
.driver = {
|
||||
.name = "bxt_alc298s_i2s",
|
||||
},
|
||||
};
|
||||
module_platform_driver(broxton_audio)
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Ramesh Babu <Ramesh.Babu@intel.com>");
|
||||
MODULE_AUTHOR("Senthilnathan Veppur <senthilnathanx.veppur@intel.com>");
|
||||
MODULE_DESCRIPTION("Intel SST Audio for Broxton");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:bxt_alc298s_i2s");
|
@ -304,7 +304,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
|
||||
/* back ends */
|
||||
{
|
||||
.name = "SSP2-Codec",
|
||||
.be_id = 1,
|
||||
.id = 1,
|
||||
.cpu_dai_name = "ssp2-port",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.no_pcm = 1,
|
||||
|
@ -267,7 +267,7 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = {
|
||||
/* back ends */
|
||||
{
|
||||
.name = "SSP2-Codec",
|
||||
.be_id = 1,
|
||||
.id = 1,
|
||||
.cpu_dai_name = "ssp2-port",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.no_pcm = 1,
|
||||
|
@ -255,7 +255,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
|
||||
/* back ends */
|
||||
{
|
||||
.name = "SSP2-Codec",
|
||||
.be_id = 1,
|
||||
.id = 1,
|
||||
.cpu_dai_name = "ssp2-port",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.no_pcm = 1,
|
||||
|
@ -295,7 +295,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
|
||||
/* back ends */
|
||||
{
|
||||
.name = "SSP2-Codec",
|
||||
.be_id = 1,
|
||||
.id = 1,
|
||||
.cpu_dai_name = "ssp2-port",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.no_pcm = 1,
|
||||
|
@ -273,7 +273,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
|
||||
{
|
||||
/* SSP2 - Codec */
|
||||
.name = "SSP2-Codec",
|
||||
.be_id = 1,
|
||||
.id = 1,
|
||||
.cpu_dai_name = "ssp2-port",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.no_pcm = 1,
|
||||
|
@ -156,7 +156,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = {
|
||||
{
|
||||
/* SSP0 - Codec */
|
||||
.name = "Codec",
|
||||
.be_id = 0,
|
||||
.id = 0,
|
||||
.cpu_dai_name = "snd-soc-dummy-dai",
|
||||
.platform_name = "snd-soc-dummy",
|
||||
.no_pcm = 1,
|
||||
|
@ -391,7 +391,6 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
||||
.platform_name = "0000:00:1f.3",
|
||||
.init = NULL,
|
||||
.dpcm_capture = 1,
|
||||
.ignore_suspend = 1,
|
||||
.nonatomic = 1,
|
||||
.dynamic = 1,
|
||||
.ops = &skylaye_refcap_ops,
|
||||
@ -456,7 +455,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
||||
{
|
||||
/* SSP0 - Codec */
|
||||
.name = "SSP0-Codec",
|
||||
.be_id = 0,
|
||||
.id = 0,
|
||||
.cpu_dai_name = "SSP0 Pin",
|
||||
.platform_name = "0000:00:1f.3",
|
||||
.no_pcm = 1,
|
||||
@ -472,7 +471,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
||||
{
|
||||
/* SSP1 - Codec */
|
||||
.name = "SSP1-Codec",
|
||||
.be_id = 1,
|
||||
.id = 1,
|
||||
.cpu_dai_name = "SSP1 Pin",
|
||||
.platform_name = "0000:00:1f.3",
|
||||
.no_pcm = 1,
|
||||
@ -489,7 +488,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
||||
},
|
||||
{
|
||||
.name = "dmic01",
|
||||
.be_id = 2,
|
||||
.id = 2,
|
||||
.cpu_dai_name = "DMIC01 Pin",
|
||||
.codec_name = "dmic-codec",
|
||||
.codec_dai_name = "dmic-hifi",
|
||||
@ -501,7 +500,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
||||
},
|
||||
{
|
||||
.name = "iDisp1",
|
||||
.be_id = 3,
|
||||
.id = 3,
|
||||
.cpu_dai_name = "iDisp1 Pin",
|
||||
.codec_name = "ehdaudio0D2",
|
||||
.codec_dai_name = "intel-hdmi-hifi1",
|
||||
@ -512,7 +511,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
||||
},
|
||||
{
|
||||
.name = "iDisp2",
|
||||
.be_id = 4,
|
||||
.id = 4,
|
||||
.cpu_dai_name = "iDisp2 Pin",
|
||||
.codec_name = "ehdaudio0D2",
|
||||
.codec_dai_name = "intel-hdmi-hifi2",
|
||||
@ -523,7 +522,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
||||
},
|
||||
{
|
||||
.name = "iDisp3",
|
||||
.be_id = 5,
|
||||
.id = 5,
|
||||
.cpu_dai_name = "iDisp3 Pin",
|
||||
.codec_name = "ehdaudio0D2",
|
||||
.codec_dai_name = "intel-hdmi-hifi3",
|
||||
|
@ -440,7 +440,6 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
||||
.platform_name = "0000:00:1f.3",
|
||||
.init = NULL,
|
||||
.dpcm_capture = 1,
|
||||
.ignore_suspend = 1,
|
||||
.nonatomic = 1,
|
||||
.dynamic = 1,
|
||||
.ops = &skylaye_refcap_ops,
|
||||
@ -505,7 +504,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
||||
{
|
||||
/* SSP0 - Codec */
|
||||
.name = "SSP0-Codec",
|
||||
.be_id = 0,
|
||||
.id = 0,
|
||||
.cpu_dai_name = "SSP0 Pin",
|
||||
.platform_name = "0000:00:1f.3",
|
||||
.no_pcm = 1,
|
||||
@ -523,7 +522,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
||||
{
|
||||
/* SSP1 - Codec */
|
||||
.name = "SSP1-Codec",
|
||||
.be_id = 1,
|
||||
.id = 1,
|
||||
.cpu_dai_name = "SSP1 Pin",
|
||||
.platform_name = "0000:00:1f.3",
|
||||
.no_pcm = 1,
|
||||
@ -540,7 +539,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
||||
},
|
||||
{
|
||||
.name = "dmic01",
|
||||
.be_id = 2,
|
||||
.id = 2,
|
||||
.cpu_dai_name = "DMIC01 Pin",
|
||||
.codec_name = "dmic-codec",
|
||||
.codec_dai_name = "dmic-hifi",
|
||||
@ -552,7 +551,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
||||
},
|
||||
{
|
||||
.name = "iDisp1",
|
||||
.be_id = 3,
|
||||
.id = 3,
|
||||
.cpu_dai_name = "iDisp1 Pin",
|
||||
.codec_name = "ehdaudio0D2",
|
||||
.codec_dai_name = "intel-hdmi-hifi1",
|
||||
@ -563,7 +562,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
||||
},
|
||||
{
|
||||
.name = "iDisp2",
|
||||
.be_id = 4,
|
||||
.id = 4,
|
||||
.cpu_dai_name = "iDisp2 Pin",
|
||||
.codec_name = "ehdaudio0D2",
|
||||
.codec_dai_name = "intel-hdmi-hifi2",
|
||||
@ -574,7 +573,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
|
||||
},
|
||||
{
|
||||
.name = "iDisp3",
|
||||
.be_id = 5,
|
||||
.id = 5,
|
||||
.cpu_dai_name = "iDisp3 Pin",
|
||||
.codec_name = "ehdaudio0D2",
|
||||
.codec_dai_name = "intel-hdmi-hifi3",
|
||||
|
@ -317,7 +317,6 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
|
||||
.platform_name = "0000:00:1f.3",
|
||||
.init = NULL,
|
||||
.dpcm_capture = 1,
|
||||
.ignore_suspend = 1,
|
||||
.nonatomic = 1,
|
||||
.dynamic = 1,
|
||||
},
|
||||
@ -375,7 +374,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
|
||||
{
|
||||
/* SSP0 - Codec */
|
||||
.name = "SSP0-Codec",
|
||||
.be_id = 0,
|
||||
.id = 0,
|
||||
.cpu_dai_name = "SSP0 Pin",
|
||||
.platform_name = "0000:00:1f.3",
|
||||
.no_pcm = 1,
|
||||
@ -393,7 +392,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
|
||||
},
|
||||
{
|
||||
.name = "dmic01",
|
||||
.be_id = 1,
|
||||
.id = 1,
|
||||
.cpu_dai_name = "DMIC01 Pin",
|
||||
.codec_name = "dmic-codec",
|
||||
.codec_dai_name = "dmic-hifi",
|
||||
@ -405,7 +404,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
|
||||
},
|
||||
{
|
||||
.name = "iDisp1",
|
||||
.be_id = 2,
|
||||
.id = 2,
|
||||
.cpu_dai_name = "iDisp1 Pin",
|
||||
.codec_name = "ehdaudio0D2",
|
||||
.codec_dai_name = "intel-hdmi-hifi1",
|
||||
@ -416,7 +415,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
|
||||
},
|
||||
{
|
||||
.name = "iDisp2",
|
||||
.be_id = 3,
|
||||
.id = 3,
|
||||
.cpu_dai_name = "iDisp2 Pin",
|
||||
.codec_name = "ehdaudio0D2",
|
||||
.codec_dai_name = "intel-hdmi-hifi2",
|
||||
@ -427,7 +426,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
|
||||
},
|
||||
{
|
||||
.name = "iDisp3",
|
||||
.be_id = 4,
|
||||
.id = 4,
|
||||
.cpu_dai_name = "iDisp3 Pin",
|
||||
.codec_name = "ehdaudio0D2",
|
||||
.codec_dai_name = "intel-hdmi-hifi3",
|
||||
|
@ -12,10 +12,19 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
/* translation fron HID to I2C name, needed for DAI codec_name */
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]);
|
||||
#else
|
||||
inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* acpi match */
|
||||
struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines);
|
||||
|
@ -445,7 +445,7 @@ static int create_adsp_page_table(struct snd_pcm_substream *substream,
|
||||
|
||||
pages = snd_sgbuf_aligned_pages(size);
|
||||
|
||||
dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n",
|
||||
dev_dbg(rtd->dev, "generating page table for %p size 0x%zx pages %d\n",
|
||||
dma_area, size, pages);
|
||||
|
||||
for (i = 0; i < pages; i++) {
|
||||
|
@ -5,6 +5,6 @@ obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
|
||||
|
||||
# Skylake IPC Support
|
||||
snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \
|
||||
skl-sst.o
|
||||
skl-sst.o bxt-sst.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o
|
||||
|
328
sound/soc/intel/skylake/bxt-sst.c
Normal file
328
sound/soc/intel/skylake/bxt-sst.c
Normal file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
* bxt-sst.c - DSP library functions for BXT platform
|
||||
*
|
||||
* Copyright (C) 2015-16 Intel Corp
|
||||
* Author:Rafal Redzimski <rafal.f.redzimski@intel.com>
|
||||
* Jeeja KP <jeeja.kp@intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include "../common/sst-dsp.h"
|
||||
#include "../common/sst-dsp-priv.h"
|
||||
#include "skl-sst-ipc.h"
|
||||
|
||||
#define BXT_BASEFW_TIMEOUT 3000
|
||||
#define BXT_INIT_TIMEOUT 500
|
||||
#define BXT_IPC_PURGE_FW 0x01004000
|
||||
|
||||
#define BXT_ROM_INIT 0x5
|
||||
#define BXT_ADSP_SRAM0_BASE 0x80000
|
||||
|
||||
/* Firmware status window */
|
||||
#define BXT_ADSP_FW_STATUS BXT_ADSP_SRAM0_BASE
|
||||
#define BXT_ADSP_ERROR_CODE (BXT_ADSP_FW_STATUS + 0x4)
|
||||
|
||||
#define BXT_ADSP_SRAM1_BASE 0xA0000
|
||||
|
||||
static unsigned int bxt_get_errorcode(struct sst_dsp *ctx)
|
||||
{
|
||||
return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE);
|
||||
}
|
||||
|
||||
static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
|
||||
const void *fwdata, u32 fwsize)
|
||||
{
|
||||
int stream_tag, ret, i;
|
||||
u32 reg;
|
||||
|
||||
stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab);
|
||||
if (stream_tag < 0) {
|
||||
dev_err(ctx->dev, "Failed to prepare DMA FW loading err: %x\n",
|
||||
stream_tag);
|
||||
return stream_tag;
|
||||
}
|
||||
|
||||
ctx->dsp_ops.stream_tag = stream_tag;
|
||||
memcpy(ctx->dmab.area, fwdata, fwsize);
|
||||
|
||||
/* Purge FW request */
|
||||
sst_dsp_shim_write(ctx, SKL_ADSP_REG_HIPCI, SKL_ADSP_REG_HIPCI_BUSY |
|
||||
BXT_IPC_PURGE_FW | (stream_tag - 1));
|
||||
|
||||
ret = skl_dsp_enable_core(ctx);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Boot dsp core failed ret: %d\n", ret);
|
||||
ret = -EIO;
|
||||
goto base_fw_load_failed;
|
||||
}
|
||||
|
||||
for (i = BXT_INIT_TIMEOUT; i > 0; --i) {
|
||||
reg = sst_dsp_shim_read(ctx, SKL_ADSP_REG_HIPCIE);
|
||||
|
||||
if (reg & SKL_ADSP_REG_HIPCIE_DONE) {
|
||||
sst_dsp_shim_update_bits_forced(ctx,
|
||||
SKL_ADSP_REG_HIPCIE,
|
||||
SKL_ADSP_REG_HIPCIE_DONE,
|
||||
SKL_ADSP_REG_HIPCIE_DONE);
|
||||
break;
|
||||
}
|
||||
mdelay(1);
|
||||
}
|
||||
if (!i) {
|
||||
dev_info(ctx->dev, "Waiting for HIPCIE done, reg: 0x%x\n", reg);
|
||||
sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCIE,
|
||||
SKL_ADSP_REG_HIPCIE_DONE,
|
||||
SKL_ADSP_REG_HIPCIE_DONE);
|
||||
}
|
||||
|
||||
/* enable Interrupt */
|
||||
skl_ipc_int_enable(ctx);
|
||||
skl_ipc_op_int_enable(ctx);
|
||||
|
||||
for (i = BXT_INIT_TIMEOUT; i > 0; --i) {
|
||||
if (SKL_FW_INIT ==
|
||||
(sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS) &
|
||||
SKL_FW_STS_MASK)) {
|
||||
|
||||
dev_info(ctx->dev, "ROM loaded, continue FW loading\n");
|
||||
break;
|
||||
}
|
||||
mdelay(1);
|
||||
}
|
||||
if (!i) {
|
||||
dev_err(ctx->dev, "Timeout for ROM init, HIPCIE: 0x%x\n", reg);
|
||||
ret = -EIO;
|
||||
goto base_fw_load_failed;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
base_fw_load_failed:
|
||||
ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag);
|
||||
skl_dsp_disable_core(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sst_transfer_fw_host_dma(struct sst_dsp *ctx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag);
|
||||
ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK,
|
||||
BXT_ROM_INIT, BXT_BASEFW_TIMEOUT, "Firmware boot");
|
||||
|
||||
ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag);
|
||||
ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bxt_load_base_firmware(struct sst_dsp *ctx)
|
||||
{
|
||||
const struct firmware *fw = NULL;
|
||||
struct skl_sst *skl = ctx->thread_context;
|
||||
int ret;
|
||||
|
||||
ret = request_firmware(&fw, ctx->fw_name, ctx->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Request firmware failed %d\n", ret);
|
||||
goto sst_load_base_firmware_failed;
|
||||
}
|
||||
|
||||
ret = sst_bxt_prepare_fw(ctx, fw->data, fw->size);
|
||||
/* Retry Enabling core and ROM load. Retry seemed to help */
|
||||
if (ret < 0) {
|
||||
ret = sst_bxt_prepare_fw(ctx, fw->data, fw->size);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret);
|
||||
goto sst_load_base_firmware_failed;
|
||||
}
|
||||
}
|
||||
|
||||
ret = sst_transfer_fw_host_dma(ctx);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Transfer firmware failed %d\n", ret);
|
||||
dev_info(ctx->dev, "Error code=0x%x: FW status=0x%x\n",
|
||||
sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE),
|
||||
sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS));
|
||||
|
||||
skl_dsp_disable_core(ctx);
|
||||
} else {
|
||||
dev_dbg(ctx->dev, "Firmware download successful\n");
|
||||
ret = wait_event_timeout(skl->boot_wait, skl->boot_complete,
|
||||
msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
|
||||
if (ret == 0) {
|
||||
dev_err(ctx->dev, "DSP boot fail, FW Ready timeout\n");
|
||||
skl_dsp_disable_core(ctx);
|
||||
ret = -EIO;
|
||||
} else {
|
||||
skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sst_load_base_firmware_failed:
|
||||
release_firmware(fw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bxt_set_dsp_D0(struct sst_dsp *ctx)
|
||||
{
|
||||
struct skl_sst *skl = ctx->thread_context;
|
||||
int ret;
|
||||
|
||||
skl->boot_complete = false;
|
||||
|
||||
ret = skl_dsp_enable_core(ctx);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "enable dsp core failed ret: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
skl_ipc_int_enable(ctx);
|
||||
skl_ipc_op_int_enable(ctx);
|
||||
|
||||
ret = wait_event_timeout(skl->boot_wait, skl->boot_complete,
|
||||
msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
|
||||
if (ret == 0) {
|
||||
dev_err(ctx->dev, "ipc: error DSP boot timeout\n");
|
||||
dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n",
|
||||
sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE),
|
||||
sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bxt_set_dsp_D3(struct sst_dsp *ctx)
|
||||
{
|
||||
struct skl_ipc_dxstate_info dx;
|
||||
struct skl_sst *skl = ctx->thread_context;
|
||||
int ret = 0;
|
||||
|
||||
if (!is_skl_dsp_running(ctx))
|
||||
return ret;
|
||||
|
||||
dx.core_mask = SKL_DSP_CORE0_MASK;
|
||||
dx.dx_mask = SKL_IPC_D3_MASK;
|
||||
|
||||
ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID,
|
||||
SKL_BASE_FW_MODULE_ID, &dx);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Failed to set DSP to D3 state: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = skl_dsp_disable_core(ctx);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "disbale dsp core failed: %d\n", ret);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
skl_dsp_set_state_locked(ctx, SKL_DSP_RESET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct skl_dsp_fw_ops bxt_fw_ops = {
|
||||
.set_state_D0 = bxt_set_dsp_D0,
|
||||
.set_state_D3 = bxt_set_dsp_D3,
|
||||
.load_fw = bxt_load_base_firmware,
|
||||
.get_fw_errcode = bxt_get_errorcode,
|
||||
};
|
||||
|
||||
static struct sst_ops skl_ops = {
|
||||
.irq_handler = skl_dsp_sst_interrupt,
|
||||
.write = sst_shim32_write,
|
||||
.read = sst_shim32_read,
|
||||
.ram_read = sst_memcpy_fromio_32,
|
||||
.ram_write = sst_memcpy_toio_32,
|
||||
.free = skl_dsp_free,
|
||||
};
|
||||
|
||||
static struct sst_dsp_device skl_dev = {
|
||||
.thread = skl_dsp_irq_thread_handler,
|
||||
.ops = &skl_ops,
|
||||
};
|
||||
|
||||
int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
||||
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
|
||||
struct skl_sst **dsp)
|
||||
{
|
||||
struct skl_sst *skl;
|
||||
struct sst_dsp *sst;
|
||||
int ret;
|
||||
|
||||
skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL);
|
||||
if (skl == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
skl->dev = dev;
|
||||
skl_dev.thread_context = skl;
|
||||
|
||||
skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq);
|
||||
if (!skl->dsp) {
|
||||
dev_err(skl->dev, "skl_dsp_ctx_init failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
sst = skl->dsp;
|
||||
sst->fw_name = fw_name;
|
||||
sst->dsp_ops = dsp_ops;
|
||||
sst->fw_ops = bxt_fw_ops;
|
||||
sst->addr.lpe = mmio_base;
|
||||
sst->addr.shim = mmio_base;
|
||||
|
||||
sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
|
||||
SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
|
||||
|
||||
ret = skl_ipc_init(dev, skl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
skl->boot_complete = false;
|
||||
init_waitqueue_head(&skl->boot_wait);
|
||||
|
||||
ret = sst->fw_ops.load_fw(sst);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Load base fw failed: %x", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dsp)
|
||||
*dsp = skl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bxt_sst_dsp_init);
|
||||
|
||||
|
||||
void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
|
||||
{
|
||||
skl_ipc_free(&ctx->ipc);
|
||||
ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
|
||||
|
||||
if (ctx->dsp->addr.lpe)
|
||||
iounmap(ctx->dsp->addr.lpe);
|
||||
|
||||
ctx->dsp->ops->free(ctx->dsp);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Intel Broxton IPC driver");
|
@ -72,6 +72,105 @@ static void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable)
|
||||
skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)&mask);
|
||||
}
|
||||
|
||||
static int skl_dsp_setup_spib(struct device *dev, unsigned int size,
|
||||
int stream_tag, int enable)
|
||||
{
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
struct hdac_stream *stream = snd_hdac_get_stream(bus,
|
||||
SNDRV_PCM_STREAM_PLAYBACK, stream_tag);
|
||||
struct hdac_ext_stream *estream;
|
||||
|
||||
if (!stream)
|
||||
return -EINVAL;
|
||||
|
||||
estream = stream_to_hdac_ext_stream(stream);
|
||||
/* enable/disable SPIB for this hdac stream */
|
||||
snd_hdac_ext_stream_spbcap_enable(ebus, enable, stream->index);
|
||||
|
||||
/* set the spib value */
|
||||
snd_hdac_ext_stream_set_spib(ebus, estream, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skl_dsp_prepare(struct device *dev, unsigned int format,
|
||||
unsigned int size, struct snd_dma_buffer *dmab)
|
||||
{
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
struct hdac_ext_stream *estream;
|
||||
struct hdac_stream *stream;
|
||||
struct snd_pcm_substream substream;
|
||||
int ret;
|
||||
|
||||
if (!bus)
|
||||
return -ENODEV;
|
||||
|
||||
memset(&substream, 0, sizeof(substream));
|
||||
substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
|
||||
|
||||
estream = snd_hdac_ext_stream_assign(ebus, &substream,
|
||||
HDAC_EXT_STREAM_TYPE_HOST);
|
||||
if (!estream)
|
||||
return -ENODEV;
|
||||
|
||||
stream = hdac_stream(estream);
|
||||
|
||||
/* assign decouple host dma channel */
|
||||
ret = snd_hdac_dsp_prepare(stream, format, size, dmab);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
skl_dsp_setup_spib(dev, size, stream->stream_tag, true);
|
||||
|
||||
return stream->stream_tag;
|
||||
}
|
||||
|
||||
static int skl_dsp_trigger(struct device *dev, bool start, int stream_tag)
|
||||
{
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
|
||||
struct hdac_stream *stream;
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
|
||||
if (!bus)
|
||||
return -ENODEV;
|
||||
|
||||
stream = snd_hdac_get_stream(bus,
|
||||
SNDRV_PCM_STREAM_PLAYBACK, stream_tag);
|
||||
if (!stream)
|
||||
return -EINVAL;
|
||||
|
||||
snd_hdac_dsp_trigger(stream, start);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skl_dsp_cleanup(struct device *dev,
|
||||
struct snd_dma_buffer *dmab, int stream_tag)
|
||||
{
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
|
||||
struct hdac_stream *stream;
|
||||
struct hdac_ext_stream *estream;
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
|
||||
if (!bus)
|
||||
return -ENODEV;
|
||||
|
||||
stream = snd_hdac_get_stream(bus,
|
||||
SNDRV_PCM_STREAM_PLAYBACK, stream_tag);
|
||||
if (!stream)
|
||||
return -EINVAL;
|
||||
|
||||
estream = stream_to_hdac_ext_stream(stream);
|
||||
skl_dsp_setup_spib(dev, 0, stream_tag, false);
|
||||
snd_hdac_ext_stream_release(estream, HDAC_EXT_STREAM_TYPE_HOST);
|
||||
|
||||
snd_hdac_dsp_cleanup(stream, dmab);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct skl_dsp_loader_ops skl_get_loader_ops(void)
|
||||
{
|
||||
struct skl_dsp_loader_ops loader_ops;
|
||||
@ -84,6 +183,21 @@ static struct skl_dsp_loader_ops skl_get_loader_ops(void)
|
||||
return loader_ops;
|
||||
};
|
||||
|
||||
static struct skl_dsp_loader_ops bxt_get_loader_ops(void)
|
||||
{
|
||||
struct skl_dsp_loader_ops loader_ops;
|
||||
|
||||
memset(&loader_ops, 0, sizeof(loader_ops));
|
||||
|
||||
loader_ops.alloc_dma_buf = skl_alloc_dma_buf;
|
||||
loader_ops.free_dma_buf = skl_free_dma_buf;
|
||||
loader_ops.prepare = skl_dsp_prepare;
|
||||
loader_ops.trigger = skl_dsp_trigger;
|
||||
loader_ops.cleanup = skl_dsp_cleanup;
|
||||
|
||||
return loader_ops;
|
||||
};
|
||||
|
||||
static const struct skl_dsp_ops dsp_ops[] = {
|
||||
{
|
||||
.id = 0x9d70,
|
||||
@ -91,6 +205,12 @@ static const struct skl_dsp_ops dsp_ops[] = {
|
||||
.init = skl_sst_dsp_init,
|
||||
.cleanup = skl_sst_dsp_cleanup
|
||||
},
|
||||
{
|
||||
.id = 0x5a98,
|
||||
.loader_ops = bxt_get_loader_ops,
|
||||
.init = bxt_sst_dsp_init,
|
||||
.cleanup = bxt_sst_dsp_cleanup
|
||||
},
|
||||
};
|
||||
|
||||
static int skl_get_dsp_ops(int pci_id)
|
||||
@ -744,7 +864,7 @@ int skl_init_module(struct skl_sst *ctx,
|
||||
return ret;
|
||||
}
|
||||
mconfig->m_state = SKL_MODULE_INIT_DONE;
|
||||
|
||||
kfree(param_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -25,11 +25,12 @@ static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45,
|
||||
|
||||
#define DSDT_NHLT_PATH "\\_SB.PCI0.HDAS"
|
||||
|
||||
void *skl_nhlt_init(struct device *dev)
|
||||
struct nhlt_acpi_table *skl_nhlt_init(struct device *dev)
|
||||
{
|
||||
acpi_handle handle;
|
||||
union acpi_object *obj;
|
||||
struct nhlt_resource_desc *nhlt_ptr = NULL;
|
||||
struct nhlt_acpi_table *nhlt_table = NULL;
|
||||
|
||||
if (ACPI_FAILURE(acpi_get_handle(NULL, DSDT_NHLT_PATH, &handle))) {
|
||||
dev_err(dev, "Requested NHLT device not found\n");
|
||||
@ -39,18 +40,20 @@ void *skl_nhlt_init(struct device *dev)
|
||||
obj = acpi_evaluate_dsm(handle, OSC_UUID, 1, 1, NULL);
|
||||
if (obj && obj->type == ACPI_TYPE_BUFFER) {
|
||||
nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer;
|
||||
|
||||
return memremap(nhlt_ptr->min_addr, nhlt_ptr->length,
|
||||
nhlt_table = (struct nhlt_acpi_table *)
|
||||
memremap(nhlt_ptr->min_addr, nhlt_ptr->length,
|
||||
MEMREMAP_WB);
|
||||
ACPI_FREE(obj);
|
||||
return nhlt_table;
|
||||
}
|
||||
|
||||
dev_err(dev, "device specific method to extract NHLT blob failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void skl_nhlt_free(void *addr)
|
||||
void skl_nhlt_free(struct nhlt_acpi_table *nhlt)
|
||||
{
|
||||
memunmap(addr);
|
||||
memunmap((void *) nhlt);
|
||||
}
|
||||
|
||||
static struct nhlt_specific_cfg *skl_get_specific_cfg(
|
||||
@ -120,7 +123,7 @@ struct nhlt_specific_cfg
|
||||
struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
|
||||
struct device *dev = bus->dev;
|
||||
struct nhlt_specific_cfg *sp_config;
|
||||
struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
|
||||
struct nhlt_acpi_table *nhlt = skl->nhlt;
|
||||
u16 bps = (s_fmt == 16) ? 16 : 32;
|
||||
u8 j;
|
||||
|
||||
|
@ -213,7 +213,7 @@ static int skl_be_prepare(struct snd_pcm_substream *substream,
|
||||
struct skl_sst *ctx = skl->skl_sst;
|
||||
struct skl_module_cfg *mconfig;
|
||||
|
||||
if ((dai->playback_active > 1) || (dai->capture_active > 1))
|
||||
if (dai->playback_widget->power || dai->capture_widget->power)
|
||||
return 0;
|
||||
|
||||
mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream);
|
||||
@ -402,23 +402,33 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct skl_module_cfg *mconfig;
|
||||
struct hdac_ext_bus *ebus = get_bus_ctx(substream);
|
||||
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
|
||||
struct snd_soc_dapm_widget *w;
|
||||
int ret;
|
||||
|
||||
mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
|
||||
if (!mconfig)
|
||||
return -EIO;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
w = dai->playback_widget;
|
||||
else
|
||||
w = dai->capture_widget;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
skl_pcm_prepare(substream, dai);
|
||||
/*
|
||||
* enable DMA Resume enable bit for the stream, set the dpib
|
||||
* & lpib position to resune before starting the DMA
|
||||
*/
|
||||
snd_hdac_ext_stream_drsm_enable(ebus, true,
|
||||
hdac_stream(stream)->index);
|
||||
snd_hdac_ext_stream_set_dpibr(ebus, stream, stream->dpib);
|
||||
snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
|
||||
if (!w->ignore_suspend) {
|
||||
skl_pcm_prepare(substream, dai);
|
||||
/*
|
||||
* enable DMA Resume enable bit for the stream, set the
|
||||
* dpib & lpib position to resume before starting the
|
||||
* DMA
|
||||
*/
|
||||
snd_hdac_ext_stream_drsm_enable(ebus, true,
|
||||
hdac_stream(stream)->index);
|
||||
snd_hdac_ext_stream_set_dpibr(ebus, stream,
|
||||
stream->dpib);
|
||||
snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
|
||||
}
|
||||
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
@ -448,7 +458,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
return ret;
|
||||
|
||||
ret = skl_decoupled_trigger(substream, cmd);
|
||||
if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) {
|
||||
if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) {
|
||||
/* save the dpib and lpib positions */
|
||||
stream->dpib = readl(ebus->bus.remap_addr +
|
||||
AZX_REG_VS_SDXDPIB_XBASE +
|
||||
@ -523,7 +533,6 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
|
||||
if (!link)
|
||||
return -EINVAL;
|
||||
|
||||
snd_hdac_ext_bus_link_power_up(link);
|
||||
snd_hdac_ext_link_stream_reset(link_dev);
|
||||
|
||||
snd_hdac_ext_link_stream_setup(link_dev, format_val);
|
||||
@ -759,6 +768,78 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "SSP2 Pin",
|
||||
.ops = &skl_be_ssp_dai_ops,
|
||||
.playback = {
|
||||
.stream_name = "ssp2 Tx",
|
||||
.channels_min = HDA_STEREO,
|
||||
.channels_max = HDA_STEREO,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "ssp2 Rx",
|
||||
.channels_min = HDA_STEREO,
|
||||
.channels_max = HDA_STEREO,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "SSP3 Pin",
|
||||
.ops = &skl_be_ssp_dai_ops,
|
||||
.playback = {
|
||||
.stream_name = "ssp3 Tx",
|
||||
.channels_min = HDA_STEREO,
|
||||
.channels_max = HDA_STEREO,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "ssp3 Rx",
|
||||
.channels_min = HDA_STEREO,
|
||||
.channels_max = HDA_STEREO,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "SSP4 Pin",
|
||||
.ops = &skl_be_ssp_dai_ops,
|
||||
.playback = {
|
||||
.stream_name = "ssp4 Tx",
|
||||
.channels_min = HDA_STEREO,
|
||||
.channels_max = HDA_STEREO,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "ssp4 Rx",
|
||||
.channels_min = HDA_STEREO,
|
||||
.channels_max = HDA_STEREO,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "SSP5 Pin",
|
||||
.ops = &skl_be_ssp_dai_ops,
|
||||
.playback = {
|
||||
.stream_name = "ssp5 Tx",
|
||||
.channels_min = HDA_STEREO,
|
||||
.channels_max = HDA_STEREO,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "ssp5 Rx",
|
||||
.channels_min = HDA_STEREO,
|
||||
.channels_max = HDA_STEREO,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "iDisp1 Pin",
|
||||
.ops = &skl_link_dai_ops,
|
||||
|
@ -336,8 +336,6 @@ void skl_dsp_free(struct sst_dsp *dsp)
|
||||
skl_ipc_int_disable(dsp);
|
||||
|
||||
free_irq(dsp->irq, dsp);
|
||||
dsp->cl_dev.ops.cl_cleanup_controller(dsp);
|
||||
skl_cldma_int_disable(dsp);
|
||||
skl_ipc_op_int_disable(dsp);
|
||||
skl_ipc_int_disable(dsp);
|
||||
|
||||
|
@ -118,16 +118,25 @@ struct skl_dsp_fw_ops {
|
||||
int (*set_state_D0)(struct sst_dsp *ctx);
|
||||
int (*set_state_D3)(struct sst_dsp *ctx);
|
||||
unsigned int (*get_fw_errcode)(struct sst_dsp *ctx);
|
||||
int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, char *mod_name);
|
||||
int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name);
|
||||
int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id);
|
||||
|
||||
};
|
||||
|
||||
struct skl_dsp_loader_ops {
|
||||
int stream_tag;
|
||||
|
||||
int (*alloc_dma_buf)(struct device *dev,
|
||||
struct snd_dma_buffer *dmab, size_t size);
|
||||
int (*free_dma_buf)(struct device *dev,
|
||||
struct snd_dma_buffer *dmab);
|
||||
int (*prepare)(struct device *dev, unsigned int format,
|
||||
unsigned int byte_size,
|
||||
struct snd_dma_buffer *bufp);
|
||||
int (*trigger)(struct device *dev, bool start, int stream_tag);
|
||||
|
||||
int (*cleanup)(struct device *dev, struct snd_dma_buffer *dmab,
|
||||
int stream_tag);
|
||||
};
|
||||
|
||||
struct skl_load_module_info {
|
||||
@ -160,6 +169,10 @@ int skl_dsp_boot(struct sst_dsp *ctx);
|
||||
int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
||||
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
|
||||
struct skl_sst **dsp);
|
||||
int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
||||
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
|
||||
struct skl_sst **dsp);
|
||||
void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
|
||||
void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
|
||||
|
||||
#endif /*__SKL_SST_DSP_H__*/
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/uuid.h>
|
||||
#include "../common/sst-dsp.h"
|
||||
#include "../common/sst-dsp-priv.h"
|
||||
#include "../common/sst-ipc.h"
|
||||
@ -304,14 +305,16 @@ static int skl_transfer_module(struct sst_dsp *ctx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, char *guid)
|
||||
static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid)
|
||||
{
|
||||
struct skl_module_table *module_entry = NULL;
|
||||
int ret = 0;
|
||||
char mod_name[64]; /* guid str = 32 chars + 4 hyphens */
|
||||
uuid_le *uuid_mod;
|
||||
|
||||
snprintf(mod_name, sizeof(mod_name), "%s%s%s",
|
||||
"intel/dsp_fw_", guid, ".bin");
|
||||
uuid_mod = (uuid_le *)guid;
|
||||
snprintf(mod_name, sizeof(mod_name), "%s%pUL%s",
|
||||
"intel/dsp_fw_", uuid_mod, ".bin");
|
||||
|
||||
module_entry = skl_module_get_from_id(ctx, mod_id);
|
||||
if (module_entry == NULL) {
|
||||
@ -451,6 +454,10 @@ void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
|
||||
skl_clear_module_table(ctx->dsp);
|
||||
skl_ipc_free(&ctx->ipc);
|
||||
ctx->dsp->ops->free(ctx->dsp);
|
||||
if (ctx->boot_complete) {
|
||||
ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
|
||||
skl_cldma_int_disable(ctx->dsp);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup);
|
||||
|
||||
|
@ -1564,6 +1564,8 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
|
||||
return -ENOMEM;
|
||||
|
||||
w->priv = mconfig;
|
||||
memcpy(&mconfig->guid, &dfw_config->uuid, 16);
|
||||
|
||||
mconfig->id.module_id = dfw_config->module_id;
|
||||
mconfig->id.instance_id = dfw_config->instance_id;
|
||||
mconfig->mcps = dfw_config->max_mcps;
|
||||
@ -1593,10 +1595,6 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
|
||||
mconfig->time_slot = dfw_config->time_slot;
|
||||
mconfig->formats_config.caps_size = dfw_config->caps.caps_size;
|
||||
|
||||
if (dfw_config->is_loadable)
|
||||
memcpy(mconfig->guid, dfw_config->uuid,
|
||||
ARRAY_SIZE(dfw_config->uuid));
|
||||
|
||||
mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) *
|
||||
sizeof(*mconfig->m_in_pin),
|
||||
GFP_KERNEL);
|
||||
|
@ -281,7 +281,7 @@ enum skl_module_state {
|
||||
};
|
||||
|
||||
struct skl_module_cfg {
|
||||
char guid[SKL_UUID_STR_SZ];
|
||||
u8 guid[16];
|
||||
struct skl_module_inst_id id;
|
||||
u8 domain;
|
||||
bool homogenous_inputs;
|
||||
|
@ -181,7 +181,7 @@ struct skl_dfw_pipe {
|
||||
} __packed;
|
||||
|
||||
struct skl_dfw_module {
|
||||
char uuid[SKL_UUID_STR_SZ];
|
||||
u8 uuid[16];
|
||||
|
||||
u16 module_id;
|
||||
u16 instance_id;
|
||||
|
@ -229,7 +229,12 @@ static int skl_suspend(struct device *dev)
|
||||
* running, we need to save the state for these and continue
|
||||
*/
|
||||
if (skl->supend_active) {
|
||||
/* turn off the links and stop the CORB/RIRB DMA if it is On */
|
||||
snd_hdac_ext_bus_link_power_down_all(ebus);
|
||||
|
||||
if (ebus->cmd_dma_state)
|
||||
snd_hdac_bus_stop_cmd_io(&ebus->bus);
|
||||
|
||||
enable_irq_wake(bus->irq);
|
||||
pci_save_state(pci);
|
||||
pci_disable_device(pci);
|
||||
@ -255,6 +260,7 @@ static int skl_resume(struct device *dev)
|
||||
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
|
||||
struct skl *skl = ebus_to_skl(ebus);
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
struct hdac_ext_link *hlink = NULL;
|
||||
int ret;
|
||||
|
||||
/* Turned OFF in HDMI codec driver after codec reconfiguration */
|
||||
@ -276,8 +282,29 @@ static int skl_resume(struct device *dev)
|
||||
ret = pci_enable_device(pci);
|
||||
snd_hdac_ext_bus_link_power_up_all(ebus);
|
||||
disable_irq_wake(bus->irq);
|
||||
/*
|
||||
* turn On the links which are On before active suspend
|
||||
* and start the CORB/RIRB DMA if On before
|
||||
* active suspend.
|
||||
*/
|
||||
list_for_each_entry(hlink, &ebus->hlink_list, list) {
|
||||
if (hlink->ref_count)
|
||||
snd_hdac_ext_bus_link_power_up(hlink);
|
||||
}
|
||||
|
||||
if (ebus->cmd_dma_state)
|
||||
snd_hdac_bus_init_cmd_io(&ebus->bus);
|
||||
} else {
|
||||
ret = _skl_resume(ebus);
|
||||
|
||||
/* turn off the links which are off before suspend */
|
||||
list_for_each_entry(hlink, &ebus->hlink_list, list) {
|
||||
if (!hlink->ref_count)
|
||||
snd_hdac_ext_bus_link_power_down(hlink);
|
||||
}
|
||||
|
||||
if (!ebus->cmd_dma_state)
|
||||
snd_hdac_bus_stop_cmd_io(&ebus->bus);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -613,6 +640,7 @@ static int skl_probe(struct pci_dev *pci,
|
||||
struct skl *skl;
|
||||
struct hdac_ext_bus *ebus = NULL;
|
||||
struct hdac_bus *bus = NULL;
|
||||
struct hdac_ext_link *hlink = NULL;
|
||||
int err;
|
||||
|
||||
/* we use ext core ops, so provide NULL for ops here */
|
||||
@ -643,7 +671,7 @@ static int skl_probe(struct pci_dev *pci,
|
||||
err = skl_machine_device_register(skl,
|
||||
(void *)pci_id->driver_data);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
goto out_nhlt_free;
|
||||
|
||||
err = skl_init_dsp(skl);
|
||||
if (err < 0) {
|
||||
@ -679,6 +707,12 @@ static int skl_probe(struct pci_dev *pci,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* we are done probling so decrement link counts
|
||||
*/
|
||||
list_for_each_entry(hlink, &ebus->hlink_list, list)
|
||||
snd_hdac_ext_bus_link_put(ebus, hlink);
|
||||
|
||||
/*configure PM */
|
||||
pm_runtime_put_noidle(bus->dev);
|
||||
pm_runtime_allow(bus->dev);
|
||||
@ -693,6 +727,8 @@ out_dsp_free:
|
||||
skl_free_dsp(skl);
|
||||
out_mach_free:
|
||||
skl_machine_device_unregister(skl);
|
||||
out_nhlt_free:
|
||||
skl_nhlt_free(skl->nhlt);
|
||||
out_free:
|
||||
skl->init_failed = 1;
|
||||
skl_free(ebus);
|
||||
@ -743,6 +779,7 @@ static void skl_remove(struct pci_dev *pci)
|
||||
skl_free_dsp(skl);
|
||||
skl_machine_device_unregister(skl);
|
||||
skl_dmic_device_unregister(skl);
|
||||
skl_nhlt_free(skl->nhlt);
|
||||
skl_free(ebus);
|
||||
dev_set_drvdata(&pci->dev, NULL);
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ struct skl {
|
||||
struct platform_device *dmic_dev;
|
||||
struct platform_device *i2s_dev;
|
||||
|
||||
void *nhlt; /* nhlt ptr */
|
||||
struct nhlt_acpi_table *nhlt; /* nhlt ptr */
|
||||
struct skl_sst *skl_sst; /* sst skl ctx */
|
||||
|
||||
struct skl_dsp_resource resource;
|
||||
@ -103,8 +103,8 @@ struct skl_dsp_ops {
|
||||
int skl_platform_unregister(struct device *dev);
|
||||
int skl_platform_register(struct device *dev);
|
||||
|
||||
void *skl_nhlt_init(struct device *dev);
|
||||
void skl_nhlt_free(void *addr);
|
||||
struct nhlt_acpi_table *skl_nhlt_init(struct device *dev);
|
||||
void skl_nhlt_free(struct nhlt_acpi_table *addr);
|
||||
struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance,
|
||||
u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user