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 @@ ...@@ -14,6 +14,8 @@
* @gtscap: gts capabilities pointer * @gtscap: gts capabilities pointer
* @drsmcap: dma resume capabilities pointer * @drsmcap: dma resume capabilities pointer
* @hlink_list: link list of HDA links * @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_ext_bus {
struct hdac_bus bus; struct hdac_bus bus;
...@@ -27,6 +29,9 @@ struct hdac_ext_bus { ...@@ -27,6 +29,9 @@ struct hdac_ext_bus {
void __iomem *drsmcap; void __iomem *drsmcap;
struct list_head hlink_list; 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, int snd_hdac_ext_bus_init(struct hdac_ext_bus *sbus, struct device *dev,
...@@ -142,6 +147,9 @@ struct hdac_ext_link { ...@@ -142,6 +147,9 @@ struct hdac_ext_link {
void __iomem *ml_addr; /* link output stream reg pointer */ void __iomem *ml_addr; /* link output stream reg pointer */
u32 lcaps; /* link capablities */ u32 lcaps; /* link capablities */
u16 lsdiid; /* link sdi identifier */ u16 lsdiid; /* link sdi identifier */
int ref_count;
struct list_head list; struct list_head list;
}; };
...@@ -154,6 +162,11 @@ void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link, ...@@ -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, void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
int stream); 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 */ /* update register macro */
#define snd_hdac_updatel(addr, reg, mask, val) \ #define snd_hdac_updatel(addr, reg, mask, val) \
writel(((readl(addr + reg) & ~(mask)) | (val)), \ writel(((readl(addr + reg) & ~(mask)) | (val)), \
......
...@@ -1002,7 +1002,7 @@ struct snd_soc_dai_link { ...@@ -1002,7 +1002,7 @@ struct snd_soc_dai_link {
*/ */
const char *platform_name; const char *platform_name;
struct device_node *platform_of_node; 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; const struct snd_soc_pcm_stream *params;
unsigned int num_params; unsigned int num_params;
......
...@@ -105,6 +105,9 @@ int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev, ...@@ -105,6 +105,9 @@ int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev,
INIT_LIST_HEAD(&ebus->hlink_list); INIT_LIST_HEAD(&ebus->hlink_list);
ebus->idx = idx++; ebus->idx = idx++;
mutex_init(&ebus->lock);
ebus->cmd_dma_state = true;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init); 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) ...@@ -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->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP);
hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID); 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); 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) ...@@ -327,3 +330,66 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all); 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) ...@@ -1378,10 +1378,18 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec)
struct snd_soc_dapm_context *dapm = struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(&codec->component); snd_soc_component_get_dapm(&codec->component);
struct hdac_hdmi_pin *pin; struct hdac_hdmi_pin *pin;
struct hdac_ext_link *hlink = NULL;
int ret; int ret;
edev->scodec = codec; 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); ret = create_fill_widget_route_map(dapm);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1480,9 +1488,14 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) ...@@ -1480,9 +1488,14 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
struct hdac_device *codec = &edev->hdac; struct hdac_device *codec = &edev->hdac;
struct hdac_hdmi_priv *hdmi_priv; struct hdac_hdmi_priv *hdmi_priv;
struct snd_soc_dai_driver *hdmi_dais = NULL; struct snd_soc_dai_driver *hdmi_dais = NULL;
struct hdac_ext_link *hlink = NULL;
int num_dais = 0; int num_dais = 0;
int ret = 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); hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL);
if (hdmi_priv == NULL) if (hdmi_priv == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -1516,8 +1529,12 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) ...@@ -1516,8 +1529,12 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
} }
/* ASoC specific initialization */ /* ASoC specific initialization */
return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, ret = snd_soc_register_codec(&codec->dev, &hdmi_hda_codec,
hdmi_dais, num_dais); 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) static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
...@@ -1556,6 +1573,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) ...@@ -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_ext_device *edev = to_hda_ext_device(dev);
struct hdac_device *hdac = &edev->hdac; struct hdac_device *hdac = &edev->hdac;
struct hdac_bus *bus = hdac->bus; 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; int err;
dev_dbg(dev, "Enter: %s\n", __func__); dev_dbg(dev, "Enter: %s\n", __func__);
...@@ -1579,6 +1599,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) ...@@ -1579,6 +1599,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
return err; return err;
} }
hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev));
snd_hdac_ext_bus_link_put(ebus, hlink);
return 0; return 0;
} }
...@@ -1587,6 +1610,8 @@ static int hdac_hdmi_runtime_resume(struct device *dev) ...@@ -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_ext_device *edev = to_hda_ext_device(dev);
struct hdac_device *hdac = &edev->hdac; struct hdac_device *hdac = &edev->hdac;
struct hdac_bus *bus = hdac->bus; struct hdac_bus *bus = hdac->bus;
struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
struct hdac_ext_link *hlink = NULL;
int err; int err;
dev_dbg(dev, "Enter: %s\n", __func__); dev_dbg(dev, "Enter: %s\n", __func__);
...@@ -1595,6 +1620,9 @@ static int hdac_hdmi_runtime_resume(struct device *dev) ...@@ -1595,6 +1620,9 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
if (!bus) if (!bus)
return 0; 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); err = snd_hdac_display_power(bus, true);
if (err < 0) { if (err < 0) {
dev_err(bus->dev, "Cannot turn on display power on i915\n"); dev_err(bus->dev, "Cannot turn on display power on i915\n");
......
...@@ -58,6 +58,21 @@ config SND_SOC_INTEL_HASWELL_MACH ...@@ -58,6 +58,21 @@ config SND_SOC_INTEL_HASWELL_MACH
Say Y if you have such a device Say Y if you have such a device
If unsure select "N". If unsure select "N".
config SND_SOC_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 config SND_SOC_INTEL_BYT_RT5640_MACH
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
depends on X86_INTEL_LPSS && I2C depends on X86_INTEL_LPSS && I2C
...@@ -162,6 +177,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH ...@@ -162,6 +177,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
config SND_SOC_INTEL_SKYLAKE config SND_SOC_INTEL_SKYLAKE
tristate tristate
select SND_HDA_EXT_CORE select SND_HDA_EXT_CORE
select SND_HDA_DSP_LOADER
select SND_SOC_TOPOLOGY select SND_SOC_TOPOLOGY
select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST
......
...@@ -195,7 +195,7 @@ static int sst_check_and_send_slot_map(struct sst_data *drv, struct snd_kcontrol ...@@ -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) if (e->w && e->w->power)
ret = sst_send_slot_map(drv); 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", dev_err(&drv->pdev->dev, "Slot control: %s doesn't have DAPM widget!!!\n",
kcontrol->id.name); kcontrol->id.name);
return ret; return ret;
......
...@@ -2,6 +2,7 @@ snd-soc-sst-haswell-objs := haswell.o ...@@ -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-rt5640-mach-objs := byt-rt5640.o
snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
snd-soc-sst-broadwell-objs := broadwell.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-rt5640-objs := bytcr_rt5640.o
snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o
snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.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 ...@@ -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_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_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_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_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_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.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[] = { ...@@ -201,7 +201,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
{ {
/* SSP0 - Codec */ /* SSP0 - Codec */
.name = "Codec", .name = "Codec",
.be_id = 0, .id = 0,
.cpu_dai_name = "snd-soc-dummy-dai", .cpu_dai_name = "snd-soc-dummy-dai",
.platform_name = "snd-soc-dummy", .platform_name = "snd-soc-dummy",
.no_pcm = 1, .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[] = { ...@@ -304,7 +304,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = {
/* back ends */ /* back ends */
{ {
.name = "SSP2-Codec", .name = "SSP2-Codec",
.be_id = 1, .id = 1,
.cpu_dai_name = "ssp2-port", .cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform", .platform_name = "sst-mfld-platform",
.no_pcm = 1, .no_pcm = 1,
......
...@@ -267,7 +267,7 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { ...@@ -267,7 +267,7 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = {
/* back ends */ /* back ends */
{ {
.name = "SSP2-Codec", .name = "SSP2-Codec",
.be_id = 1, .id = 1,
.cpu_dai_name = "ssp2-port", .cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform", .platform_name = "sst-mfld-platform",
.no_pcm = 1, .no_pcm = 1,
......
...@@ -255,7 +255,7 @@ static struct snd_soc_dai_link cht_dailink[] = { ...@@ -255,7 +255,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
/* back ends */ /* back ends */
{ {
.name = "SSP2-Codec", .name = "SSP2-Codec",
.be_id = 1, .id = 1,
.cpu_dai_name = "ssp2-port", .cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform", .platform_name = "sst-mfld-platform",
.no_pcm = 1, .no_pcm = 1,
......
...@@ -295,7 +295,7 @@ static struct snd_soc_dai_link cht_dailink[] = { ...@@ -295,7 +295,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
/* back ends */ /* back ends */
{ {
.name = "SSP2-Codec", .name = "SSP2-Codec",
.be_id = 1, .id = 1,
.cpu_dai_name = "ssp2-port", .cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform", .platform_name = "sst-mfld-platform",
.no_pcm = 1, .no_pcm = 1,
......
...@@ -273,7 +273,7 @@ static struct snd_soc_dai_link cht_dailink[] = { ...@@ -273,7 +273,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
{ {
/* SSP2 - Codec */ /* SSP2 - Codec */
.name = "SSP2-Codec", .name = "SSP2-Codec",
.be_id = 1, .id = 1,
.cpu_dai_name = "ssp2-port", .cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform", .platform_name = "sst-mfld-platform",
.no_pcm = 1, .no_pcm = 1,
......
...@@ -156,7 +156,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { ...@@ -156,7 +156,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = {
{ {
/* SSP0 - Codec */ /* SSP0 - Codec */
.name = "Codec", .name = "Codec",
.be_id = 0, .id = 0,
.cpu_dai_name = "snd-soc-dummy-dai", .cpu_dai_name = "snd-soc-dummy-dai",
.platform_name = "snd-soc-dummy", .platform_name = "snd-soc-dummy",
.no_pcm = 1, .no_pcm = 1,
......
...@@ -391,7 +391,6 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -391,7 +391,6 @@ static struct snd_soc_dai_link skylake_dais[] = {
.platform_name = "0000:00:1f.3", .platform_name = "0000:00:1f.3",
.init = NULL, .init = NULL,
.dpcm_capture = 1, .dpcm_capture = 1,
.ignore_suspend = 1,
.nonatomic = 1, .nonatomic = 1,
.dynamic = 1, .dynamic = 1,
.ops = &skylaye_refcap_ops, .ops = &skylaye_refcap_ops,
...@@ -456,7 +455,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -456,7 +455,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
{ {
/* SSP0 - Codec */ /* SSP0 - Codec */
.name = "SSP0-Codec", .name = "SSP0-Codec",
.be_id = 0, .id = 0,
.cpu_dai_name = "SSP0 Pin", .cpu_dai_name = "SSP0 Pin",
.platform_name = "0000:00:1f.3", .platform_name = "0000:00:1f.3",
.no_pcm = 1, .no_pcm = 1,
...@@ -472,7 +471,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -472,7 +471,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
{ {
/* SSP1 - Codec */ /* SSP1 - Codec */
.name = "SSP1-Codec", .name = "SSP1-Codec",
.be_id = 1, .id = 1,
.cpu_dai_name = "SSP1 Pin", .cpu_dai_name = "SSP1 Pin",
.platform_name = "0000:00:1f.3", .platform_name = "0000:00:1f.3",
.no_pcm = 1, .no_pcm = 1,
...@@ -489,7 +488,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -489,7 +488,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
}, },
{ {
.name = "dmic01", .name = "dmic01",
.be_id = 2, .id = 2,
.cpu_dai_name = "DMIC01 Pin", .cpu_dai_name = "DMIC01 Pin",
.codec_name = "dmic-codec", .codec_name = "dmic-codec",
.codec_dai_name = "dmic-hifi", .codec_dai_name = "dmic-hifi",
...@@ -501,7 +500,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -501,7 +500,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
}, },
{ {
.name = "iDisp1", .name = "iDisp1",
.be_id = 3, .id = 3,
.cpu_dai_name = "iDisp1 Pin", .cpu_dai_name = "iDisp1 Pin",
.codec_name = "ehdaudio0D2", .codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi1", .codec_dai_name = "intel-hdmi-hifi1",
...@@ -512,7 +511,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -512,7 +511,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
}, },
{ {
.name = "iDisp2", .name = "iDisp2",
.be_id = 4, .id = 4,
.cpu_dai_name = "iDisp2 Pin", .cpu_dai_name = "iDisp2 Pin",
.codec_name = "ehdaudio0D2", .codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi2", .codec_dai_name = "intel-hdmi-hifi2",
...@@ -523,7 +522,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -523,7 +522,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
}, },
{ {
.name = "iDisp3", .name = "iDisp3",
.be_id = 5, .id = 5,
.cpu_dai_name = "iDisp3 Pin", .cpu_dai_name = "iDisp3 Pin",
.codec_name = "ehdaudio0D2", .codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi3", .codec_dai_name = "intel-hdmi-hifi3",
......
...@@ -440,7 +440,6 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -440,7 +440,6 @@ static struct snd_soc_dai_link skylake_dais[] = {
.platform_name = "0000:00:1f.3", .platform_name = "0000:00:1f.3",
.init = NULL, .init = NULL,
.dpcm_capture = 1, .dpcm_capture = 1,
.ignore_suspend = 1,
.nonatomic = 1, .nonatomic = 1,
.dynamic = 1, .dynamic = 1,
.ops = &skylaye_refcap_ops, .ops = &skylaye_refcap_ops,
...@@ -505,7 +504,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -505,7 +504,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
{ {
/* SSP0 - Codec */ /* SSP0 - Codec */
.name = "SSP0-Codec", .name = "SSP0-Codec",
.be_id = 0, .id = 0,
.cpu_dai_name = "SSP0 Pin", .cpu_dai_name = "SSP0 Pin",
.platform_name = "0000:00:1f.3", .platform_name = "0000:00:1f.3",
.no_pcm = 1, .no_pcm = 1,
...@@ -523,7 +522,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -523,7 +522,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
{ {
/* SSP1 - Codec */ /* SSP1 - Codec */
.name = "SSP1-Codec", .name = "SSP1-Codec",
.be_id = 1, .id = 1,
.cpu_dai_name = "SSP1 Pin", .cpu_dai_name = "SSP1 Pin",
.platform_name = "0000:00:1f.3", .platform_name = "0000:00:1f.3",
.no_pcm = 1, .no_pcm = 1,
...@@ -540,7 +539,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -540,7 +539,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
}, },
{ {
.name = "dmic01", .name = "dmic01",
.be_id = 2, .id = 2,
.cpu_dai_name = "DMIC01 Pin", .cpu_dai_name = "DMIC01 Pin",
.codec_name = "dmic-codec", .codec_name = "dmic-codec",
.codec_dai_name = "dmic-hifi", .codec_dai_name = "dmic-hifi",
...@@ -552,7 +551,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -552,7 +551,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
}, },
{ {
.name = "iDisp1", .name = "iDisp1",
.be_id = 3, .id = 3,
.cpu_dai_name = "iDisp1 Pin", .cpu_dai_name = "iDisp1 Pin",
.codec_name = "ehdaudio0D2", .codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi1", .codec_dai_name = "intel-hdmi-hifi1",
...@@ -563,7 +562,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -563,7 +562,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
}, },
{ {
.name = "iDisp2", .name = "iDisp2",
.be_id = 4, .id = 4,
.cpu_dai_name = "iDisp2 Pin", .cpu_dai_name = "iDisp2 Pin",
.codec_name = "ehdaudio0D2", .codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi2", .codec_dai_name = "intel-hdmi-hifi2",
...@@ -574,7 +573,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -574,7 +573,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
}, },
{ {
.name = "iDisp3", .name = "iDisp3",
.be_id = 5, .id = 5,
.cpu_dai_name = "iDisp3 Pin", .cpu_dai_name = "iDisp3 Pin",
.codec_name = "ehdaudio0D2", .codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi3", .codec_dai_name = "intel-hdmi-hifi3",
......
...@@ -317,7 +317,6 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { ...@@ -317,7 +317,6 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.platform_name = "0000:00:1f.3", .platform_name = "0000:00:1f.3",
.init = NULL, .init = NULL,
.dpcm_capture = 1, .dpcm_capture = 1,
.ignore_suspend = 1,
.nonatomic = 1, .nonatomic = 1,
.dynamic = 1, .dynamic = 1,
}, },
...@@ -375,7 +374,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { ...@@ -375,7 +374,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
{ {
/* SSP0 - Codec */ /* SSP0 - Codec */
.name = "SSP0-Codec", .name = "SSP0-Codec",
.be_id = 0, .id = 0,
.cpu_dai_name = "SSP0 Pin", .cpu_dai_name = "SSP0 Pin",
.platform_name = "0000:00:1f.3", .platform_name = "0000:00:1f.3",
.no_pcm = 1, .no_pcm = 1,
...@@ -393,7 +392,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { ...@@ -393,7 +392,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
}, },
{ {
.name = "dmic01", .name = "dmic01",
.be_id = 1, .id = 1,
.cpu_dai_name = "DMIC01 Pin", .cpu_dai_name = "DMIC01 Pin",
.codec_name = "dmic-codec", .codec_name = "dmic-codec",
.codec_dai_name = "dmic-hifi", .codec_dai_name = "dmic-hifi",
...@@ -405,7 +404,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { ...@@ -405,7 +404,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
}, },
{ {
.name = "iDisp1", .name = "iDisp1",
.be_id = 2, .id = 2,
.cpu_dai_name = "iDisp1 Pin", .cpu_dai_name = "iDisp1 Pin",
.codec_name = "ehdaudio0D2", .codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi1", .codec_dai_name = "intel-hdmi-hifi1",
...@@ -416,7 +415,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { ...@@ -416,7 +415,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
}, },
{ {
.name = "iDisp2", .name = "iDisp2",
.be_id = 3, .id = 3,
.cpu_dai_name = "iDisp2 Pin", .cpu_dai_name = "iDisp2 Pin",
.codec_name = "ehdaudio0D2", .codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi2", .codec_dai_name = "intel-hdmi-hifi2",
...@@ -427,7 +426,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { ...@@ -427,7 +426,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
}, },
{ {
.name = "iDisp3", .name = "iDisp3",
.be_id = 4, .id = 4,
.cpu_dai_name = "iDisp3 Pin", .cpu_dai_name = "iDisp3 Pin",
.codec_name = "ehdaudio0D2", .codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi3", .codec_dai_name = "intel-hdmi-hifi3",
......
...@@ -12,10 +12,19 @@ ...@@ -12,10 +12,19 @@
* *
*/ */
#include <linux/kconfig.h>
#include <linux/stddef.h>
#include <linux/acpi.h> #include <linux/acpi.h>
/* translation fron HID to I2C name, needed for DAI codec_name */ /* 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]); 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 */ /* acpi match */
struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines); 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, ...@@ -445,7 +445,7 @@ static int create_adsp_page_table(struct snd_pcm_substream *substream,
pages = snd_sgbuf_aligned_pages(size); 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); dma_area, size, pages);
for (i = 0; i < pages; i++) { for (i = 0; i < pages; i++) {
......
...@@ -5,6 +5,6 @@ obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o ...@@ -5,6 +5,6 @@ obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
# Skylake IPC Support # Skylake IPC Support
snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \ 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 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) ...@@ -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); 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) static struct skl_dsp_loader_ops skl_get_loader_ops(void)
{ {
struct skl_dsp_loader_ops loader_ops; struct skl_dsp_loader_ops loader_ops;
...@@ -84,6 +183,21 @@ static struct skl_dsp_loader_ops skl_get_loader_ops(void) ...@@ -84,6 +183,21 @@ static struct skl_dsp_loader_ops skl_get_loader_ops(void)
return loader_ops; 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[] = { static const struct skl_dsp_ops dsp_ops[] = {
{ {
.id = 0x9d70, .id = 0x9d70,
...@@ -91,6 +205,12 @@ static const struct skl_dsp_ops dsp_ops[] = { ...@@ -91,6 +205,12 @@ static const struct skl_dsp_ops dsp_ops[] = {
.init = skl_sst_dsp_init, .init = skl_sst_dsp_init,
.cleanup = skl_sst_dsp_cleanup .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) static int skl_get_dsp_ops(int pci_id)
...@@ -744,7 +864,7 @@ int skl_init_module(struct skl_sst *ctx, ...@@ -744,7 +864,7 @@ int skl_init_module(struct skl_sst *ctx,
return ret; return ret;
} }
mconfig->m_state = SKL_MODULE_INIT_DONE; mconfig->m_state = SKL_MODULE_INIT_DONE;
kfree(param_data);
return ret; return ret;
} }
......
...@@ -25,11 +25,12 @@ static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45, ...@@ -25,11 +25,12 @@ static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45,
#define DSDT_NHLT_PATH "\\_SB.PCI0.HDAS" #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; acpi_handle handle;
union acpi_object *obj; union acpi_object *obj;
struct nhlt_resource_desc *nhlt_ptr = NULL; 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))) { if (ACPI_FAILURE(acpi_get_handle(NULL, DSDT_NHLT_PATH, &handle))) {
dev_err(dev, "Requested NHLT device not found\n"); dev_err(dev, "Requested NHLT device not found\n");
...@@ -39,18 +40,20 @@ void *skl_nhlt_init(struct device *dev) ...@@ -39,18 +40,20 @@ void *skl_nhlt_init(struct device *dev)
obj = acpi_evaluate_dsm(handle, OSC_UUID, 1, 1, NULL); obj = acpi_evaluate_dsm(handle, OSC_UUID, 1, 1, NULL);
if (obj && obj->type == ACPI_TYPE_BUFFER) { if (obj && obj->type == ACPI_TYPE_BUFFER) {
nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer; nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer;
nhlt_table = (struct nhlt_acpi_table *)
return memremap(nhlt_ptr->min_addr, nhlt_ptr->length, memremap(nhlt_ptr->min_addr, nhlt_ptr->length,
MEMREMAP_WB); MEMREMAP_WB);
ACPI_FREE(obj);
return nhlt_table;
} }
dev_err(dev, "device specific method to extract NHLT blob failed\n"); dev_err(dev, "device specific method to extract NHLT blob failed\n");
return NULL; 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( static struct nhlt_specific_cfg *skl_get_specific_cfg(
...@@ -120,7 +123,7 @@ struct nhlt_specific_cfg ...@@ -120,7 +123,7 @@ struct nhlt_specific_cfg
struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
struct device *dev = bus->dev; struct device *dev = bus->dev;
struct nhlt_specific_cfg *sp_config; 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; u16 bps = (s_fmt == 16) ? 16 : 32;
u8 j; u8 j;
......
...@@ -213,7 +213,7 @@ static int skl_be_prepare(struct snd_pcm_substream *substream, ...@@ -213,7 +213,7 @@ static int skl_be_prepare(struct snd_pcm_substream *substream,
struct skl_sst *ctx = skl->skl_sst; struct skl_sst *ctx = skl->skl_sst;
struct skl_module_cfg *mconfig; 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; return 0;
mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); 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, ...@@ -402,23 +402,33 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct skl_module_cfg *mconfig; struct skl_module_cfg *mconfig;
struct hdac_ext_bus *ebus = get_bus_ctx(substream); struct hdac_ext_bus *ebus = get_bus_ctx(substream);
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
struct snd_soc_dapm_widget *w;
int ret; int ret;
mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
if (!mconfig) if (!mconfig)
return -EIO; return -EIO;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
w = dai->playback_widget;
else
w = dai->capture_widget;
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
skl_pcm_prepare(substream, dai); if (!w->ignore_suspend) {
/* skl_pcm_prepare(substream, dai);
* enable DMA Resume enable bit for the stream, set the dpib /*
* & lpib position to resune before starting the DMA * enable DMA Resume enable bit for the stream, set the
*/ * dpib & lpib position to resume before starting the
snd_hdac_ext_stream_drsm_enable(ebus, true, * DMA
hdac_stream(stream)->index); */
snd_hdac_ext_stream_set_dpibr(ebus, stream, stream->dpib); snd_hdac_ext_stream_drsm_enable(ebus, true,
snd_hdac_ext_stream_set_lpib(stream, stream->lpib); 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_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
...@@ -448,7 +458,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -448,7 +458,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
return ret; return ret;
ret = skl_decoupled_trigger(substream, cmd); 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 */ /* save the dpib and lpib positions */
stream->dpib = readl(ebus->bus.remap_addr + stream->dpib = readl(ebus->bus.remap_addr +
AZX_REG_VS_SDXDPIB_XBASE + AZX_REG_VS_SDXDPIB_XBASE +
...@@ -523,7 +533,6 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, ...@@ -523,7 +533,6 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
if (!link) if (!link)
return -EINVAL; return -EINVAL;
snd_hdac_ext_bus_link_power_up(link);
snd_hdac_ext_link_stream_reset(link_dev); snd_hdac_ext_link_stream_reset(link_dev);
snd_hdac_ext_link_stream_setup(link_dev, format_val); snd_hdac_ext_link_stream_setup(link_dev, format_val);
...@@ -759,6 +768,78 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { ...@@ -759,6 +768,78 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.formats = SNDRV_PCM_FMTBIT_S16_LE, .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", .name = "iDisp1 Pin",
.ops = &skl_link_dai_ops, .ops = &skl_link_dai_ops,
......
...@@ -336,8 +336,6 @@ void skl_dsp_free(struct sst_dsp *dsp) ...@@ -336,8 +336,6 @@ void skl_dsp_free(struct sst_dsp *dsp)
skl_ipc_int_disable(dsp); skl_ipc_int_disable(dsp);
free_irq(dsp->irq, 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_op_int_disable(dsp);
skl_ipc_int_disable(dsp); skl_ipc_int_disable(dsp);
......
...@@ -118,16 +118,25 @@ struct skl_dsp_fw_ops { ...@@ -118,16 +118,25 @@ struct skl_dsp_fw_ops {
int (*set_state_D0)(struct sst_dsp *ctx); int (*set_state_D0)(struct sst_dsp *ctx);
int (*set_state_D3)(struct sst_dsp *ctx); int (*set_state_D3)(struct sst_dsp *ctx);
unsigned int (*get_fw_errcode)(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); int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id);
}; };
struct skl_dsp_loader_ops { struct skl_dsp_loader_ops {
int stream_tag;
int (*alloc_dma_buf)(struct device *dev, int (*alloc_dma_buf)(struct device *dev,
struct snd_dma_buffer *dmab, size_t size); struct snd_dma_buffer *dmab, size_t size);
int (*free_dma_buf)(struct device *dev, int (*free_dma_buf)(struct device *dev,
struct snd_dma_buffer *dmab); 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 { struct skl_load_module_info {
...@@ -160,6 +169,10 @@ int skl_dsp_boot(struct sst_dsp *ctx); ...@@ -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, 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, const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
struct skl_sst **dsp); 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 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__*/ #endif /*__SKL_SST_DSP_H__*/
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/uuid.h>
#include "../common/sst-dsp.h" #include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h" #include "../common/sst-dsp-priv.h"
#include "../common/sst-ipc.h" #include "../common/sst-ipc.h"
...@@ -304,14 +305,16 @@ static int skl_transfer_module(struct sst_dsp *ctx, ...@@ -304,14 +305,16 @@ static int skl_transfer_module(struct sst_dsp *ctx,
return ret; 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; struct skl_module_table *module_entry = NULL;
int ret = 0; int ret = 0;
char mod_name[64]; /* guid str = 32 chars + 4 hyphens */ char mod_name[64]; /* guid str = 32 chars + 4 hyphens */
uuid_le *uuid_mod;
snprintf(mod_name, sizeof(mod_name), "%s%s%s", uuid_mod = (uuid_le *)guid;
"intel/dsp_fw_", guid, ".bin"); 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); module_entry = skl_module_get_from_id(ctx, mod_id);
if (module_entry == NULL) { if (module_entry == NULL) {
...@@ -451,6 +454,10 @@ void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) ...@@ -451,6 +454,10 @@ void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
skl_clear_module_table(ctx->dsp); skl_clear_module_table(ctx->dsp);
skl_ipc_free(&ctx->ipc); skl_ipc_free(&ctx->ipc);
ctx->dsp->ops->free(ctx->dsp); 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); EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup);
......
...@@ -1564,6 +1564,8 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, ...@@ -1564,6 +1564,8 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
return -ENOMEM; return -ENOMEM;
w->priv = mconfig; w->priv = mconfig;
memcpy(&mconfig->guid, &dfw_config->uuid, 16);
mconfig->id.module_id = dfw_config->module_id; mconfig->id.module_id = dfw_config->module_id;
mconfig->id.instance_id = dfw_config->instance_id; mconfig->id.instance_id = dfw_config->instance_id;
mconfig->mcps = dfw_config->max_mcps; mconfig->mcps = dfw_config->max_mcps;
...@@ -1593,10 +1595,6 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, ...@@ -1593,10 +1595,6 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
mconfig->time_slot = dfw_config->time_slot; mconfig->time_slot = dfw_config->time_slot;
mconfig->formats_config.caps_size = dfw_config->caps.caps_size; 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) * mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) *
sizeof(*mconfig->m_in_pin), sizeof(*mconfig->m_in_pin),
GFP_KERNEL); GFP_KERNEL);
......
...@@ -281,7 +281,7 @@ enum skl_module_state { ...@@ -281,7 +281,7 @@ enum skl_module_state {
}; };
struct skl_module_cfg { struct skl_module_cfg {
char guid[SKL_UUID_STR_SZ]; u8 guid[16];
struct skl_module_inst_id id; struct skl_module_inst_id id;
u8 domain; u8 domain;
bool homogenous_inputs; bool homogenous_inputs;
......
...@@ -181,7 +181,7 @@ struct skl_dfw_pipe { ...@@ -181,7 +181,7 @@ struct skl_dfw_pipe {
} __packed; } __packed;
struct skl_dfw_module { struct skl_dfw_module {
char uuid[SKL_UUID_STR_SZ]; u8 uuid[16];
u16 module_id; u16 module_id;
u16 instance_id; u16 instance_id;
......
...@@ -229,7 +229,12 @@ static int skl_suspend(struct device *dev) ...@@ -229,7 +229,12 @@ static int skl_suspend(struct device *dev)
* running, we need to save the state for these and continue * running, we need to save the state for these and continue
*/ */
if (skl->supend_active) { 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); 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); enable_irq_wake(bus->irq);
pci_save_state(pci); pci_save_state(pci);
pci_disable_device(pci); pci_disable_device(pci);
...@@ -255,6 +260,7 @@ static int skl_resume(struct device *dev) ...@@ -255,6 +260,7 @@ static int skl_resume(struct device *dev)
struct hdac_ext_bus *ebus = pci_get_drvdata(pci); struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
struct skl *skl = ebus_to_skl(ebus); struct skl *skl = ebus_to_skl(ebus);
struct hdac_bus *bus = ebus_to_hbus(ebus); struct hdac_bus *bus = ebus_to_hbus(ebus);
struct hdac_ext_link *hlink = NULL;
int ret; int ret;
/* Turned OFF in HDMI codec driver after codec reconfiguration */ /* Turned OFF in HDMI codec driver after codec reconfiguration */
...@@ -276,8 +282,29 @@ static int skl_resume(struct device *dev) ...@@ -276,8 +282,29 @@ static int skl_resume(struct device *dev)
ret = pci_enable_device(pci); ret = pci_enable_device(pci);
snd_hdac_ext_bus_link_power_up_all(ebus); snd_hdac_ext_bus_link_power_up_all(ebus);
disable_irq_wake(bus->irq); 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 { } else {
ret = _skl_resume(ebus); 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; return ret;
...@@ -613,6 +640,7 @@ static int skl_probe(struct pci_dev *pci, ...@@ -613,6 +640,7 @@ static int skl_probe(struct pci_dev *pci,
struct skl *skl; struct skl *skl;
struct hdac_ext_bus *ebus = NULL; struct hdac_ext_bus *ebus = NULL;
struct hdac_bus *bus = NULL; struct hdac_bus *bus = NULL;
struct hdac_ext_link *hlink = NULL;
int err; int err;
/* we use ext core ops, so provide NULL for ops here */ /* we use ext core ops, so provide NULL for ops here */
...@@ -643,7 +671,7 @@ static int skl_probe(struct pci_dev *pci, ...@@ -643,7 +671,7 @@ static int skl_probe(struct pci_dev *pci,
err = skl_machine_device_register(skl, err = skl_machine_device_register(skl,
(void *)pci_id->driver_data); (void *)pci_id->driver_data);
if (err < 0) if (err < 0)
goto out_free; goto out_nhlt_free;
err = skl_init_dsp(skl); err = skl_init_dsp(skl);
if (err < 0) { if (err < 0) {
...@@ -679,6 +707,12 @@ static int skl_probe(struct pci_dev *pci, ...@@ -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 */ /*configure PM */
pm_runtime_put_noidle(bus->dev); pm_runtime_put_noidle(bus->dev);
pm_runtime_allow(bus->dev); pm_runtime_allow(bus->dev);
...@@ -693,6 +727,8 @@ static int skl_probe(struct pci_dev *pci, ...@@ -693,6 +727,8 @@ static int skl_probe(struct pci_dev *pci,
skl_free_dsp(skl); skl_free_dsp(skl);
out_mach_free: out_mach_free:
skl_machine_device_unregister(skl); skl_machine_device_unregister(skl);
out_nhlt_free:
skl_nhlt_free(skl->nhlt);
out_free: out_free:
skl->init_failed = 1; skl->init_failed = 1;
skl_free(ebus); skl_free(ebus);
...@@ -743,6 +779,7 @@ static void skl_remove(struct pci_dev *pci) ...@@ -743,6 +779,7 @@ static void skl_remove(struct pci_dev *pci)
skl_free_dsp(skl); skl_free_dsp(skl);
skl_machine_device_unregister(skl); skl_machine_device_unregister(skl);
skl_dmic_device_unregister(skl); skl_dmic_device_unregister(skl);
skl_nhlt_free(skl->nhlt);
skl_free(ebus); skl_free(ebus);
dev_set_drvdata(&pci->dev, NULL); dev_set_drvdata(&pci->dev, NULL);
} }
......
...@@ -66,7 +66,7 @@ struct skl { ...@@ -66,7 +66,7 @@ struct skl {
struct platform_device *dmic_dev; struct platform_device *dmic_dev;
struct platform_device *i2s_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_sst *skl_sst; /* sst skl ctx */
struct skl_dsp_resource resource; struct skl_dsp_resource resource;
...@@ -103,8 +103,8 @@ struct skl_dsp_ops { ...@@ -103,8 +103,8 @@ struct skl_dsp_ops {
int skl_platform_unregister(struct device *dev); int skl_platform_unregister(struct device *dev);
int skl_platform_register(struct device *dev); int skl_platform_register(struct device *dev);
void *skl_nhlt_init(struct device *dev); struct nhlt_acpi_table *skl_nhlt_init(struct device *dev);
void skl_nhlt_free(void *addr); void skl_nhlt_free(struct nhlt_acpi_table *addr);
struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, 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); 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