Commit c988e261 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/intel' into asoc-next

parents 35302156 b2047e99
......@@ -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,
......
/*
* 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
/*
* 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 @@ static int skl_probe(struct pci_dev *pci,
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment