Commit 44d62462 authored by Mark Brown's avatar Mark Brown

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

parents 0d911262 1b00126c
...@@ -1124,8 +1124,10 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) ...@@ -1124,8 +1124,10 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll)
} }
hdac_hdmi_parse_eld(edev, pin); hdac_hdmi_parse_eld(edev, pin);
print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET, print_hex_dump_debug("ELD: ",
pin->eld.eld_buffer, pin->eld.eld_size); DUMP_PREFIX_OFFSET, 16, 1,
pin->eld.eld_buffer, pin->eld.eld_size,
true);
} else { } else {
pin->eld.monitor_present = false; pin->eld.monitor_present = false;
pin->eld.eld_valid = false; pin->eld.eld_valid = false;
...@@ -1816,6 +1818,7 @@ static const struct dev_pm_ops hdac_hdmi_pm = { ...@@ -1816,6 +1818,7 @@ static const struct dev_pm_ops hdac_hdmi_pm = {
static const struct hda_device_id hdmi_list[] = { static const struct hda_device_id hdmi_list[] = {
HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0), HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0),
{} {}
}; };
......
...@@ -1100,6 +1100,13 @@ static const struct dmi_system_id force_combo_jack_table[] = { ...@@ -1100,6 +1100,13 @@ static const struct dmi_system_id force_combo_jack_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Skylake Client platform") DMI_MATCH(DMI_PRODUCT_NAME, "Skylake Client platform")
} }
}, },
{
.ident = "Intel Kabylake RVP",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "Kabylake Client platform")
}
},
{ } { }
}; };
......
...@@ -7,7 +7,7 @@ config SND_MFLD_MACHINE ...@@ -7,7 +7,7 @@ config SND_MFLD_MACHINE
help help
This adds support for ASoC machine driver for Intel(R) MID Medfield platform This adds support for ASoC machine driver for Intel(R) MID Medfield platform
used as alsa device in audio substem in Intel(R) MID devices used as alsa device in audio substem in Intel(R) MID devices
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_SST_MFLD_PLATFORM config SND_SST_MFLD_PLATFORM
...@@ -25,7 +25,6 @@ config SND_SST_IPC_ACPI ...@@ -25,7 +25,6 @@ config SND_SST_IPC_ACPI
tristate tristate
select SND_SST_IPC select SND_SST_IPC
select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST
depends on ACPI
config SND_SOC_INTEL_SST config SND_SOC_INTEL_SST
tristate tristate
...@@ -33,6 +32,12 @@ config SND_SOC_INTEL_SST ...@@ -33,6 +32,12 @@ config SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_MATCH if ACPI select SND_SOC_INTEL_SST_MATCH if ACPI
depends on (X86 || COMPILE_TEST) depends on (X86 || COMPILE_TEST)
# firmware stuff depends DW_DMAC_CORE; since there is no depends-on from
# the reverse selection, each machine driver needs to select
# SND_SOC_INTEL_SST_FIRMWARE carefully depending on DW_DMAC_CORE
config SND_SOC_INTEL_SST_FIRMWARE
tristate
config SND_SOC_INTEL_SST_ACPI config SND_SOC_INTEL_SST_ACPI
tristate tristate
...@@ -48,16 +53,33 @@ config SND_SOC_INTEL_BAYTRAIL ...@@ -48,16 +53,33 @@ config SND_SOC_INTEL_BAYTRAIL
config SND_SOC_INTEL_HASWELL_MACH config SND_SOC_INTEL_HASWELL_MACH
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
depends on DW_DMAC_CORE=y depends on DW_DMAC_CORE
select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_FIRMWARE
select SND_SOC_INTEL_HASWELL select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5640 select SND_SOC_RT5640
help help
This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell
Ultrabook platforms. Ultrabook platforms.
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_DA7219_MAX98357A_MACH
tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode"
depends on X86 && ACPI && I2C
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE
select SND_SOC_DA7219
select SND_SOC_MAX98357A
select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI
select SND_HDA_DSP_LOADER
help
This adds support for ASoC machine driver for Broxton-P platforms
with DA7219 + MAX98357A I2S audio codec.
Say Y if you have such a device.
If unsure select "N".
config SND_SOC_INTEL_BXT_RT298_MACH config SND_SOC_INTEL_BXT_RT298_MACH
tristate "ASoC Audio driver for Broxton with RT298 I2S mode" tristate "ASoC Audio driver for Broxton with RT298 I2S mode"
depends on X86 && ACPI && I2C depends on X86 && ACPI && I2C
...@@ -70,26 +92,28 @@ config SND_SOC_INTEL_BXT_RT298_MACH ...@@ -70,26 +92,28 @@ config SND_SOC_INTEL_BXT_RT298_MACH
help help
This adds support for ASoC machine driver for Broxton platforms This adds support for ASoC machine driver for Broxton platforms
with RT286 I2S audio codec. with RT286 I2S audio codec.
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_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
depends on DW_DMAC_CORE=y && (SND_SST_IPC_ACPI = n) depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n)
select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_FIRMWARE
select SND_SOC_INTEL_BAYTRAIL select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_RT5640 select SND_SOC_RT5640
help help
This adds audio driver for Intel Baytrail platform based boards This adds audio driver for Intel Baytrail platform based boards
with the RT5640 audio codec. This driver is deprecated, use with the RT5640 audio codec. This driver is deprecated, use
SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality.
config SND_SOC_INTEL_BYT_MAX98090_MACH config SND_SOC_INTEL_BYT_MAX98090_MACH
tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
depends on X86_INTEL_LPSS && I2C depends on X86_INTEL_LPSS && I2C
depends on DW_DMAC_CORE=y && (SND_SST_IPC_ACPI = n) depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n)
select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_FIRMWARE
select SND_SOC_INTEL_BAYTRAIL select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_MAX98090 select SND_SOC_MAX98090
help help
...@@ -100,19 +124,20 @@ config SND_SOC_INTEL_BROADWELL_MACH ...@@ -100,19 +124,20 @@ config SND_SOC_INTEL_BROADWELL_MACH
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ depends on X86_INTEL_LPSS && I2C && DW_DMAC && \
I2C_DESIGNWARE_PLATFORM I2C_DESIGNWARE_PLATFORM
depends on DW_DMAC_CORE=y depends on DW_DMAC_CORE
select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_FIRMWARE
select SND_SOC_INTEL_HASWELL select SND_SOC_INTEL_HASWELL
select SND_SOC_RT286 select SND_SOC_RT286
help help
This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell
Ultrabook platforms. Ultrabook platforms.
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_BYTCR_RT5640_MACH config SND_SOC_INTEL_BYTCR_RT5640_MACH
tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec"
depends on X86 && I2C depends on X86 && I2C && ACPI
select SND_SOC_RT5640 select SND_SOC_RT5640
select SND_SST_MFLD_PLATFORM select SND_SST_MFLD_PLATFORM
select SND_SST_IPC_ACPI select SND_SST_IPC_ACPI
...@@ -120,12 +145,12 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH ...@@ -120,12 +145,12 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH
help help
This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
platforms with RT5640 audio codec. platforms with RT5640 audio codec.
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_BYTCR_RT5651_MACH config SND_SOC_INTEL_BYTCR_RT5651_MACH
tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec"
depends on X86 && I2C depends on X86 && I2C && ACPI
select SND_SOC_RT5651 select SND_SOC_RT5651
select SND_SST_MFLD_PLATFORM select SND_SST_MFLD_PLATFORM
select SND_SST_IPC_ACPI select SND_SST_IPC_ACPI
...@@ -133,12 +158,12 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH ...@@ -133,12 +158,12 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH
help help
This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
platforms with RT5651 audio codec. platforms with RT5651 audio codec.
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_CHT_BSW_RT5672_MACH config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
depends on X86_INTEL_LPSS && I2C depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_RT5670 select SND_SOC_RT5670
select SND_SST_MFLD_PLATFORM select SND_SST_MFLD_PLATFORM
select SND_SST_IPC_ACPI select SND_SST_IPC_ACPI
...@@ -146,12 +171,12 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH ...@@ -146,12 +171,12 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
help help
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
platforms with RT5672 audio codec. platforms with RT5672 audio codec.
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_CHT_BSW_RT5645_MACH config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec" tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec"
depends on X86_INTEL_LPSS && I2C depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_RT5645 select SND_SOC_RT5645
select SND_SST_MFLD_PLATFORM select SND_SST_MFLD_PLATFORM
select SND_SST_IPC_ACPI select SND_SST_IPC_ACPI
...@@ -163,16 +188,16 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH ...@@ -163,16 +188,16 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 & TI codec" tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 & TI codec"
depends on X86_INTEL_LPSS && I2C depends on X86_INTEL_LPSS && I2C && ACPI
select SND_SOC_MAX98090 select SND_SOC_MAX98090
select SND_SOC_TS3A227E select SND_SOC_TS3A227E
select SND_SST_MFLD_PLATFORM select SND_SST_MFLD_PLATFORM
select SND_SST_IPC_ACPI select SND_SST_IPC_ACPI
select SND_SOC_INTEL_SST_MATCH if ACPI select SND_SOC_INTEL_SST_MATCH if ACPI
help help
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
platforms with MAX98090 audio codec it also can support TI jack chip as aux device. platforms with MAX98090 audio codec it also can support TI jack chip as aux device.
If unsure select "N". If unsure select "N".
config SND_SOC_INTEL_SKYLAKE config SND_SOC_INTEL_SKYLAKE
tristate tristate
...@@ -192,7 +217,7 @@ config SND_SOC_INTEL_SKL_RT286_MACH ...@@ -192,7 +217,7 @@ config SND_SOC_INTEL_SKL_RT286_MACH
help help
This adds support for ASoC machine driver for Skylake platforms This adds support for ASoC machine driver for Skylake platforms
with RT286 I2S audio codec. with RT286 I2S audio codec.
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_SKL_NAU88L25_SSM4567_MACH config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
...@@ -207,7 +232,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH ...@@ -207,7 +232,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
help help
This adds support for ASoC Onboard Codec I2S machine driver. This will This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for NAU88L25 + SSM4567. create an alsa sound card for NAU88L25 + SSM4567.
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_SKL_NAU88L25_MAX98357A_MACH config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
...@@ -222,5 +247,5 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH ...@@ -222,5 +247,5 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
help help
This adds support for ASoC Onboard Codec I2S machine driver. This will This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for NAU88L25 + MAX98357A. create an alsa sound card for NAU88L25 + MAX98357A.
Say Y if you have such a device Say Y if you have such a device.
If unsure select "N". If unsure select "N".
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pm_qos.h> #include <linux/pm_qos.h>
#include <linux/dmi.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <asm/platform_sst_audio.h> #include <asm/platform_sst_audio.h>
#include <sound/core.h> #include <sound/core.h>
...@@ -237,6 +238,9 @@ static int sst_acpi_probe(struct platform_device *pdev) ...@@ -237,6 +238,9 @@ static int sst_acpi_probe(struct platform_device *pdev)
dev_err(dev, "No matching machine driver found\n"); dev_err(dev, "No matching machine driver found\n");
return -ENODEV; return -ENODEV;
} }
if (mach->machine_quirk)
mach = mach->machine_quirk(mach);
pdata = mach->pdata; pdata = mach->pdata;
ret = kstrtouint(id->id, 16, &dev_id); ret = kstrtouint(id->id, 16, &dev_id);
...@@ -320,6 +324,44 @@ static int sst_acpi_remove(struct platform_device *pdev) ...@@ -320,6 +324,44 @@ static int sst_acpi_remove(struct platform_device *pdev)
return 0; return 0;
} }
static unsigned long cht_machine_id;
#define CHT_SURFACE_MACH 1
static int cht_surface_quirk_cb(const struct dmi_system_id *id)
{
cht_machine_id = CHT_SURFACE_MACH;
return 1;
}
static const struct dmi_system_id cht_table[] = {
{
.callback = cht_surface_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"),
},
},
};
static struct sst_acpi_mach cht_surface_mach = {
"10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data };
static struct sst_acpi_mach *cht_quirk(void *arg)
{
struct sst_acpi_mach *mach = arg;
dmi_check_system(cht_table);
if (cht_machine_id == CHT_SURFACE_MACH)
return &cht_surface_mach;
else
return mach;
}
static struct sst_acpi_mach sst_acpi_bytcr[] = { static struct sst_acpi_mach sst_acpi_bytcr[] = {
{"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
&byt_rvp_platform_data }, &byt_rvp_platform_data },
...@@ -343,7 +385,7 @@ static struct sst_acpi_mach sst_acpi_chv[] = { ...@@ -343,7 +385,7 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
{"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data }, &chv_platform_data },
/* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
{"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", NULL, {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk,
&chv_platform_data }, &chv_platform_data },
{}, {},
......
...@@ -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-da7219_max98357a-objs := bxt_da7219_max98357a.o
snd-soc-sst-bxt-rt298-objs := bxt_rt298.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
...@@ -15,6 +16,7 @@ snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o ...@@ -15,6 +16,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_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.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
......
/*
* Intel Broxton-P I2S Machine Driver
*
* Copyright (C) 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/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "../../codecs/hdac_hdmi.h"
#include "../../codecs/da7219.h"
#include "../../codecs/da7219-aad.h"
#define BXT_DIALOG_CODEC_DAI "da7219-hifi"
#define BXT_MAXIM_CODEC_DAI "HiFi"
#define DUAL_CHANNEL 2
static struct snd_soc_jack broxton_headset;
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 const struct snd_kcontrol_new broxton_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Spk"),
};
static const struct snd_soc_dapm_widget broxton_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_SPK("Spk", 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_map[] = {
/* HP jack connectors - unknown if we have jack detection */
{"Headphone Jack", NULL, "HPL"},
{"Headphone Jack", NULL, "HPR"},
/* speaker */
{"Spk", NULL, "Speaker"},
/* other jacks */
{"MIC", NULL, "Headset Mic"},
/* digital mics */
{"DMic", NULL, "SoC DMIC"},
/* CODEC BE connections */
{"HiFi Playback", NULL, "ssp5 Tx"},
{"ssp5 Tx", NULL, "codec0_out"},
{"Playback", NULL, "ssp1 Tx"},
{"ssp1 Tx", NULL, "codec1_out"},
{"codec0_in", NULL, "ssp1 Rx"},
{"ssp1 Rx", NULL, "Capture"},
{"HDMI1", NULL, "hif5 Output"},
{"HDMI2", NULL, "hif6 Output"},
{"HDMI3", NULL, "hif7 Output"},
{"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"},
/* DMIC */
{"dmic01_hifi", NULL, "DMIC01 Rx"},
{"DMIC01 Rx", NULL, "DMIC AIF"},
};
static int broxton_ssp_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 convert the FE rate to 48k, stereo */
rate->min = rate->max = 48000;
channels->min = channels->max = DUAL_CHANNEL;
/* set SSP to 24 bit */
snd_mask_none(fmt);
snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
return 0;
}
static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd)
{
int ret;
struct snd_soc_codec *codec = rtd->codec;
/*
* Headset buttons map to the google Reference headset.
* These can be configured by userspace.
*/
ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3, &broxton_headset,
NULL, 0);
if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
return ret;
}
da7219_aad_jack_det(codec, &broxton_headset);
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
return ret;
}
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_da7219_fe_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dapm_context *dapm;
struct snd_soc_component *component = rtd->cpu_dai->component;
dapm = snd_soc_component_get_dapm(component);
snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
return 0;
}
static unsigned int rates[] = {
48000,
};
static struct snd_pcm_hw_constraint_list constraints_rates = {
.count = ARRAY_SIZE(rates),
.list = rates,
.mask = 0,
};
static unsigned int channels[] = {
DUAL_CHANNEL,
};
static struct snd_pcm_hw_constraint_list constraints_channels = {
.count = ARRAY_SIZE(channels),
.list = channels,
.mask = 0,
};
static int bxt_fe_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
/*
* On this platform for PCM device we support,
* 48Khz
* stereo
* 16 bit audio
*/
runtime->hw.channels_max = DUAL_CHANNEL;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16);
snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
return 0;
}
static const struct snd_soc_ops broxton_da7219_fe_ops = {
.startup = bxt_fe_startup,
};
static int broxton_da7219_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,
DA7219_CLKSRC_MCLK, 19200000, SND_SOC_CLOCK_IN);
if (ret < 0)
dev_err(codec_dai->dev, "can't set codec sysclk configuration\n");
ret = snd_soc_dai_set_pll(codec_dai, 0,
DA7219_SYSCLK_PLL_SRM, 0, DA7219_PLL_FREQ_OUT_98304);
if (ret < 0) {
dev_err(codec_dai->dev, "failed to start PLL: %d\n", ret);
return -EIO;
}
return ret;
}
static int broxton_da7219_hw_free(struct snd_pcm_substream *substream)
{
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_pll(codec_dai, 0,
DA7219_SYSCLK_MCLK, 0, 0);
if (ret < 0) {
dev_err(codec_dai->dev, "failed to stop PLL: %d\n", ret);
return -EIO;
}
return ret;
}
static struct snd_soc_ops broxton_da7219_ops = {
.hw_params = broxton_da7219_hw_params,
.hw_free = broxton_da7219_hw_free,
};
/* broxton digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link broxton_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",
.dynamic = 1,
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.nonatomic = 1,
.init = broxton_da7219_fe_init,
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_playback = 1,
.ops = &broxton_da7219_fe_ops,
},
[BXT_DPCM_AUDIO_CP]
{
.name = "Bxt Audio Capture Port",
.stream_name = "Audio Record",
.cpu_dai_name = "System Pin",
.platform_name = "0000:00:0e.0",
.dynamic = 1,
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.nonatomic = 1,
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_capture = 1,
.ops = &broxton_da7219_fe_ops,
},
[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,
.ignore_suspend = 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 = "MX98357A:00",
.codec_dai_name = BXT_MAXIM_CODEC_DAI,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.ignore_pmdown_time = 1,
.be_hw_params_fixup = broxton_ssp_fixup,
.dpcm_playback = 1,
},
{
/* SSP1 - Codec */
.name = "SSP1-Codec",
.id = 1,
.cpu_dai_name = "SSP1 Pin",
.platform_name = "0000:00:0e.0",
.no_pcm = 1,
.codec_name = "i2c-DLGS7219:00",
.codec_dai_name = BXT_DIALOG_CODEC_DAI,
.init = broxton_da7219_codec_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.ignore_pmdown_time = 1,
.be_hw_params_fixup = broxton_ssp_fixup,
.ops = &broxton_da7219_ops,
.dpcm_playback = 1,
.dpcm_capture = 1,
},
{
.name = "dmic01",
.id = 2,
.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 + da7219 */
static struct snd_soc_card broxton_audio_card = {
.name = "bxtda7219max",
.owner = THIS_MODULE,
.dai_link = broxton_dais,
.num_links = ARRAY_SIZE(broxton_dais),
.controls = broxton_controls,
.num_controls = ARRAY_SIZE(broxton_controls),
.dapm_widgets = broxton_widgets,
.num_dapm_widgets = ARRAY_SIZE(broxton_widgets),
.dapm_routes = broxton_map,
.num_dapm_routes = ARRAY_SIZE(broxton_map),
.fully_routed = true,
};
static int broxton_audio_probe(struct platform_device *pdev)
{
broxton_audio_card.dev = &pdev->dev;
return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card);
}
static struct platform_driver broxton_audio = {
.probe = broxton_audio_probe,
.driver = {
.name = "bxt_da7219_max98357a_i2s",
.pm = &snd_soc_pm_ops,
},
};
module_platform_driver(broxton_audio)
/* Module information */
MODULE_DESCRIPTION("Audio Machine driver-DA7219 & MAX98357A in I2S mode");
MODULE_AUTHOR("Sathyanarayana Nujella <sathyanarayana.nujella@intel.com>");
MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com>");
MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:bxt_da7219_max98357a_i2s");
...@@ -33,6 +33,7 @@ enum { ...@@ -33,6 +33,7 @@ enum {
BXT_DPCM_AUDIO_PB = 0, BXT_DPCM_AUDIO_PB = 0,
BXT_DPCM_AUDIO_CP, BXT_DPCM_AUDIO_CP,
BXT_DPCM_AUDIO_REF_CP, BXT_DPCM_AUDIO_REF_CP,
BXT_DPCM_AUDIO_DMIC_CP,
BXT_DPCM_AUDIO_HDMI1_PB, BXT_DPCM_AUDIO_HDMI1_PB,
BXT_DPCM_AUDIO_HDMI2_PB, BXT_DPCM_AUDIO_HDMI2_PB,
BXT_DPCM_AUDIO_HDMI3_PB, BXT_DPCM_AUDIO_HDMI3_PB,
...@@ -88,6 +89,7 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = { ...@@ -88,6 +89,7 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = {
/* CODEC BE connections */ /* CODEC BE connections */
{ "AIF1 Playback", NULL, "ssp5 Tx"}, { "AIF1 Playback", NULL, "ssp5 Tx"},
{ "ssp5 Tx", NULL, "codec0_out"}, { "ssp5 Tx", NULL, "codec0_out"},
{ "ssp5 Tx", NULL, "codec1_out"},
{ "codec0_in", NULL, "ssp5 Rx" }, { "codec0_in", NULL, "ssp5 Rx" },
{ "ssp5 Rx", NULL, "AIF1 Capture" }, { "ssp5 Rx", NULL, "AIF1 Capture" },
...@@ -104,6 +106,17 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = { ...@@ -104,6 +106,17 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = {
}; };
static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dapm_context *dapm;
struct snd_soc_component *component = rtd->cpu_dai->component;
dapm = snd_soc_component_get_dapm(component);
snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
return 0;
}
static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd) static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_soc_codec *codec = rtd->codec; struct snd_soc_codec *codec = rtd->codec;
...@@ -118,6 +131,9 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd) ...@@ -118,6 +131,9 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret; return ret;
rt298_mic_detect(codec, &broxton_headset); rt298_mic_detect(codec, &broxton_headset);
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
return 0; return 0;
} }
...@@ -169,6 +185,89 @@ static struct snd_soc_ops broxton_rt298_ops = { ...@@ -169,6 +185,89 @@ static struct snd_soc_ops broxton_rt298_ops = {
.hw_params = broxton_rt298_hw_params, .hw_params = broxton_rt298_hw_params,
}; };
static unsigned int rates[] = {
48000,
};
static struct snd_pcm_hw_constraint_list constraints_rates = {
.count = ARRAY_SIZE(rates),
.list = rates,
.mask = 0,
};
static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
if (params_channels(params) == 2)
channels->min = channels->max = 2;
else
channels->min = channels->max = 4;
return 0;
}
static unsigned int channels_dmic[] = {
2, 4,
};
static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
.count = ARRAY_SIZE(channels_dmic),
.list = channels_dmic,
.mask = 0,
};
static int broxton_dmic_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
runtime->hw.channels_max = 4;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_dmic_channels);
return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
}
static struct snd_soc_ops broxton_dmic_ops = {
.startup = broxton_dmic_startup,
};
static unsigned int channels[] = {
2,
};
static struct snd_pcm_hw_constraint_list constraints_channels = {
.count = ARRAY_SIZE(channels),
.list = channels,
.mask = 0,
};
static int bxt_fe_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
/*
* on this platform for PCM device we support:
* 48Khz
* stereo
*/
runtime->hw.channels_max = 2;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_channels);
snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
return 0;
}
static const struct snd_soc_ops broxton_rt286_fe_ops = {
.startup = bxt_fe_startup,
};
/* broxton digital audio interface glue - connects codec <--> CPU */ /* broxton digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link broxton_rt298_dais[] = { static struct snd_soc_dai_link broxton_rt298_dais[] = {
/* Front End DAI links */ /* Front End DAI links */
...@@ -182,8 +281,10 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { ...@@ -182,8 +281,10 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
.dynamic = 1, .dynamic = 1,
.codec_name = "snd-soc-dummy", .codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai", .codec_dai_name = "snd-soc-dummy-dai",
.init = broxton_rt298_fe_init,
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_playback = 1, .dpcm_playback = 1,
.ops = &broxton_rt286_fe_ops,
}, },
[BXT_DPCM_AUDIO_CP] [BXT_DPCM_AUDIO_CP]
{ {
...@@ -197,6 +298,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { ...@@ -197,6 +298,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
.codec_dai_name = "snd-soc-dummy-dai", .codec_dai_name = "snd-soc-dummy-dai",
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_capture = 1, .dpcm_capture = 1,
.ops = &broxton_rt286_fe_ops,
}, },
[BXT_DPCM_AUDIO_REF_CP] [BXT_DPCM_AUDIO_REF_CP]
{ {
...@@ -211,6 +313,20 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { ...@@ -211,6 +313,20 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
.nonatomic = 1, .nonatomic = 1,
.dynamic = 1, .dynamic = 1,
}, },
[BXT_DPCM_AUDIO_DMIC_CP]
{
.name = "Bxt Audio DMIC cap",
.stream_name = "dmiccap",
.cpu_dai_name = "DMIC 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,
.ops = &broxton_dmic_ops,
},
[BXT_DPCM_AUDIO_HDMI1_PB] [BXT_DPCM_AUDIO_HDMI1_PB]
{ {
.name = "Bxt HDMI Port1", .name = "Bxt HDMI Port1",
...@@ -276,6 +392,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { ...@@ -276,6 +392,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
.codec_name = "dmic-codec", .codec_name = "dmic-codec",
.codec_dai_name = "dmic-hifi", .codec_dai_name = "dmic-hifi",
.platform_name = "0000:00:0e.0", .platform_name = "0000:00:0e.0",
.be_hw_params_fixup = broxton_dmic_fixup,
.ignore_suspend = 1, .ignore_suspend = 1,
.dpcm_capture = 1, .dpcm_capture = 1,
.no_pcm = 1, .no_pcm = 1,
...@@ -341,6 +458,7 @@ static struct platform_driver broxton_audio = { ...@@ -341,6 +458,7 @@ static struct platform_driver broxton_audio = {
.probe = broxton_audio_probe, .probe = broxton_audio_probe,
.driver = { .driver = {
.name = "bxt_alc298s_i2s", .name = "bxt_alc298s_i2s",
.pm = &snd_soc_pm_ops,
}, },
}; };
module_platform_driver(broxton_audio) module_platform_driver(broxton_audio)
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <sound/jack.h> #include <sound/jack.h>
#include "../../codecs/rt5645.h" #include "../../codecs/rt5645.h"
#include "../atom/sst-atom-controls.h" #include "../atom/sst-atom-controls.h"
#include "../common/sst-acpi.h"
#define CHT_PLAT_CLK_3_HZ 19200000 #define CHT_PLAT_CLK_3_HZ 19200000
#define CHT_CODEC_DAI "rt5645-aif1" #define CHT_CODEC_DAI "rt5645-aif1"
...@@ -340,10 +341,13 @@ static struct snd_soc_card snd_soc_card_chtrt5650 = { ...@@ -340,10 +341,13 @@ static struct snd_soc_card snd_soc_card_chtrt5650 = {
}; };
static struct cht_acpi_card snd_soc_cards[] = { static struct cht_acpi_card snd_soc_cards[] = {
{"10EC5640", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
{"10EC5645", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, {"10EC5645", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
{"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650}, {"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650},
}; };
static char cht_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
static int snd_cht_mc_probe(struct platform_device *pdev) static int snd_cht_mc_probe(struct platform_device *pdev)
{ {
int ret_val = 0; int ret_val = 0;
...@@ -351,6 +355,9 @@ static int snd_cht_mc_probe(struct platform_device *pdev) ...@@ -351,6 +355,9 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
struct cht_mc_private *drv; struct cht_mc_private *drv;
struct snd_soc_card *card = snd_soc_cards[0].soc_card; struct snd_soc_card *card = snd_soc_cards[0].soc_card;
char codec_name[16]; char codec_name[16];
struct sst_acpi_mach *mach;
const char *i2c_name = NULL;
int dai_index = 0;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
if (!drv) if (!drv)
...@@ -366,12 +373,23 @@ static int snd_cht_mc_probe(struct platform_device *pdev) ...@@ -366,12 +373,23 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
} }
} }
card->dev = &pdev->dev; card->dev = &pdev->dev;
mach = card->dev->platform_data;
sprintf(codec_name, "i2c-%s:00", drv->acpi_card->codec_id); sprintf(codec_name, "i2c-%s:00", drv->acpi_card->codec_id);
/* set correct codec name */ /* set correct codec name */
for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) for (i = 0; i < ARRAY_SIZE(cht_dailink); i++)
if (!strcmp(card->dai_link[i].codec_name, "i2c-10EC5645:00")) if (!strcmp(card->dai_link[i].codec_name, "i2c-10EC5645:00")) {
card->dai_link[i].codec_name = kstrdup(codec_name, GFP_KERNEL); card->dai_link[i].codec_name = kstrdup(codec_name, GFP_KERNEL);
dai_index = i;
}
/* fixup codec name based on HID */
i2c_name = sst_acpi_find_name_from_hid(mach->id);
if (i2c_name != NULL) {
snprintf(cht_rt5640_codec_name, sizeof(cht_rt5640_codec_name),
"%s%s", "i2c-", i2c_name);
cht_dailink[dai_index].codec_name = cht_rt5640_codec_name;
}
snd_soc_card_set_drvdata(card, drv); snd_soc_card_set_drvdata(card, drv);
ret_val = devm_snd_soc_register_card(&pdev->dev, card); ret_val = devm_snd_soc_register_card(&pdev->dev, card);
......
...@@ -23,12 +23,15 @@ ...@@ -23,12 +23,15 @@
#include <sound/soc.h> #include <sound/soc.h>
#include "../../codecs/nau8825.h" #include "../../codecs/nau8825.h"
#include "../../codecs/hdac_hdmi.h" #include "../../codecs/hdac_hdmi.h"
#include "../skylake/skl.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
#define SKL_MAXIM_CODEC_DAI "HiFi" #define SKL_MAXIM_CODEC_DAI "HiFi"
#define DMIC_CH(p) p->list[p->count-1]
static struct snd_soc_jack skylake_headset; static struct snd_soc_jack skylake_headset;
static struct snd_soc_card skylake_audio_card; static struct snd_soc_card skylake_audio_card;
static const struct snd_pcm_hw_constraint_list *dmic_constraints;
struct skl_hdmi_pcm { struct skl_hdmi_pcm {
struct list_head head; struct list_head head;
...@@ -339,7 +342,7 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, ...@@ -339,7 +342,7 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_interval *channels = hw_param_interval(params, struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS); SNDRV_PCM_HW_PARAM_CHANNELS);
if (params_channels(params) == 2) if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2)
channels->min = channels->max = 2; channels->min = channels->max = 2;
else else
channels->min = channels->max = 4; channels->min = channels->max = 4;
...@@ -357,13 +360,23 @@ static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { ...@@ -357,13 +360,23 @@ static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
.mask = 0, .mask = 0,
}; };
static const unsigned int dmic_2ch[] = {
2,
};
static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = {
.count = ARRAY_SIZE(dmic_2ch),
.list = dmic_2ch,
.mask = 0,
};
static int skylake_dmic_startup(struct snd_pcm_substream *substream) static int skylake_dmic_startup(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
runtime->hw.channels_max = 4; runtime->hw.channels_max = DMIC_CH(dmic_constraints);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_dmic_channels); dmic_constraints);
return snd_pcm_hw_constraint_list(substream->runtime, 0, return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
...@@ -382,8 +395,22 @@ static struct snd_pcm_hw_constraint_list constraints_16000 = { ...@@ -382,8 +395,22 @@ static struct snd_pcm_hw_constraint_list constraints_16000 = {
.list = rates_16000, .list = rates_16000,
}; };
static const unsigned int ch_mono[] = {
1,
};
static const struct snd_pcm_hw_constraint_list constraints_refcap = {
.count = ARRAY_SIZE(ch_mono),
.list = ch_mono,
};
static int skylake_refcap_startup(struct snd_pcm_substream *substream) static int skylake_refcap_startup(struct snd_pcm_substream *substream)
{ {
substream->runtime->hw.channels_max = 1;
snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_refcap);
return snd_pcm_hw_constraint_list(substream->runtime, 0, return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, SNDRV_PCM_HW_PARAM_RATE,
&constraints_16000); &constraints_16000);
...@@ -610,6 +637,7 @@ static struct snd_soc_card skylake_audio_card = { ...@@ -610,6 +637,7 @@ static struct snd_soc_card skylake_audio_card = {
static int skylake_audio_probe(struct platform_device *pdev) static int skylake_audio_probe(struct platform_device *pdev)
{ {
struct skl_nau8825_private *ctx; struct skl_nau8825_private *ctx;
struct skl_machine_pdata *pdata;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
if (!ctx) if (!ctx)
...@@ -620,15 +648,27 @@ static int skylake_audio_probe(struct platform_device *pdev) ...@@ -620,15 +648,27 @@ static int skylake_audio_probe(struct platform_device *pdev)
skylake_audio_card.dev = &pdev->dev; skylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&skylake_audio_card, ctx); snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
pdata = dev_get_drvdata(&pdev->dev);
if (pdata)
dmic_constraints = pdata->dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
} }
static const struct platform_device_id skl_board_ids[] = {
{ .name = "skl_n88l25_m98357a" },
{ .name = "kbl_n88l25_m98357a" },
{ }
};
static struct platform_driver skylake_audio = { static struct platform_driver skylake_audio = {
.probe = skylake_audio_probe, .probe = skylake_audio_probe,
.driver = { .driver = {
.name = "skl_nau88l25_max98357a_i2s", .name = "skl_n88l25_m98357a",
.pm = &snd_soc_pm_ops, .pm = &snd_soc_pm_ops,
}, },
.id_table = skl_board_ids,
}; };
module_platform_driver(skylake_audio) module_platform_driver(skylake_audio)
...@@ -637,4 +677,5 @@ module_platform_driver(skylake_audio) ...@@ -637,4 +677,5 @@ module_platform_driver(skylake_audio)
MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode"); MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode");
MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com"); MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:skl_nau88l25_max98357a_i2s"); MODULE_ALIAS("platform:skl_n88l25_m98357a");
MODULE_ALIAS("platform:kbl_n88l25_m98357a");
...@@ -27,12 +27,15 @@ ...@@ -27,12 +27,15 @@
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include "../../codecs/nau8825.h" #include "../../codecs/nau8825.h"
#include "../../codecs/hdac_hdmi.h" #include "../../codecs/hdac_hdmi.h"
#include "../skylake/skl.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
#define SKL_SSM_CODEC_DAI "ssm4567-hifi" #define SKL_SSM_CODEC_DAI "ssm4567-hifi"
#define DMIC_CH(p) p->list[p->count-1]
static struct snd_soc_jack skylake_headset; static struct snd_soc_jack skylake_headset;
static struct snd_soc_card skylake_audio_card; static struct snd_soc_card skylake_audio_card;
static const struct snd_pcm_hw_constraint_list *dmic_constraints;
struct skl_hdmi_pcm { struct skl_hdmi_pcm {
struct list_head head; struct list_head head;
...@@ -367,7 +370,7 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, ...@@ -367,7 +370,7 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
{ {
struct snd_interval *channels = hw_param_interval(params, struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS); SNDRV_PCM_HW_PARAM_CHANNELS);
if (params_channels(params) == 2) if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2)
channels->min = channels->max = 2; channels->min = channels->max = 2;
else else
channels->min = channels->max = 4; channels->min = channels->max = 4;
...@@ -405,13 +408,23 @@ static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { ...@@ -405,13 +408,23 @@ static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
.mask = 0, .mask = 0,
}; };
static const unsigned int dmic_2ch[] = {
2,
};
static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = {
.count = ARRAY_SIZE(dmic_2ch),
.list = dmic_2ch,
.mask = 0,
};
static int skylake_dmic_startup(struct snd_pcm_substream *substream) static int skylake_dmic_startup(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
runtime->hw.channels_max = 4; runtime->hw.channels_max = DMIC_CH(dmic_constraints);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_dmic_channels); dmic_constraints);
return snd_pcm_hw_constraint_list(substream->runtime, 0, return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
...@@ -430,8 +443,22 @@ static struct snd_pcm_hw_constraint_list constraints_16000 = { ...@@ -430,8 +443,22 @@ static struct snd_pcm_hw_constraint_list constraints_16000 = {
.list = rates_16000, .list = rates_16000,
}; };
static const unsigned int ch_mono[] = {
1,
};
static const struct snd_pcm_hw_constraint_list constraints_refcap = {
.count = ARRAY_SIZE(ch_mono),
.list = ch_mono,
};
static int skylake_refcap_startup(struct snd_pcm_substream *substream) static int skylake_refcap_startup(struct snd_pcm_substream *substream)
{ {
substream->runtime->hw.channels_max = 1;
snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
&constraints_refcap);
return snd_pcm_hw_constraint_list(substream->runtime, 0, return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, SNDRV_PCM_HW_PARAM_RATE,
&constraints_16000); &constraints_16000);
...@@ -662,6 +689,7 @@ static struct snd_soc_card skylake_audio_card = { ...@@ -662,6 +689,7 @@ static struct snd_soc_card skylake_audio_card = {
static int skylake_audio_probe(struct platform_device *pdev) static int skylake_audio_probe(struct platform_device *pdev)
{ {
struct skl_nau88125_private *ctx; struct skl_nau88125_private *ctx;
struct skl_machine_pdata *pdata;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
if (!ctx) if (!ctx)
...@@ -672,15 +700,27 @@ static int skylake_audio_probe(struct platform_device *pdev) ...@@ -672,15 +700,27 @@ static int skylake_audio_probe(struct platform_device *pdev)
skylake_audio_card.dev = &pdev->dev; skylake_audio_card.dev = &pdev->dev;
snd_soc_card_set_drvdata(&skylake_audio_card, ctx); snd_soc_card_set_drvdata(&skylake_audio_card, ctx);
pdata = dev_get_drvdata(&pdev->dev);
if (pdata)
dmic_constraints = pdata->dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels;
return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card);
} }
static const struct platform_device_id skl_board_ids[] = {
{ .name = "skl_n88l25_s4567" },
{ .name = "kbl_n88l25_s4567" },
{ }
};
static struct platform_driver skylake_audio = { static struct platform_driver skylake_audio = {
.probe = skylake_audio_probe, .probe = skylake_audio_probe,
.driver = { .driver = {
.name = "skl_nau88l25_ssm4567_i2s", .name = "skl_n88l25_s4567",
.pm = &snd_soc_pm_ops, .pm = &snd_soc_pm_ops,
}, },
.id_table = skl_board_ids,
}; };
module_platform_driver(skylake_audio) module_platform_driver(skylake_audio)
...@@ -693,4 +733,5 @@ MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); ...@@ -693,4 +733,5 @@ MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>");
MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>");
MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode"); MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:skl_nau88l25_ssm4567_i2s"); MODULE_ALIAS("platform:skl_n88l25_s4567");
MODULE_ALIAS("platform:kbl_n88l25_s4567");
...@@ -505,12 +505,20 @@ static int skylake_audio_probe(struct platform_device *pdev) ...@@ -505,12 +505,20 @@ static int skylake_audio_probe(struct platform_device *pdev)
return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286); return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286);
} }
static const struct platform_device_id skl_board_ids[] = {
{ .name = "skl_alc286s_i2s" },
{ .name = "kbl_alc286s_i2s" },
{ }
};
static struct platform_driver skylake_audio = { static struct platform_driver skylake_audio = {
.probe = skylake_audio_probe, .probe = skylake_audio_probe,
.driver = { .driver = {
.name = "skl_alc286s_i2s", .name = "skl_alc286s_i2s",
.pm = &snd_soc_pm_ops, .pm = &snd_soc_pm_ops,
}, },
.id_table = skl_board_ids,
}; };
module_platform_driver(skylake_audio) module_platform_driver(skylake_audio)
...@@ -520,3 +528,4 @@ MODULE_AUTHOR("Omair Mohammed Abdullah <omair.m.abdullah@intel.com>"); ...@@ -520,3 +528,4 @@ MODULE_AUTHOR("Omair Mohammed Abdullah <omair.m.abdullah@intel.com>");
MODULE_DESCRIPTION("Intel SST Audio for Skylake"); MODULE_DESCRIPTION("Intel SST Audio for Skylake");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:skl_alc286s_i2s"); MODULE_ALIAS("platform:skl_alc286s_i2s");
MODULE_ALIAS("platform:kbl_alc286s_i2s");
...@@ -2,9 +2,9 @@ snd-soc-sst-dsp-objs := sst-dsp.o ...@@ -2,9 +2,9 @@ snd-soc-sst-dsp-objs := sst-dsp.o
snd-soc-sst-acpi-objs := sst-acpi.o snd-soc-sst-acpi-objs := sst-acpi.o
snd-soc-sst-match-objs := sst-match-acpi.o snd-soc-sst-match-objs := sst-match-acpi.o
snd-soc-sst-ipc-objs := sst-ipc.o snd-soc-sst-ipc-objs := sst-ipc.o
snd-soc-sst-firmware-objs := sst-firmware.o
snd-soc-sst-dsp-$(CONFIG_DW_DMAC_CORE) += sst-firmware.o
obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
obj-$(CONFIG_SND_SOC_INTEL_SST_MATCH) += snd-soc-sst-match.o obj-$(CONFIG_SND_SOC_INTEL_SST_MATCH) += snd-soc-sst-match.o
obj-$(CONFIG_SND_SOC_INTEL_SST_FIRMWARE) += snd-soc-sst-firmware.o
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#if IS_ENABLED(CONFIG_ACPI) #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 #else
inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]) static inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
{ {
return NULL; return NULL;
} }
...@@ -40,6 +40,6 @@ struct sst_acpi_mach { ...@@ -40,6 +40,6 @@ struct sst_acpi_mach {
/* board name */ /* board name */
const char *board; const char *board;
void (*machine_quirk)(void); struct sst_acpi_mach * (*machine_quirk)(void *arg);
void *pdata; void *pdata;
}; };
...@@ -383,10 +383,6 @@ struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, ...@@ -383,10 +383,6 @@ struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
u32 index, void *private); u32 index, void *private);
void sst_mem_block_unregister_all(struct sst_dsp *dsp); void sst_mem_block_unregister_all(struct sst_dsp *dsp);
/* Create/Free DMA resources */
int sst_dma_new(struct sst_dsp *sst);
void sst_dma_free(struct sst_dma *dma);
u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset, u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset,
enum sst_mem_type type); enum sst_mem_type type);
#endif #endif
...@@ -285,7 +285,7 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, ...@@ -285,7 +285,7 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
} }
reg = sst_dsp_shim_read_unlocked(ctx, offset); reg = sst_dsp_shim_read_unlocked(ctx, offset);
dev_info(ctx->dev, "FW Poll Status: reg=%#x %s %s\n", reg, operation, dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s %s\n", reg, operation,
(time < timeout) ? "successful" : "timedout"); (time < timeout) ? "successful" : "timedout");
ret = time < timeout ? 0 : -ETIME; ret = time < timeout ? 0 : -ETIME;
...@@ -420,73 +420,6 @@ void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes) ...@@ -420,73 +420,6 @@ void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
} }
EXPORT_SYMBOL_GPL(sst_dsp_inbox_read); EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
#ifdef CONFIG_DW_DMAC_CORE
struct sst_dsp *sst_dsp_new(struct device *dev,
struct sst_dsp_device *sst_dev, struct sst_pdata *pdata)
{
struct sst_dsp *sst;
int err;
dev_dbg(dev, "initialising audio DSP id 0x%x\n", pdata->id);
sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL);
if (sst == NULL)
return NULL;
spin_lock_init(&sst->spinlock);
mutex_init(&sst->mutex);
sst->dev = dev;
sst->dma_dev = pdata->dma_dev;
sst->thread_context = sst_dev->thread_context;
sst->sst_dev = sst_dev;
sst->id = pdata->id;
sst->irq = pdata->irq;
sst->ops = sst_dev->ops;
sst->pdata = pdata;
INIT_LIST_HEAD(&sst->used_block_list);
INIT_LIST_HEAD(&sst->free_block_list);
INIT_LIST_HEAD(&sst->module_list);
INIT_LIST_HEAD(&sst->fw_list);
INIT_LIST_HEAD(&sst->scratch_block_list);
/* Initialise SST Audio DSP */
if (sst->ops->init) {
err = sst->ops->init(sst, pdata);
if (err < 0)
return NULL;
}
/* Register the ISR */
err = request_threaded_irq(sst->irq, sst->ops->irq_handler,
sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
if (err)
goto irq_err;
err = sst_dma_new(sst);
if (err)
dev_warn(dev, "sst_dma_new failed %d\n", err);
return sst;
irq_err:
if (sst->ops->free)
sst->ops->free(sst);
return NULL;
}
EXPORT_SYMBOL_GPL(sst_dsp_new);
void sst_dsp_free(struct sst_dsp *sst)
{
free_irq(sst->irq, sst);
if (sst->ops->free)
sst->ops->free(sst);
sst_dma_free(sst->dma);
}
EXPORT_SYMBOL_GPL(sst_dsp_free);
#endif
/* Module information */ /* Module information */
MODULE_AUTHOR("Liam Girdwood"); MODULE_AUTHOR("Liam Girdwood");
MODULE_DESCRIPTION("Intel SST Core"); MODULE_DESCRIPTION("Intel SST Core");
......
...@@ -216,7 +216,7 @@ struct sst_pdata { ...@@ -216,7 +216,7 @@ struct sst_pdata {
void *dsp; void *dsp;
}; };
#ifdef CONFIG_DW_DMAC_CORE #if IS_ENABLED(CONFIG_DW_DMAC_CORE)
/* Initialization */ /* Initialization */
struct sst_dsp *sst_dsp_new(struct device *dev, struct sst_dsp *sst_dsp_new(struct device *dev,
struct sst_dsp_device *sst_dev, struct sst_pdata *pdata); struct sst_dsp_device *sst_dev, struct sst_pdata *pdata);
......
...@@ -1211,3 +1211,71 @@ u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset, ...@@ -1211,3 +1211,71 @@ u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset,
} }
} }
EXPORT_SYMBOL_GPL(sst_dsp_get_offset); EXPORT_SYMBOL_GPL(sst_dsp_get_offset);
struct sst_dsp *sst_dsp_new(struct device *dev,
struct sst_dsp_device *sst_dev, struct sst_pdata *pdata)
{
struct sst_dsp *sst;
int err;
dev_dbg(dev, "initialising audio DSP id 0x%x\n", pdata->id);
sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL);
if (sst == NULL)
return NULL;
spin_lock_init(&sst->spinlock);
mutex_init(&sst->mutex);
sst->dev = dev;
sst->dma_dev = pdata->dma_dev;
sst->thread_context = sst_dev->thread_context;
sst->sst_dev = sst_dev;
sst->id = pdata->id;
sst->irq = pdata->irq;
sst->ops = sst_dev->ops;
sst->pdata = pdata;
INIT_LIST_HEAD(&sst->used_block_list);
INIT_LIST_HEAD(&sst->free_block_list);
INIT_LIST_HEAD(&sst->module_list);
INIT_LIST_HEAD(&sst->fw_list);
INIT_LIST_HEAD(&sst->scratch_block_list);
/* Initialise SST Audio DSP */
if (sst->ops->init) {
err = sst->ops->init(sst, pdata);
if (err < 0)
return NULL;
}
/* Register the ISR */
err = request_threaded_irq(sst->irq, sst->ops->irq_handler,
sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
if (err)
goto irq_err;
err = sst_dma_new(sst);
if (err)
dev_warn(dev, "sst_dma_new failed %d\n", err);
return sst;
irq_err:
if (sst->ops->free)
sst->ops->free(sst);
return NULL;
}
EXPORT_SYMBOL_GPL(sst_dsp_new);
void sst_dsp_free(struct sst_dsp *sst)
{
free_irq(sst->irq, sst);
if (sst->ops->free)
sst->ops->free(sst);
sst_dma_free(sst->dma);
}
EXPORT_SYMBOL_GPL(sst_dsp_free);
MODULE_DESCRIPTION("Intel SST Firmware Loader");
MODULE_LICENSE("GPL v2");
...@@ -819,7 +819,6 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream) ...@@ -819,7 +819,6 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream)
mutex_lock(&pcm_data->mutex); mutex_lock(&pcm_data->mutex);
pm_runtime_get_sync(pdata->dev); pm_runtime_get_sync(pdata->dev);
snd_soc_pcm_set_drvdata(rtd, pcm_data);
pcm_data->substream = substream; pcm_data->substream = substream;
snd_soc_set_runtime_hwparams(substream, &hsw_pcm_hardware); snd_soc_set_runtime_hwparams(substream, &hsw_pcm_hardware);
......
...@@ -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 bxt-sst.o skl-sst.o bxt-sst.o skl-sst-utils.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o
...@@ -37,11 +37,19 @@ ...@@ -37,11 +37,19 @@
#define BXT_ADSP_SRAM1_BASE 0xA0000 #define BXT_ADSP_SRAM1_BASE 0xA0000
#define BXT_INSTANCE_ID 0
#define BXT_BASE_FW_MODULE_ID 0
static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) static unsigned int bxt_get_errorcode(struct sst_dsp *ctx)
{ {
return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE);
} }
/*
* First boot sequence has some extra steps. Core 0 waits for power
* status on core 1, so power up core 1 also momentarily, keep it in
* reset/stall and then turn it off
*/
static int sst_bxt_prepare_fw(struct sst_dsp *ctx, static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
const void *fwdata, u32 fwsize) const void *fwdata, u32 fwsize)
{ {
...@@ -49,7 +57,7 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, ...@@ -49,7 +57,7 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
u32 reg; u32 reg;
stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab);
if (stream_tag < 0) { if (stream_tag <= 0) {
dev_err(ctx->dev, "Failed to prepare DMA FW loading err: %x\n", dev_err(ctx->dev, "Failed to prepare DMA FW loading err: %x\n",
stream_tag); stream_tag);
return stream_tag; return stream_tag;
...@@ -58,17 +66,27 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, ...@@ -58,17 +66,27 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
ctx->dsp_ops.stream_tag = stream_tag; ctx->dsp_ops.stream_tag = stream_tag;
memcpy(ctx->dmab.area, fwdata, fwsize); memcpy(ctx->dmab.area, fwdata, fwsize);
/* Purge FW request */ /* Step 1: Power up core 0 and core1 */
ret = skl_dsp_core_power_up(ctx, SKL_DSP_CORE0_MASK |
SKL_DSP_CORE_MASK(1));
if (ret < 0) {
dev_err(ctx->dev, "dsp core0/1 power up failed\n");
goto base_fw_load_failed;
}
/* Step 2: Purge FW request */
sst_dsp_shim_write(ctx, SKL_ADSP_REG_HIPCI, SKL_ADSP_REG_HIPCI_BUSY | sst_dsp_shim_write(ctx, SKL_ADSP_REG_HIPCI, SKL_ADSP_REG_HIPCI_BUSY |
BXT_IPC_PURGE_FW | (stream_tag - 1)); (BXT_IPC_PURGE_FW | ((stream_tag - 1) << 9)));
ret = skl_dsp_enable_core(ctx); /* Step 3: Unset core0 reset state & unstall/run core0 */
ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "Boot dsp core failed ret: %d\n", ret); dev_err(ctx->dev, "Start dsp core failed ret: %d\n", ret);
ret = -EIO; ret = -EIO;
goto base_fw_load_failed; goto base_fw_load_failed;
} }
/* Step 4: Wait for DONE Bit */
for (i = BXT_INIT_TIMEOUT; i > 0; --i) { for (i = BXT_INIT_TIMEOUT; i > 0; --i) {
reg = sst_dsp_shim_read(ctx, SKL_ADSP_REG_HIPCIE); reg = sst_dsp_shim_read(ctx, SKL_ADSP_REG_HIPCIE);
...@@ -88,10 +106,18 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, ...@@ -88,10 +106,18 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
SKL_ADSP_REG_HIPCIE_DONE); SKL_ADSP_REG_HIPCIE_DONE);
} }
/* enable Interrupt */ /* Step 5: power down core1 */
ret = skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1));
if (ret < 0) {
dev_err(ctx->dev, "dsp core1 power down failed\n");
goto base_fw_load_failed;
}
/* Step 6: Enable Interrupt */
skl_ipc_int_enable(ctx); skl_ipc_int_enable(ctx);
skl_ipc_op_int_enable(ctx); skl_ipc_op_int_enable(ctx);
/* Step 7: Wait for ROM init */
for (i = BXT_INIT_TIMEOUT; i > 0; --i) { for (i = BXT_INIT_TIMEOUT; i > 0; --i) {
if (SKL_FW_INIT == if (SKL_FW_INIT ==
(sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS) & (sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS) &
...@@ -112,7 +138,8 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, ...@@ -112,7 +138,8 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
base_fw_load_failed: base_fw_load_failed:
ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag); ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag);
skl_dsp_disable_core(ctx); skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1));
skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
return ret; return ret;
} }
...@@ -130,23 +157,41 @@ static int sst_transfer_fw_host_dma(struct sst_dsp *ctx) ...@@ -130,23 +157,41 @@ static int sst_transfer_fw_host_dma(struct sst_dsp *ctx)
return ret; return ret;
} }
#define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000
static int bxt_load_base_firmware(struct sst_dsp *ctx) static int bxt_load_base_firmware(struct sst_dsp *ctx)
{ {
const struct firmware *fw = NULL; struct firmware stripped_fw;
struct skl_sst *skl = ctx->thread_context; struct skl_sst *skl = ctx->thread_context;
int ret; int ret;
ret = request_firmware(&fw, ctx->fw_name, ctx->dev); ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "Request firmware failed %d\n", ret); dev_err(ctx->dev, "Request firmware failed %d\n", ret);
goto sst_load_base_firmware_failed; goto sst_load_base_firmware_failed;
} }
ret = sst_bxt_prepare_fw(ctx, fw->data, fw->size); /* check for extended manifest */
if (ctx->fw == NULL)
goto sst_load_base_firmware_failed;
ret = snd_skl_parse_uuids(ctx, BXT_ADSP_FW_BIN_HDR_OFFSET);
if (ret < 0)
goto sst_load_base_firmware_failed;
stripped_fw.data = ctx->fw->data;
stripped_fw.size = ctx->fw->size;
skl_dsp_strip_extended_manifest(&stripped_fw);
ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size);
/* Retry Enabling core and ROM load. Retry seemed to help */ /* Retry Enabling core and ROM load. Retry seemed to help */
if (ret < 0) { if (ret < 0) {
ret = sst_bxt_prepare_fw(ctx, fw->data, fw->size); ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size);
if (ret < 0) { if (ret < 0) {
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));
dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret); dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret);
goto sst_load_base_firmware_failed; goto sst_load_base_firmware_failed;
} }
...@@ -159,83 +204,135 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx) ...@@ -159,83 +204,135 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx)
sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE),
sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS));
skl_dsp_disable_core(ctx); skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
} else { } else {
dev_dbg(ctx->dev, "Firmware download successful\n"); dev_dbg(ctx->dev, "Firmware download successful\n");
ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, ret = wait_event_timeout(skl->boot_wait, skl->boot_complete,
msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
if (ret == 0) { if (ret == 0) {
dev_err(ctx->dev, "DSP boot fail, FW Ready timeout\n"); dev_err(ctx->dev, "DSP boot fail, FW Ready timeout\n");
skl_dsp_disable_core(ctx); skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
ret = -EIO; ret = -EIO;
} else { } else {
skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
ret = 0; ret = 0;
skl->fw_loaded = true;
} }
} }
sst_load_base_firmware_failed: sst_load_base_firmware_failed:
release_firmware(fw); release_firmware(ctx->fw);
return ret; return ret;
} }
static int bxt_set_dsp_D0(struct sst_dsp *ctx) static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
{ {
struct skl_sst *skl = ctx->thread_context; struct skl_sst *skl = ctx->thread_context;
int ret; int ret;
struct skl_ipc_dxstate_info dx;
unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
skl->boot_complete = false; if (skl->fw_loaded == false) {
skl->boot_complete = false;
ret = skl_dsp_enable_core(ctx); ret = bxt_load_base_firmware(ctx);
if (ret < 0) { if (ret < 0)
dev_err(ctx->dev, "enable dsp core failed ret: %d\n", ret); dev_err(ctx->dev, "reload fw failed: %d\n", ret);
return ret; return ret;
} }
/* enable interrupt */ /* If core 0 is being turned on, turn on core 1 as well */
skl_ipc_int_enable(ctx); if (core_id == SKL_DSP_CORE0_ID)
skl_ipc_op_int_enable(ctx); ret = skl_dsp_core_power_up(ctx, core_mask |
SKL_DSP_CORE_MASK(1));
else
ret = skl_dsp_core_power_up(ctx, core_mask);
if (ret < 0)
goto err;
if (core_id == SKL_DSP_CORE0_ID) {
/*
* Enable interrupt after SPA is set and before
* DSP is unstalled
*/
skl_ipc_int_enable(ctx);
skl_ipc_op_int_enable(ctx);
skl->boot_complete = false;
}
ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, ret = skl_dsp_start_core(ctx, core_mask);
msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); if (ret < 0)
if (ret == 0) { goto err;
dev_err(ctx->dev, "ipc: error DSP boot timeout\n");
dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n", if (core_id == SKL_DSP_CORE0_ID) {
sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), ret = wait_event_timeout(skl->boot_wait,
sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); skl->boot_complete,
return -EIO; msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
/* If core 1 was turned on for booting core 0, turn it off */
skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1));
if (ret == 0) {
dev_err(ctx->dev, "%s: DSP boot timeout\n", __func__);
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));
dev_err(ctx->dev, "Failed to set core0 to D0 state\n");
ret = -EIO;
goto err;
}
}
/* Tell FW if additional core in now On */
if (core_id != SKL_DSP_CORE0_ID) {
dx.core_mask = core_mask;
dx.dx_mask = core_mask;
ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID,
BXT_BASE_FW_MODULE_ID, &dx);
if (ret < 0) {
dev_err(ctx->dev, "IPC set_dx for core %d fail: %d\n",
core_id, ret);
goto err;
}
} }
skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); skl->cores.state[core_id] = SKL_DSP_RUNNING;
return 0; return 0;
err:
if (core_id == SKL_DSP_CORE0_ID)
core_mask |= SKL_DSP_CORE_MASK(1);
skl_dsp_disable_core(ctx, core_mask);
return ret;
} }
static int bxt_set_dsp_D3(struct sst_dsp *ctx) static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
{ {
int ret;
struct skl_ipc_dxstate_info dx; struct skl_ipc_dxstate_info dx;
struct skl_sst *skl = ctx->thread_context; struct skl_sst *skl = ctx->thread_context;
int ret = 0; unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
if (!is_skl_dsp_running(ctx)) dx.core_mask = core_mask;
return ret;
dx.core_mask = SKL_DSP_CORE0_MASK;
dx.dx_mask = SKL_IPC_D3_MASK; dx.dx_mask = SKL_IPC_D3_MASK;
ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, dev_dbg(ctx->dev, "core mask=%x dx_mask=%x\n",
SKL_BASE_FW_MODULE_ID, &dx); dx.core_mask, dx.dx_mask);
if (ret < 0) {
dev_err(ctx->dev, "Failed to set DSP to D3 state: %d\n", ret); ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID,
return ret; BXT_BASE_FW_MODULE_ID, &dx);
} if (ret < 0)
dev_err(ctx->dev,
"Failed to set DSP to D3:core id = %d;Continue reset\n",
core_id);
ret = skl_dsp_disable_core(ctx); ret = skl_dsp_disable_core(ctx, core_mask);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "disbale dsp core failed: %d\n", ret); dev_err(ctx->dev, "Failed to disable core %d", ret);
ret = -EIO; return ret;
} }
skl->cores.state[core_id] = SKL_DSP_RESET;
skl_dsp_set_state_locked(ctx, SKL_DSP_RESET);
return 0; return 0;
} }
...@@ -274,6 +371,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, ...@@ -274,6 +371,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
skl->dev = dev; skl->dev = dev;
skl_dev.thread_context = skl; skl_dev.thread_context = skl;
INIT_LIST_HEAD(&skl->uuid_list);
skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq);
if (!skl->dsp) { if (!skl->dsp) {
...@@ -296,6 +394,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, ...@@ -296,6 +394,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
if (ret) if (ret)
return ret; return ret;
skl->cores.count = 2;
skl->boot_complete = false; skl->boot_complete = false;
init_waitqueue_head(&skl->boot_wait); init_waitqueue_head(&skl->boot_wait);
...@@ -305,6 +404,8 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, ...@@ -305,6 +404,8 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
return ret; return ret;
} }
skl_dsp_init_core_state(sst);
if (dsp) if (dsp)
*dsp = skl; *dsp = skl;
...@@ -315,6 +416,7 @@ EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); ...@@ -315,6 +416,7 @@ EXPORT_SYMBOL_GPL(bxt_sst_dsp_init);
void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
{ {
skl_freeup_uuid_list(ctx);
skl_ipc_free(&ctx->ipc); skl_ipc_free(&ctx->ipc);
ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
......
...@@ -205,6 +205,12 @@ static const struct skl_dsp_ops dsp_ops[] = { ...@@ -205,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 = 0x9d71,
.loader_ops = skl_get_loader_ops,
.init = skl_sst_dsp_init,
.cleanup = skl_sst_dsp_cleanup
},
{ {
.id = 0x5a98, .id = 0x5a98,
.loader_ops = bxt_get_loader_ops, .loader_ops = bxt_get_loader_ops,
...@@ -730,7 +736,7 @@ static int skl_set_module_format(struct skl_sst *ctx, ...@@ -730,7 +736,7 @@ static int skl_set_module_format(struct skl_sst *ctx,
dev_dbg(ctx->dev, "Module type=%d config size: %d bytes\n", dev_dbg(ctx->dev, "Module type=%d config size: %d bytes\n",
module_config->id.module_id, param_size); module_config->id.module_id, param_size);
print_hex_dump(KERN_DEBUG, "Module params:", DUMP_PREFIX_OFFSET, 8, 4, print_hex_dump_debug("Module params:", DUMP_PREFIX_OFFSET, 8, 4,
*param_data, param_size, false); *param_data, param_size, false);
return 0; return 0;
} }
...@@ -1046,7 +1052,7 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) ...@@ -1046,7 +1052,7 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id);
/* If pipe is not started, do not try to stop the pipe in FW. */ /* If pipe is started, do stop the pipe in FW. */
if (pipe->state > SKL_PIPE_STARTED) { if (pipe->state > SKL_PIPE_STARTED) {
ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED);
if (ret < 0) { if (ret < 0) {
...@@ -1055,18 +1061,20 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) ...@@ -1055,18 +1061,20 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
} }
pipe->state = SKL_PIPE_PAUSED; pipe->state = SKL_PIPE_PAUSED;
} else { }
/* If pipe was not created in FW, do not try to delete it */
if (pipe->state < SKL_PIPE_CREATED)
return 0;
ret = skl_ipc_delete_pipeline(&ctx->ipc, pipe->ppl_id); /* If pipe was not created in FW, do not try to delete it */
if (ret < 0) if (pipe->state < SKL_PIPE_CREATED)
dev_err(ctx->dev, "Failed to delete pipeline\n"); return 0;
pipe->state = SKL_PIPE_INVALID; ret = skl_ipc_delete_pipeline(&ctx->ipc, pipe->ppl_id);
if (ret < 0) {
dev_err(ctx->dev, "Failed to delete pipeline\n");
return ret;
} }
pipe->state = SKL_PIPE_INVALID;
return ret; return ret;
} }
...@@ -1125,7 +1133,30 @@ int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) ...@@ -1125,7 +1133,30 @@ int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
return ret; return ret;
} }
pipe->state = SKL_PIPE_CREATED; pipe->state = SKL_PIPE_PAUSED;
return 0;
}
/*
* Reset the pipeline by sending set pipe state IPC this will reset the DMA
* from the DSP side
*/
int skl_reset_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
{
int ret;
/* If pipe was not created in FW, do not try to pause or delete */
if (pipe->state < SKL_PIPE_PAUSED)
return 0;
ret = skl_set_pipe_state(ctx, pipe, PPL_RESET);
if (ret < 0) {
dev_dbg(ctx->dev, "Failed to reset pipe ret=%d\n", ret);
return ret;
}
pipe->state = SKL_PIPE_RESET;
return 0; return 0;
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* *
*/ */
#include <linux/pci.h>
#include "skl.h" #include "skl.h"
/* Unique identification for getting NHLT blobs */ /* Unique identification for getting NHLT blobs */
...@@ -149,6 +150,45 @@ struct nhlt_specific_cfg ...@@ -149,6 +150,45 @@ struct nhlt_specific_cfg
return NULL; return NULL;
} }
int skl_get_dmic_geo(struct skl *skl)
{
struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
struct nhlt_endpoint *epnt;
struct nhlt_dmic_array_config *cfg;
struct device *dev = &skl->pci->dev;
unsigned int dmic_geo = 0;
u8 j;
epnt = (struct nhlt_endpoint *)nhlt->desc;
for (j = 0; j < nhlt->endpoint_count; j++) {
if (epnt->linktype == NHLT_LINK_DMIC) {
cfg = (struct nhlt_dmic_array_config *)
(epnt->config.caps);
switch (cfg->array_type) {
case NHLT_MIC_ARRAY_2CH_SMALL:
case NHLT_MIC_ARRAY_2CH_BIG:
dmic_geo |= MIC_ARRAY_2CH;
break;
case NHLT_MIC_ARRAY_4CH_1ST_GEOM:
case NHLT_MIC_ARRAY_4CH_L_SHAPED:
case NHLT_MIC_ARRAY_4CH_2ND_GEOM:
dmic_geo |= MIC_ARRAY_4CH;
break;
default:
dev_warn(dev, "undefined DMIC array_type 0x%0x\n",
cfg->array_type);
}
}
epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
}
return dmic_geo;
}
static void skl_nhlt_trim_space(struct skl *skl) static void skl_nhlt_trim_space(struct skl *skl)
{ {
char *s = skl->tplg_name; char *s = skl->tplg_name;
......
...@@ -103,4 +103,26 @@ struct nhlt_resource_desc { ...@@ -103,4 +103,26 @@ struct nhlt_resource_desc {
u64 length; u64 length;
} __packed; } __packed;
#define MIC_ARRAY_2CH 2
#define MIC_ARRAY_4CH 4
struct nhlt_tdm_config {
u8 virtual_slot;
u8 config_type;
} __packed;
struct nhlt_dmic_array_config {
struct nhlt_tdm_config tdm_config;
u8 array_type;
} __packed;
enum {
NHLT_MIC_ARRAY_2CH_SMALL = 0xa,
NHLT_MIC_ARRAY_2CH_BIG = 0xb,
NHLT_MIC_ARRAY_4CH_1ST_GEOM = 0xc,
NHLT_MIC_ARRAY_4CH_L_SHAPED = 0xd,
NHLT_MIC_ARRAY_4CH_2ND_GEOM = 0xe,
NHLT_MIC_ARRAY_VENDOR_DEFINED = 0xf,
};
#endif #endif
...@@ -227,16 +227,25 @@ static int skl_pcm_prepare(struct snd_pcm_substream *substream, ...@@ -227,16 +227,25 @@ static int skl_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
struct skl *skl = get_skl_ctx(dai->dev);
unsigned int format_val; unsigned int format_val;
int err; int err;
struct skl_module_cfg *mconfig;
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
format_val = skl_get_format(substream, dai); format_val = skl_get_format(substream, dai);
dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n", dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n",
hdac_stream(stream)->stream_tag, format_val); hdac_stream(stream)->stream_tag, format_val);
snd_hdac_stream_reset(hdac_stream(stream)); snd_hdac_stream_reset(hdac_stream(stream));
/* In case of XRUN recovery, reset the FW pipe to clean state */
if (mconfig && (substream->runtime->status->state ==
SNDRV_PCM_STATE_XRUN))
skl_reset_pipe(skl->skl_sst, mconfig->pipe);
err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); err = snd_hdac_stream_set_params(hdac_stream(stream), format_val);
if (err < 0) if (err < 0)
return err; return err;
...@@ -521,6 +530,8 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, ...@@ -521,6 +530,8 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
struct skl_dma_params *dma_params; struct skl_dma_params *dma_params;
struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct hdac_ext_link *link; struct hdac_ext_link *link;
struct skl *skl = get_skl_ctx(dai->dev);
struct skl_module_cfg *mconfig = NULL;
dma_params = (struct skl_dma_params *) dma_params = (struct skl_dma_params *)
snd_soc_dai_get_dma_data(codec_dai, substream); snd_soc_dai_get_dma_data(codec_dai, substream);
...@@ -535,6 +546,12 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, ...@@ -535,6 +546,12 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
snd_hdac_ext_link_stream_reset(link_dev); snd_hdac_ext_link_stream_reset(link_dev);
/* In case of XRUN recovery, reset the FW pipe to clean state */
mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream);
if (mconfig && (substream->runtime->status->state ==
SNDRV_PCM_STATE_XRUN))
skl_reset_pipe(skl->skl_sst, mconfig->pipe);
snd_hdac_ext_link_stream_setup(link_dev, format_val); snd_hdac_ext_link_stream_setup(link_dev, format_val);
snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag); snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag);
...@@ -1009,51 +1026,11 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, ...@@ -1009,51 +1026,11 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
return 0; return 0;
} }
/* calculate runtime delay from LPIB */ static snd_pcm_uframes_t skl_platform_pcm_pointer
static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus, (struct snd_pcm_substream *substream)
struct hdac_ext_stream *sstream,
unsigned int pos)
{
struct hdac_bus *bus = ebus_to_hbus(ebus);
struct hdac_stream *hstream = hdac_stream(sstream);
struct snd_pcm_substream *substream = hstream->substream;
int stream = substream->stream;
unsigned int lpib_pos = snd_hdac_stream_get_pos_lpib(hstream);
int delay;
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
delay = pos - lpib_pos;
else
delay = lpib_pos - pos;
if (delay < 0) {
if (delay >= hstream->delay_negative_threshold)
delay = 0;
else
delay += hstream->bufsize;
}
if (hstream->bufsize == delay)
delay = 0;
if (delay >= hstream->period_bytes) {
dev_info(bus->dev,
"Unstable LPIB (%d >= %d); disabling LPIB delay counting\n",
delay, hstream->period_bytes);
delay = 0;
}
return bytes_to_frames(substream->runtime, delay);
}
static unsigned int skl_get_position(struct hdac_ext_stream *hstream,
int codec_delay)
{ {
struct hdac_stream *hstr = hdac_stream(hstream); struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream);
struct snd_pcm_substream *substream = hstr->substream;
struct hdac_ext_bus *ebus;
unsigned int pos; unsigned int pos;
int delay;
/* use the position buffer as default */ /* use the position buffer as default */
pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream));
...@@ -1061,23 +1038,7 @@ static unsigned int skl_get_position(struct hdac_ext_stream *hstream, ...@@ -1061,23 +1038,7 @@ static unsigned int skl_get_position(struct hdac_ext_stream *hstream,
if (pos >= hdac_stream(hstream)->bufsize) if (pos >= hdac_stream(hstream)->bufsize)
pos = 0; pos = 0;
if (substream->runtime) { return bytes_to_frames(substream->runtime, pos);
ebus = get_bus_ctx(substream);
delay = skl_get_delay_from_lpib(ebus, hstream, pos)
+ codec_delay;
substream->runtime->delay += delay;
}
return pos;
}
static snd_pcm_uframes_t skl_platform_pcm_pointer
(struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream);
return bytes_to_frames(substream->runtime,
skl_get_position(hstream, 0));
} }
static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream,
...@@ -1180,9 +1141,17 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) ...@@ -1180,9 +1141,17 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
static int skl_platform_soc_probe(struct snd_soc_platform *platform) static int skl_platform_soc_probe(struct snd_soc_platform *platform)
{ {
struct hdac_ext_bus *ebus = dev_get_drvdata(platform->dev); struct hdac_ext_bus *ebus = dev_get_drvdata(platform->dev);
struct skl *skl = ebus_to_skl(ebus);
int ret;
if (ebus->ppcap) if (ebus->ppcap) {
return skl_tplg_init(platform, ebus); ret = skl_tplg_init(platform, ebus);
if (ret < 0) {
dev_err(platform->dev, "Failed to init topology!\n");
return ret;
}
skl->platform = platform;
}
return 0; return 0;
} }
......
...@@ -34,33 +34,84 @@ void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state) ...@@ -34,33 +34,84 @@ void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state)
mutex_unlock(&ctx->mutex); mutex_unlock(&ctx->mutex);
} }
static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx) /*
* Initialize core power state and usage count. To be called after
* successful first boot. Hence core 0 will be running and other cores
* will be reset
*/
void skl_dsp_init_core_state(struct sst_dsp *ctx)
{
struct skl_sst *skl = ctx->thread_context;
int i;
skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING;
skl->cores.usage_count[SKL_DSP_CORE0_ID] = 1;
for (i = SKL_DSP_CORE0_ID + 1; i < SKL_DSP_CORES_MAX; i++) {
skl->cores.state[i] = SKL_DSP_RESET;
skl->cores.usage_count[i] = 0;
}
}
/* Get the mask for all enabled cores */
unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx)
{
struct skl_sst *skl = ctx->thread_context;
unsigned int core_mask, en_cores_mask;
u32 val;
core_mask = SKL_DSP_CORES_MASK(skl->cores.count);
val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS);
/* Cores having CPA bit set */
en_cores_mask = (val & SKL_ADSPCS_CPA_MASK(core_mask)) >>
SKL_ADSPCS_CPA_SHIFT;
/* And cores having CRST bit cleared */
en_cores_mask &= (~val & SKL_ADSPCS_CRST_MASK(core_mask)) >>
SKL_ADSPCS_CRST_SHIFT;
/* And cores having CSTALL bit cleared */
en_cores_mask &= (~val & SKL_ADSPCS_CSTALL_MASK(core_mask)) >>
SKL_ADSPCS_CSTALL_SHIFT;
en_cores_mask &= core_mask;
dev_dbg(ctx->dev, "DSP enabled cores mask = %x\n", en_cores_mask);
return en_cores_mask;
}
static int
skl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
{ {
int ret; int ret;
/* update bits */ /* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, sst_dsp_shim_update_bits_unlocked(ctx,
SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK, SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK(core_mask),
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)); SKL_ADSPCS_CRST_MASK(core_mask));
/* poll with timeout to check if operation successful */ /* poll with timeout to check if operation successful */
ret = sst_dsp_register_poll(ctx, ret = sst_dsp_register_poll(ctx,
SKL_ADSP_REG_ADSPCS, SKL_ADSP_REG_ADSPCS,
SKL_ADSPCS_CRST_MASK, SKL_ADSPCS_CRST_MASK(core_mask),
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK), SKL_ADSPCS_CRST_MASK(core_mask),
SKL_DSP_RESET_TO, SKL_DSP_RESET_TO,
"Set reset"); "Set reset");
if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != SKL_ADSPCS_CRST_MASK(core_mask)) !=
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) { SKL_ADSPCS_CRST_MASK(core_mask)) {
dev_err(ctx->dev, "Set reset state failed\n"); dev_err(ctx->dev, "Set reset state failed: core_mask %x\n",
core_mask);
ret = -EIO; ret = -EIO;
} }
return ret; return ret;
} }
static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx) int skl_dsp_core_unset_reset_state(
struct sst_dsp *ctx, unsigned int core_mask)
{ {
int ret; int ret;
...@@ -68,152 +119,160 @@ static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx) ...@@ -68,152 +119,160 @@ static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx)
/* update bits */ /* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
SKL_ADSPCS_CRST_MASK, 0); SKL_ADSPCS_CRST_MASK(core_mask), 0);
/* poll with timeout to check if operation successful */ /* poll with timeout to check if operation successful */
ret = sst_dsp_register_poll(ctx, ret = sst_dsp_register_poll(ctx,
SKL_ADSP_REG_ADSPCS, SKL_ADSP_REG_ADSPCS,
SKL_ADSPCS_CRST_MASK, SKL_ADSPCS_CRST_MASK(core_mask),
0, 0,
SKL_DSP_RESET_TO, SKL_DSP_RESET_TO,
"Unset reset"); "Unset reset");
if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != 0) { SKL_ADSPCS_CRST_MASK(core_mask)) != 0) {
dev_err(ctx->dev, "Unset reset state failed\n"); dev_err(ctx->dev, "Unset reset state failed: core_mask %x\n",
core_mask);
ret = -EIO; ret = -EIO;
} }
return ret; return ret;
} }
static bool is_skl_dsp_core_enable(struct sst_dsp *ctx) static bool
is_skl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask)
{ {
int val; int val;
bool is_enable; bool is_enable;
val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS); val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS);
is_enable = ((val & SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) && is_enable = ((val & SKL_ADSPCS_CPA_MASK(core_mask)) &&
(val & SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)) && (val & SKL_ADSPCS_SPA_MASK(core_mask)) &&
!(val & SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) && !(val & SKL_ADSPCS_CRST_MASK(core_mask)) &&
!(val & SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK))); !(val & SKL_ADSPCS_CSTALL_MASK(core_mask)));
dev_dbg(ctx->dev, "DSP core(s) enabled? %d : core_mask %x\n",
is_enable, core_mask);
dev_dbg(ctx->dev, "DSP core is enabled=%d\n", is_enable);
return is_enable; return is_enable;
} }
static int skl_dsp_reset_core(struct sst_dsp *ctx) static int skl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask)
{ {
/* stall core */ /* stall core */
sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS, sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & SKL_ADSPCS_CSTALL_MASK(core_mask),
SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)); SKL_ADSPCS_CSTALL_MASK(core_mask));
/* set reset state */ /* set reset state */
return skl_dsp_core_set_reset_state(ctx); return skl_dsp_core_set_reset_state(ctx, core_mask);
} }
static int skl_dsp_start_core(struct sst_dsp *ctx) int skl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask)
{ {
int ret; int ret;
/* unset reset state */ /* unset reset state */
ret = skl_dsp_core_unset_reset_state(ctx); ret = skl_dsp_core_unset_reset_state(ctx, core_mask);
if (ret < 0) { if (ret < 0)
dev_dbg(ctx->dev, "dsp unset reset fails\n");
return ret; return ret;
}
/* run core */ /* run core */
dev_dbg(ctx->dev, "run core...\n"); dev_dbg(ctx->dev, "unstall/run core: core_mask = %x\n", core_mask);
sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS, sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & SKL_ADSPCS_CSTALL_MASK(core_mask), 0);
~SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK));
if (!is_skl_dsp_core_enable(ctx, core_mask)) {
if (!is_skl_dsp_core_enable(ctx)) { skl_dsp_reset_core(ctx, core_mask);
skl_dsp_reset_core(ctx); dev_err(ctx->dev, "DSP start core failed: core_mask %x\n",
dev_err(ctx->dev, "DSP core enable failed\n"); core_mask);
ret = -EIO; ret = -EIO;
} }
return ret; return ret;
} }
static int skl_dsp_core_power_up(struct sst_dsp *ctx) int skl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask)
{ {
int ret; int ret;
/* update bits */ /* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
SKL_ADSPCS_SPA_MASK, SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)); SKL_ADSPCS_SPA_MASK(core_mask),
SKL_ADSPCS_SPA_MASK(core_mask));
/* poll with timeout to check if operation successful */ /* poll with timeout to check if operation successful */
ret = sst_dsp_register_poll(ctx, ret = sst_dsp_register_poll(ctx,
SKL_ADSP_REG_ADSPCS, SKL_ADSP_REG_ADSPCS,
SKL_ADSPCS_CPA_MASK, SKL_ADSPCS_CPA_MASK(core_mask),
SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK), SKL_ADSPCS_CPA_MASK(core_mask),
SKL_DSP_PU_TO, SKL_DSP_PU_TO,
"Power up"); "Power up");
if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) != SKL_ADSPCS_CPA_MASK(core_mask)) !=
SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) { SKL_ADSPCS_CPA_MASK(core_mask)) {
dev_err(ctx->dev, "DSP core power up failed\n"); dev_err(ctx->dev, "DSP core power up failed: core_mask %x\n",
core_mask);
ret = -EIO; ret = -EIO;
} }
return ret; return ret;
} }
static int skl_dsp_core_power_down(struct sst_dsp *ctx) int skl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask)
{ {
/* update bits */ /* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
SKL_ADSPCS_SPA_MASK, 0); SKL_ADSPCS_SPA_MASK(core_mask), 0);
/* poll with timeout to check if operation successful */ /* poll with timeout to check if operation successful */
return sst_dsp_register_poll(ctx, return sst_dsp_register_poll(ctx,
SKL_ADSP_REG_ADSPCS, SKL_ADSP_REG_ADSPCS,
SKL_ADSPCS_CPA_MASK, SKL_ADSPCS_CPA_MASK(core_mask),
0, 0,
SKL_DSP_PD_TO, SKL_DSP_PD_TO,
"Power down"); "Power down");
} }
int skl_dsp_enable_core(struct sst_dsp *ctx) int skl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask)
{ {
int ret; int ret;
/* power up */ /* power up */
ret = skl_dsp_core_power_up(ctx); ret = skl_dsp_core_power_up(ctx, core_mask);
if (ret < 0) { if (ret < 0) {
dev_dbg(ctx->dev, "dsp core power up failed\n"); dev_err(ctx->dev, "dsp core power up failed: core_mask %x\n",
core_mask);
return ret; return ret;
} }
return skl_dsp_start_core(ctx); return skl_dsp_start_core(ctx, core_mask);
} }
int skl_dsp_disable_core(struct sst_dsp *ctx) int skl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask)
{ {
int ret; int ret;
ret = skl_dsp_reset_core(ctx); ret = skl_dsp_reset_core(ctx, core_mask);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "dsp core reset failed\n"); dev_err(ctx->dev, "dsp core reset failed: core_mask %x\n",
core_mask);
return ret; return ret;
} }
/* power down core*/ /* power down core*/
ret = skl_dsp_core_power_down(ctx); ret = skl_dsp_core_power_down(ctx, core_mask);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "dsp core power down failed\n"); dev_err(ctx->dev, "dsp core power down fail mask %x: %d\n",
core_mask, ret);
return ret; return ret;
} }
if (is_skl_dsp_core_enable(ctx)) { if (is_skl_dsp_core_enable(ctx, core_mask)) {
dev_err(ctx->dev, "DSP core disable failed\n"); dev_err(ctx->dev, "dsp core disable fail mask %x: %d\n",
core_mask, ret);
ret = -EIO; ret = -EIO;
} }
...@@ -224,28 +283,25 @@ int skl_dsp_boot(struct sst_dsp *ctx) ...@@ -224,28 +283,25 @@ int skl_dsp_boot(struct sst_dsp *ctx)
{ {
int ret; int ret;
if (is_skl_dsp_core_enable(ctx)) { if (is_skl_dsp_core_enable(ctx, SKL_DSP_CORE0_MASK)) {
dev_dbg(ctx->dev, "dsp core is already enabled, so reset the dap core\n"); ret = skl_dsp_reset_core(ctx, SKL_DSP_CORE0_MASK);
ret = skl_dsp_reset_core(ctx);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "dsp reset failed\n"); dev_err(ctx->dev, "dsp core0 reset fail: %d\n", ret);
return ret; return ret;
} }
ret = skl_dsp_start_core(ctx); ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "dsp start failed\n"); dev_err(ctx->dev, "dsp core0 start fail: %d\n", ret);
return ret; return ret;
} }
} else { } else {
dev_dbg(ctx->dev, "disable and enable to make sure DSP is invalid state\n"); ret = skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
ret = skl_dsp_disable_core(ctx);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "dsp disable core failes\n"); dev_err(ctx->dev, "dsp core0 disable fail: %d\n", ret);
return ret; return ret;
} }
ret = skl_dsp_enable_core(ctx); ret = skl_dsp_enable_core(ctx, SKL_DSP_CORE0_MASK);
} }
return ret; return ret;
...@@ -281,16 +337,74 @@ irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) ...@@ -281,16 +337,74 @@ irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id)
return result; return result;
} }
/*
* skl_dsp_get_core/skl_dsp_put_core will be called inside DAPM context
* within the dapm mutex. Hence no separate lock is used.
*/
int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id)
{
struct skl_sst *skl = ctx->thread_context;
int ret = 0;
if (core_id >= skl->cores.count) {
dev_err(ctx->dev, "invalid core id: %d\n", core_id);
return -EINVAL;
}
if (skl->cores.state[core_id] == SKL_DSP_RESET) {
ret = ctx->fw_ops.set_state_D0(ctx, core_id);
if (ret < 0) {
dev_err(ctx->dev, "unable to get core%d\n", core_id);
return ret;
}
}
skl->cores.usage_count[core_id]++;
dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
core_id, skl->cores.state[core_id],
skl->cores.usage_count[core_id]);
return ret;
}
EXPORT_SYMBOL_GPL(skl_dsp_get_core);
int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id)
{
struct skl_sst *skl = ctx->thread_context;
int ret = 0;
if (core_id >= skl->cores.count) {
dev_err(ctx->dev, "invalid core id: %d\n", core_id);
return -EINVAL;
}
if (--skl->cores.usage_count[core_id] == 0) {
ret = ctx->fw_ops.set_state_D3(ctx, core_id);
if (ret < 0) {
dev_err(ctx->dev, "unable to put core %d: %d\n",
core_id, ret);
skl->cores.usage_count[core_id]++;
}
}
dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
core_id, skl->cores.state[core_id],
skl->cores.usage_count[core_id]);
return ret;
}
EXPORT_SYMBOL_GPL(skl_dsp_put_core);
int skl_dsp_wake(struct sst_dsp *ctx) int skl_dsp_wake(struct sst_dsp *ctx)
{ {
return ctx->fw_ops.set_state_D0(ctx); return skl_dsp_get_core(ctx, SKL_DSP_CORE0_ID);
} }
EXPORT_SYMBOL_GPL(skl_dsp_wake); EXPORT_SYMBOL_GPL(skl_dsp_wake);
int skl_dsp_sleep(struct sst_dsp *ctx) int skl_dsp_sleep(struct sst_dsp *ctx)
{ {
return ctx->fw_ops.set_state_D3(ctx); return skl_dsp_put_core(ctx, SKL_DSP_CORE0_ID);
} }
EXPORT_SYMBOL_GPL(skl_dsp_sleep); EXPORT_SYMBOL_GPL(skl_dsp_sleep);
...@@ -337,9 +451,7 @@ void skl_dsp_free(struct sst_dsp *dsp) ...@@ -337,9 +451,7 @@ void skl_dsp_free(struct sst_dsp *dsp)
free_irq(dsp->irq, dsp); free_irq(dsp->irq, dsp);
skl_ipc_op_int_disable(dsp); skl_ipc_op_int_disable(dsp);
skl_ipc_int_disable(dsp); skl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK);
skl_dsp_disable_core(dsp);
} }
EXPORT_SYMBOL_GPL(skl_dsp_free); EXPORT_SYMBOL_GPL(skl_dsp_free);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <sound/memalloc.h> #include <sound/memalloc.h>
#include "skl-sst-cldma.h" #include "skl-sst-cldma.h"
#include "skl-tplg-interface.h"
struct sst_dsp; struct sst_dsp;
struct skl_sst; struct skl_sst;
...@@ -76,35 +77,53 @@ struct sst_dsp_device; ...@@ -76,35 +77,53 @@ struct sst_dsp_device;
#define SKL_ADSPIC_IPC 1 #define SKL_ADSPIC_IPC 1
#define SKL_ADSPIS_IPC 1 #define SKL_ADSPIS_IPC 1
/* Core ID of core0 */
#define SKL_DSP_CORE0_ID 0
/* Mask for a given core index, c = 0.. number of supported cores - 1 */
#define SKL_DSP_CORE_MASK(c) BIT(c)
/*
* Core 0 mask = SKL_DSP_CORE_MASK(0); Defined separately
* since Core0 is primary core and it is used often
*/
#define SKL_DSP_CORE0_MASK BIT(0)
/*
* Mask for a given number of cores
* nc = number of supported cores
*/
#define SKL_DSP_CORES_MASK(nc) GENMASK((nc - 1), 0)
/* ADSPCS - Audio DSP Control & Status */ /* ADSPCS - Audio DSP Control & Status */
#define SKL_DSP_CORES 1
#define SKL_DSP_CORE0_MASK 1 /*
#define SKL_DSP_CORES_MASK ((1 << SKL_DSP_CORES) - 1) * Core Reset - asserted high
* CRST Mask for a given core mask pattern, cm
/* Core Reset - asserted high */ */
#define SKL_ADSPCS_CRST_SHIFT 0 #define SKL_ADSPCS_CRST_SHIFT 0
#define SKL_ADSPCS_CRST_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_CRST_SHIFT) #define SKL_ADSPCS_CRST_MASK(cm) ((cm) << SKL_ADSPCS_CRST_SHIFT)
#define SKL_ADSPCS_CRST(x) ((x << SKL_ADSPCS_CRST_SHIFT) & SKL_ADSPCS_CRST_MASK)
/*
/* Core run/stall - when set to '1' core is stalled */ * Core run/stall - when set to '1' core is stalled
#define SKL_ADSPCS_CSTALL_SHIFT 8 * CSTALL Mask for a given core mask pattern, cm
#define SKL_ADSPCS_CSTALL_MASK (SKL_DSP_CORES_MASK << \ */
SKL_ADSPCS_CSTALL_SHIFT) #define SKL_ADSPCS_CSTALL_SHIFT 8
#define SKL_ADSPCS_CSTALL(x) ((x << SKL_ADSPCS_CSTALL_SHIFT) & \ #define SKL_ADSPCS_CSTALL_MASK(cm) ((cm) << SKL_ADSPCS_CSTALL_SHIFT)
SKL_ADSPCS_CSTALL_MASK)
/*
/* Set Power Active - when set to '1' turn cores on */ * Set Power Active - when set to '1' turn cores on
#define SKL_ADSPCS_SPA_SHIFT 16 * SPA Mask for a given core mask pattern, cm
#define SKL_ADSPCS_SPA_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_SPA_SHIFT) */
#define SKL_ADSPCS_SPA(x) ((x << SKL_ADSPCS_SPA_SHIFT) & SKL_ADSPCS_SPA_MASK) #define SKL_ADSPCS_SPA_SHIFT 16
#define SKL_ADSPCS_SPA_MASK(cm) ((cm) << SKL_ADSPCS_SPA_SHIFT)
/* Current Power Active - power status of cores, set by hardware */
#define SKL_ADSPCS_CPA_SHIFT 24 /*
#define SKL_ADSPCS_CPA_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_CPA_SHIFT) * Current Power Active - power status of cores, set by hardware
#define SKL_ADSPCS_CPA(x) ((x << SKL_ADSPCS_CPA_SHIFT) & SKL_ADSPCS_CPA_MASK) * CPA Mask for a given core mask pattern, cm
*/
#define SST_DSP_POWER_D0 0x0 /* full On */ #define SKL_ADSPCS_CPA_SHIFT 24
#define SST_DSP_POWER_D3 0x3 /* Off */ #define SKL_ADSPCS_CPA_MASK(cm) ((cm) << SKL_ADSPCS_CPA_SHIFT)
enum skl_dsp_states { enum skl_dsp_states {
SKL_DSP_RUNNING = 1, SKL_DSP_RUNNING = 1,
...@@ -115,8 +134,8 @@ struct skl_dsp_fw_ops { ...@@ -115,8 +134,8 @@ struct skl_dsp_fw_ops {
int (*load_fw)(struct sst_dsp *ctx); int (*load_fw)(struct sst_dsp *ctx);
/* FW module parser/loader */ /* FW module parser/loader */
int (*parse_fw)(struct sst_dsp *ctx); int (*parse_fw)(struct sst_dsp *ctx);
int (*set_state_D0)(struct sst_dsp *ctx); int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id);
int (*set_state_D3)(struct sst_dsp *ctx); int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id);
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, u8 *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);
...@@ -157,14 +176,26 @@ int skl_cldma_prepare(struct sst_dsp *ctx); ...@@ -157,14 +176,26 @@ int skl_cldma_prepare(struct sst_dsp *ctx);
void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state);
struct sst_dsp *skl_dsp_ctx_init(struct device *dev, struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
struct sst_dsp_device *sst_dev, int irq); struct sst_dsp_device *sst_dev, int irq);
int skl_dsp_enable_core(struct sst_dsp *ctx);
int skl_dsp_disable_core(struct sst_dsp *ctx);
bool is_skl_dsp_running(struct sst_dsp *ctx); bool is_skl_dsp_running(struct sst_dsp *ctx);
unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx);
void skl_dsp_init_core_state(struct sst_dsp *ctx);
int skl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask);
int skl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask);
int skl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask);
int skl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask);
int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx,
unsigned int core_mask);
int skl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask);
irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id); irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id);
int skl_dsp_wake(struct sst_dsp *ctx); int skl_dsp_wake(struct sst_dsp *ctx);
int skl_dsp_sleep(struct sst_dsp *ctx); int skl_dsp_sleep(struct sst_dsp *ctx);
void skl_dsp_free(struct sst_dsp *dsp); void skl_dsp_free(struct sst_dsp *dsp);
int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id);
int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id);
int skl_dsp_boot(struct sst_dsp *ctx); 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,
...@@ -175,4 +206,11 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, ...@@ -175,4 +206,11 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
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); void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid,
struct skl_dfw_module *dfw_config);
int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset);
void skl_freeup_uuid_list(struct skl_sst *ctx);
int skl_dsp_strip_extended_manifest(struct firmware *fw);
#endif /*__SKL_SST_DSP_H__*/ #endif /*__SKL_SST_DSP_H__*/
...@@ -363,7 +363,7 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, ...@@ -363,7 +363,7 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
/* first process the header */ /* first process the header */
switch (reply) { switch (reply) {
case IPC_GLB_REPLY_SUCCESS: case IPC_GLB_REPLY_SUCCESS:
dev_info(ipc->dev, "ipc FW reply %x: success\n", header.primary); dev_dbg(ipc->dev, "ipc FW reply %x: success\n", header.primary);
/* copy the rx data from the mailbox */ /* copy the rx data from the mailbox */
sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size); sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size);
break; break;
...@@ -692,7 +692,7 @@ int skl_ipc_init_instance(struct sst_generic_ipc *ipc, ...@@ -692,7 +692,7 @@ int skl_ipc_init_instance(struct sst_generic_ipc *ipc,
/* param_block_size must be in dwords */ /* param_block_size must be in dwords */
u16 param_block_size = msg->param_data_size / sizeof(u32); u16 param_block_size = msg->param_data_size / sizeof(u32);
print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE, print_hex_dump_debug("Param data:", DUMP_PREFIX_NONE,
16, 4, buffer, param_block_size, false); 16, 4, buffer, param_block_size, false);
header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
......
...@@ -45,6 +45,14 @@ struct skl_ipc_header { ...@@ -45,6 +45,14 @@ struct skl_ipc_header {
u32 extension; u32 extension;
}; };
#define SKL_DSP_CORES_MAX 2
struct skl_dsp_cores {
unsigned int count;
enum skl_dsp_states state[SKL_DSP_CORES_MAX];
int usage_count[SKL_DSP_CORES_MAX];
};
struct skl_sst { struct skl_sst {
struct device *dev; struct device *dev;
struct sst_dsp *dsp; struct sst_dsp *dsp;
...@@ -60,6 +68,15 @@ struct skl_sst { ...@@ -60,6 +68,15 @@ struct skl_sst {
void (*enable_miscbdcge)(struct device *dev, bool enable); void (*enable_miscbdcge)(struct device *dev, bool enable);
/*Is CGCTL.MISCBDCGE disabled*/ /*Is CGCTL.MISCBDCGE disabled*/
bool miscbdcg_disabled; bool miscbdcg_disabled;
/* Populate module information */
struct list_head uuid_list;
/* Is firmware loaded */
bool fw_loaded;
/* multi-core */
struct skl_dsp_cores cores;
}; };
struct skl_ipc_init_instance_msg { struct skl_ipc_init_instance_msg {
...@@ -136,5 +153,6 @@ void skl_ipc_int_disable(struct sst_dsp *dsp); ...@@ -136,5 +153,6 @@ void skl_ipc_int_disable(struct sst_dsp *dsp);
bool skl_ipc_int_status(struct sst_dsp *dsp); bool skl_ipc_int_status(struct sst_dsp *dsp);
void skl_ipc_free(struct sst_generic_ipc *ipc); void skl_ipc_free(struct sst_generic_ipc *ipc);
int skl_ipc_init(struct device *dev, struct skl_sst *skl); int skl_ipc_init(struct device *dev, struct skl_sst *skl);
void skl_clear_module_cnt(struct sst_dsp *ctx);
#endif /* __SKL_IPC_H */ #endif /* __SKL_IPC_H */
/*
* skl-sst-utils.c - SKL sst utils functions
*
* Copyright (C) 2016 Intel Corp
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as 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/device.h>
#include <linux/slab.h>
#include <linux/uuid.h>
#include "skl-sst-dsp.h"
#include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h"
#include "skl-sst-ipc.h"
#define UUID_STR_SIZE 37
#define DEFAULT_HASH_SHA256_LEN 32
/* FW Extended Manifest Header id = $AE1 */
#define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124
struct skl_dfw_module_mod {
char name[100];
struct skl_dfw_module skl_dfw_mod;
};
struct UUID {
u8 id[16];
};
union seg_flags {
u32 ul;
struct {
u32 contents : 1;
u32 alloc : 1;
u32 load : 1;
u32 read_only : 1;
u32 code : 1;
u32 data : 1;
u32 _rsvd0 : 2;
u32 type : 4;
u32 _rsvd1 : 4;
u32 length : 16;
} r;
} __packed;
struct segment_desc {
union seg_flags flags;
u32 v_base_addr;
u32 file_offset;
};
struct module_type {
u32 load_type : 4;
u32 auto_start : 1;
u32 domain_ll : 1;
u32 domain_dp : 1;
u32 rsvd : 25;
} __packed;
struct adsp_module_entry {
u32 struct_id;
u8 name[8];
struct UUID uuid;
struct module_type type;
u8 hash1[DEFAULT_HASH_SHA256_LEN];
u32 entry_point;
u16 cfg_offset;
u16 cfg_count;
u32 affinity_mask;
u16 instance_max_count;
u16 instance_bss_size;
struct segment_desc segments[3];
} __packed;
struct adsp_fw_hdr {
u32 id;
u32 len;
u8 name[8];
u32 preload_page_count;
u32 fw_image_flags;
u32 feature_mask;
u16 major;
u16 minor;
u16 hotfix;
u16 build;
u32 num_modules;
u32 hw_buf_base;
u32 hw_buf_length;
u32 load_offset;
} __packed;
struct uuid_module {
uuid_le uuid;
int id;
int is_loadable;
struct list_head list;
};
struct skl_ext_manifest_hdr {
u32 id;
u32 len;
u16 version_major;
u16 version_minor;
u32 entries;
};
int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid,
struct skl_dfw_module *dfw_config)
{
struct uuid_module *module;
uuid_le *uuid_mod;
uuid_mod = (uuid_le *)uuid;
list_for_each_entry(module, &ctx->uuid_list, list) {
if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
dfw_config->module_id = module->id;
dfw_config->is_loadable = module->is_loadable;
return 0;
}
}
return -EINVAL;
}
EXPORT_SYMBOL_GPL(snd_skl_get_module_info);
/*
* Parse the firmware binary to get the UUID, module id
* and loadable flags
*/
int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset)
{
struct adsp_fw_hdr *adsp_hdr;
struct adsp_module_entry *mod_entry;
int i, num_entry;
uuid_le *uuid_bin;
const char *buf;
struct skl_sst *skl = ctx->thread_context;
struct uuid_module *module;
struct firmware stripped_fw;
unsigned int safe_file;
/* Get the FW pointer to derive ADSP header */
stripped_fw.data = ctx->fw->data;
stripped_fw.size = ctx->fw->size;
skl_dsp_strip_extended_manifest(&stripped_fw);
buf = stripped_fw.data;
/* check if we have enough space in file to move to header */
safe_file = sizeof(*adsp_hdr) + offset;
if (stripped_fw.size <= safe_file) {
dev_err(ctx->dev, "Small fw file size, No space for hdr\n");
return -EINVAL;
}
adsp_hdr = (struct adsp_fw_hdr *)(buf + offset);
/* check 1st module entry is in file */
safe_file += adsp_hdr->len + sizeof(*mod_entry);
if (stripped_fw.size <= safe_file) {
dev_err(ctx->dev, "Small fw file size, No module entry\n");
return -EINVAL;
}
mod_entry = (struct adsp_module_entry *)
(buf + offset + adsp_hdr->len);
num_entry = adsp_hdr->num_modules;
/* check all entries are in file */
safe_file += num_entry * sizeof(*mod_entry);
if (stripped_fw.size <= safe_file) {
dev_err(ctx->dev, "Small fw file size, No modules\n");
return -EINVAL;
}
/*
* Read the UUID(GUID) from FW Manifest.
*
* The 16 byte UUID format is: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX
* Populate the UUID table to store module_id and loadable flags
* for the module.
*/
for (i = 0; i < num_entry; i++, mod_entry++) {
module = kzalloc(sizeof(*module), GFP_KERNEL);
if (!module)
return -ENOMEM;
uuid_bin = (uuid_le *)mod_entry->uuid.id;
memcpy(&module->uuid, uuid_bin, sizeof(module->uuid));
module->id = i;
module->is_loadable = mod_entry->type.load_type;
list_add_tail(&module->list, &skl->uuid_list);
dev_dbg(ctx->dev,
"Adding uuid :%pUL mod id: %d Loadable: %d\n",
&module->uuid, module->id, module->is_loadable);
}
return 0;
}
void skl_freeup_uuid_list(struct skl_sst *ctx)
{
struct uuid_module *uuid, *_uuid;
list_for_each_entry_safe(uuid, _uuid, &ctx->uuid_list, list) {
list_del(&uuid->list);
kfree(uuid);
}
}
/*
* some firmware binary contains some extended manifest. This needs
* to be stripped in that case before we load and use that image.
*
* Get the module id for the module by checking
* the table for the UUID for the module
*/
int skl_dsp_strip_extended_manifest(struct firmware *fw)
{
struct skl_ext_manifest_hdr *hdr;
/* check if fw file is greater than header we are looking */
if (fw->size < sizeof(hdr)) {
pr_err("%s: Firmware file small, no hdr\n", __func__);
return -EINVAL;
}
hdr = (struct skl_ext_manifest_hdr *)fw->data;
if (hdr->id == SKL_EXT_MANIFEST_HEADER_MAGIC) {
fw->size -= hdr->len;
fw->data += hdr->len;
}
return 0;
}
...@@ -68,10 +68,13 @@ static int skl_transfer_firmware(struct sst_dsp *ctx, ...@@ -68,10 +68,13 @@ static int skl_transfer_firmware(struct sst_dsp *ctx,
return ret; return ret;
} }
#define SKL_ADSP_FW_BIN_HDR_OFFSET 0x284
static int skl_load_base_firmware(struct sst_dsp *ctx) static int skl_load_base_firmware(struct sst_dsp *ctx)
{ {
int ret = 0, i; int ret = 0, i;
struct skl_sst *skl = ctx->thread_context; struct skl_sst *skl = ctx->thread_context;
struct firmware stripped_fw;
u32 reg; u32 reg;
skl->boot_complete = false; skl->boot_complete = false;
...@@ -81,11 +84,25 @@ static int skl_load_base_firmware(struct sst_dsp *ctx) ...@@ -81,11 +84,25 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "Request firmware failed %d\n", ret); dev_err(ctx->dev, "Request firmware failed %d\n", ret);
skl_dsp_disable_core(ctx);
return -EIO; return -EIO;
} }
} }
ret = snd_skl_parse_uuids(ctx, SKL_ADSP_FW_BIN_HDR_OFFSET);
if (ret < 0) {
dev_err(ctx->dev,
"UUID parsing err: %d\n", ret);
release_firmware(ctx->fw);
skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
return ret;
}
/* check for extended manifest */
stripped_fw.data = ctx->fw->data;
stripped_fw.size = ctx->fw->size;
skl_dsp_strip_extended_manifest(&stripped_fw);
ret = skl_dsp_boot(ctx); ret = skl_dsp_boot(ctx);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "Boot dsp core failed ret: %d", ret); dev_err(ctx->dev, "Boot dsp core failed ret: %d", ret);
...@@ -119,7 +136,7 @@ static int skl_load_base_firmware(struct sst_dsp *ctx) ...@@ -119,7 +136,7 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
goto transfer_firmware_failed; goto transfer_firmware_failed;
} }
ret = skl_transfer_firmware(ctx, ctx->fw->data, ctx->fw->size); ret = skl_transfer_firmware(ctx, stripped_fw.data, stripped_fw.size);
if (ret < 0) { if (ret < 0) {
dev_err(ctx->dev, "Transfer firmware failed%d\n", ret); dev_err(ctx->dev, "Transfer firmware failed%d\n", ret);
goto transfer_firmware_failed; goto transfer_firmware_failed;
...@@ -133,67 +150,87 @@ static int skl_load_base_firmware(struct sst_dsp *ctx) ...@@ -133,67 +150,87 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
} }
dev_dbg(ctx->dev, "Download firmware successful%d\n", ret); dev_dbg(ctx->dev, "Download firmware successful%d\n", ret);
skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); skl->fw_loaded = true;
} }
return 0; return 0;
transfer_firmware_failed: transfer_firmware_failed:
ctx->cl_dev.ops.cl_cleanup_controller(ctx); ctx->cl_dev.ops.cl_cleanup_controller(ctx);
skl_load_base_firmware_failed: skl_load_base_firmware_failed:
skl_dsp_disable_core(ctx); skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
release_firmware(ctx->fw); release_firmware(ctx->fw);
ctx->fw = NULL; ctx->fw = NULL;
return ret; return ret;
} }
static int skl_set_dsp_D0(struct sst_dsp *ctx) static int skl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
{ {
int ret; int ret;
struct skl_ipc_dxstate_info dx;
struct skl_sst *skl = ctx->thread_context;
unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
ret = skl_load_base_firmware(ctx); /* If core0 is being turned on, we need to load the FW */
if (ret < 0) { if (core_id == SKL_DSP_CORE0_ID) {
dev_err(ctx->dev, "unable to load firmware\n"); ret = skl_load_base_firmware(ctx);
return ret; if (ret < 0) {
dev_err(ctx->dev, "unable to load firmware\n");
return ret;
}
} }
skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); /*
* If any core other than core 0 is being moved to D0, enable the
* core and send the set dx IPC for the core.
*/
if (core_id != SKL_DSP_CORE0_ID) {
ret = skl_dsp_enable_core(ctx, core_mask);
if (ret < 0)
return ret;
dx.core_mask = core_mask;
dx.dx_mask = core_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 D0:core id= %d\n",
core_id);
skl_dsp_disable_core(ctx, core_mask);
}
}
skl->cores.state[core_id] = SKL_DSP_RUNNING;
return ret; return ret;
} }
static int skl_set_dsp_D3(struct sst_dsp *ctx) static int skl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
{ {
int ret; int ret;
struct skl_ipc_dxstate_info dx; struct skl_ipc_dxstate_info dx;
struct skl_sst *skl = ctx->thread_context; struct skl_sst *skl = ctx->thread_context;
unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
dev_dbg(ctx->dev, "In %s:\n", __func__); dx.core_mask = core_mask;
mutex_lock(&ctx->mutex);
if (!is_skl_dsp_running(ctx)) {
mutex_unlock(&ctx->mutex);
return 0;
}
mutex_unlock(&ctx->mutex);
dx.core_mask = SKL_DSP_CORE0_MASK;
dx.dx_mask = SKL_IPC_D3_MASK; dx.dx_mask = SKL_IPC_D3_MASK;
ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx); ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx);
if (ret < 0) if (ret < 0)
dev_err(ctx->dev, dev_err(ctx->dev, "set Dx core %d fail: %d\n", core_id, ret);
"D3 request to FW failed, continuing reset: %d", ret);
if (core_id == SKL_DSP_CORE0_ID) {
/* disable Interrupt */ /* disable Interrupt */
ctx->cl_dev.ops.cl_cleanup_controller(ctx); ctx->cl_dev.ops.cl_cleanup_controller(ctx);
skl_cldma_int_disable(ctx); skl_cldma_int_disable(ctx);
skl_ipc_op_int_disable(ctx); skl_ipc_op_int_disable(ctx);
skl_ipc_int_disable(ctx); skl_ipc_int_disable(ctx);
ret = skl_dsp_disable_core(ctx);
if (ret < 0) {
dev_err(ctx->dev, "disable dsp core failed ret: %d\n", ret);
ret = -EIO;
} }
skl_dsp_set_state_locked(ctx, SKL_DSP_RESET);
ret = skl_dsp_disable_core(ctx, core_mask);
if (ret < 0)
return ret;
skl->cores.state[core_id] = SKL_DSP_RESET;
return ret; return ret;
} }
...@@ -360,6 +397,19 @@ static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id) ...@@ -360,6 +397,19 @@ static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id)
return ret; return ret;
} }
void skl_clear_module_cnt(struct sst_dsp *ctx)
{
struct skl_module_table *module;
if (list_empty(&ctx->module_list))
return;
list_for_each_entry(module, &ctx->module_list, list) {
module->usage_cnt = 0;
}
}
EXPORT_SYMBOL_GPL(skl_clear_module_cnt);
static void skl_clear_module_table(struct sst_dsp *ctx) static void skl_clear_module_table(struct sst_dsp *ctx)
{ {
struct skl_module_table *module, *tmp; struct skl_module_table *module, *tmp;
...@@ -409,6 +459,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, ...@@ -409,6 +459,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
skl->dev = dev; skl->dev = dev;
skl_dev.thread_context = skl; skl_dev.thread_context = skl;
INIT_LIST_HEAD(&skl->uuid_list);
skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq);
if (!skl->dsp) { if (!skl->dsp) {
...@@ -432,12 +483,16 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, ...@@ -432,12 +483,16 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
if (ret) if (ret)
return ret; return ret;
skl->cores.count = 2;
ret = sst->fw_ops.load_fw(sst); ret = sst->fw_ops.load_fw(sst);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Load base fw failed : %d", ret); dev_err(dev, "Load base fw failed : %d", ret);
goto cleanup; goto cleanup;
} }
skl_dsp_init_core_state(sst);
if (dsp) if (dsp)
*dsp = skl; *dsp = skl;
...@@ -452,6 +507,7 @@ EXPORT_SYMBOL_GPL(skl_sst_dsp_init); ...@@ -452,6 +507,7 @@ EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) 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_freeup_uuid_list(ctx);
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) { if (ctx->boot_complete) {
......
...@@ -378,43 +378,6 @@ static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, ...@@ -378,43 +378,6 @@ static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
skl_dump_mconfig(ctx, m_cfg); skl_dump_mconfig(ctx, m_cfg);
} }
/*
* A pipe can have multiple modules, each of them will be a DAPM widget as
* well. While managing a pipeline we need to get the list of all the
* widgets in a pipelines, so this helper - skl_tplg_get_pipe_widget() helps
* to get the SKL type widgets in that pipeline
*/
static int skl_tplg_alloc_pipe_widget(struct device *dev,
struct snd_soc_dapm_widget *w, struct skl_pipe *pipe)
{
struct skl_module_cfg *src_module = NULL;
struct snd_soc_dapm_path *p = NULL;
struct skl_pipe_module *p_module = NULL;
p_module = devm_kzalloc(dev, sizeof(*p_module), GFP_KERNEL);
if (!p_module)
return -ENOMEM;
p_module->w = w;
list_add_tail(&p_module->node, &pipe->w_list);
snd_soc_dapm_widget_for_each_sink_path(w, p) {
if ((p->sink->priv == NULL)
&& (!is_skl_dsp_widget_type(w)))
continue;
if ((p->sink->priv != NULL) && p->connect
&& is_skl_dsp_widget_type(p->sink)) {
src_module = p->sink->priv;
if (pipe->ppl_id == src_module->pipe->ppl_id)
skl_tplg_alloc_pipe_widget(dev,
p->sink, pipe);
}
}
return 0;
}
/* /*
* some modules can have multiple params set from user control and * some modules can have multiple params set from user control and
* need to be set after module is initialized. If set_param flag is * need to be set after module is initialized. If set_param flag is
...@@ -514,8 +477,6 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) ...@@ -514,8 +477,6 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
if (!skl_is_pipe_mcps_avail(skl, mconfig)) if (!skl_is_pipe_mcps_avail(skl, mconfig))
return -ENOMEM; return -ENOMEM;
skl_tplg_alloc_pipe_mcps(skl, mconfig);
if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) { if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
ret = ctx->dsp->fw_ops.load_mod(ctx->dsp, ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
mconfig->id.module_id, mconfig->guid); mconfig->id.module_id, mconfig->guid);
...@@ -539,6 +500,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) ...@@ -539,6 +500,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
if (ret < 0) if (ret < 0)
return ret; return ret;
skl_tplg_alloc_pipe_mcps(skl, mconfig);
ret = skl_tplg_set_module_params(w, ctx); ret = skl_tplg_set_module_params(w, ctx);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -591,9 +553,6 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, ...@@ -591,9 +553,6 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
if (!skl_is_pipe_mem_avail(skl, mconfig)) if (!skl_is_pipe_mem_avail(skl, mconfig))
return -ENOMEM; return -ENOMEM;
skl_tplg_alloc_pipe_mem(skl, mconfig);
skl_tplg_alloc_pipe_mcps(skl, mconfig);
/* /*
* Create a list of modules for pipe. * Create a list of modules for pipe.
* This list contains modules from source to sink * This list contains modules from source to sink
...@@ -602,19 +561,8 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, ...@@ -602,19 +561,8 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
if (ret < 0) if (ret < 0)
return ret; return ret;
/* skl_tplg_alloc_pipe_mem(skl, mconfig);
* we create a w_list of all widgets in that pipe. This list is not skl_tplg_alloc_pipe_mcps(skl, mconfig);
* freed on PMD event as widgets within a pipe are static. This
* saves us cycles to get widgets in pipe every time.
*
* So if we have already initialized all the widgets of a pipeline
* we skip, so check for list_empty and create the list if empty
*/
if (list_empty(&s_pipe->w_list)) {
ret = skl_tplg_alloc_pipe_widget(ctx->dev, w, s_pipe);
if (ret < 0)
return ret;
}
/* Init all pipe modules from source to sink */ /* Init all pipe modules from source to sink */
ret = skl_tplg_init_pipe_modules(skl, s_pipe); ret = skl_tplg_init_pipe_modules(skl, s_pipe);
...@@ -949,13 +897,17 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, ...@@ -949,13 +897,17 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
struct skl_pipe *s_pipe = mconfig->pipe; struct skl_pipe *s_pipe = mconfig->pipe;
int ret = 0; int ret = 0;
if (s_pipe->state == SKL_PIPE_INVALID)
return -EINVAL;
skl_tplg_free_pipe_mcps(skl, mconfig); skl_tplg_free_pipe_mcps(skl, mconfig);
skl_tplg_free_pipe_mem(skl, mconfig); skl_tplg_free_pipe_mem(skl, mconfig);
list_for_each_entry(w_module, &s_pipe->w_list, node) { list_for_each_entry(w_module, &s_pipe->w_list, node) {
dst_module = w_module->w->priv; dst_module = w_module->w->priv;
skl_tplg_free_pipe_mcps(skl, dst_module); if (mconfig->m_state >= SKL_MODULE_INIT_DONE)
skl_tplg_free_pipe_mcps(skl, dst_module);
if (src_module == NULL) { if (src_module == NULL) {
src_module = dst_module; src_module = dst_module;
continue; continue;
...@@ -1162,6 +1114,39 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, ...@@ -1162,6 +1114,39 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
return 0; return 0;
} }
/*
* Fill the dma id for host and link. In case of passthrough
* pipeline, this will both host and link in the same
* pipeline, so need to copy the link and host based on dev_type
*/
static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg,
struct skl_pipe_params *params)
{
struct skl_pipe *pipe = mcfg->pipe;
if (pipe->passthru) {
switch (mcfg->dev_type) {
case SKL_DEVICE_HDALINK:
pipe->p_params->link_dma_id = params->link_dma_id;
break;
case SKL_DEVICE_HDAHOST:
pipe->p_params->host_dma_id = params->host_dma_id;
break;
default:
break;
}
pipe->p_params->s_fmt = params->s_fmt;
pipe->p_params->ch = params->ch;
pipe->p_params->s_freq = params->s_freq;
pipe->p_params->stream = params->stream;
} else {
memcpy(pipe->p_params, params, sizeof(*params));
}
}
/* /*
* The FE params are passed by hw_params of the DAI. * The FE params are passed by hw_params of the DAI.
* On hw_params, the params are stored in Gateway module of the FE and we * On hw_params, the params are stored in Gateway module of the FE and we
...@@ -1172,10 +1157,9 @@ int skl_tplg_update_pipe_params(struct device *dev, ...@@ -1172,10 +1157,9 @@ int skl_tplg_update_pipe_params(struct device *dev,
struct skl_module_cfg *mconfig, struct skl_module_cfg *mconfig,
struct skl_pipe_params *params) struct skl_pipe_params *params)
{ {
struct skl_pipe *pipe = mconfig->pipe;
struct skl_module_fmt *format = NULL; struct skl_module_fmt *format = NULL;
memcpy(pipe->p_params, params, sizeof(*params)); skl_tplg_fill_dma_id(mconfig, params);
if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) if (params->stream == SNDRV_PCM_STREAM_PLAYBACK)
format = &mconfig->in_fmt[0]; format = &mconfig->in_fmt[0];
...@@ -1362,12 +1346,11 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, ...@@ -1362,12 +1346,11 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
struct skl_module_cfg *mconfig, struct skl_module_cfg *mconfig,
struct skl_pipe_params *params) struct skl_pipe_params *params)
{ {
struct skl_pipe *pipe = mconfig->pipe;
struct nhlt_specific_cfg *cfg; struct nhlt_specific_cfg *cfg;
struct skl *skl = get_skl_ctx(dai->dev); struct skl *skl = get_skl_ctx(dai->dev);
int link_type = skl_tplg_be_link_type(mconfig->dev_type); int link_type = skl_tplg_be_link_type(mconfig->dev_type);
memcpy(pipe->p_params, params, sizeof(*params)); skl_tplg_fill_dma_id(mconfig, params);
if (link_type == NHLT_LINK_HDA) if (link_type == NHLT_LINK_HDA)
return 0; return 0;
...@@ -1558,6 +1541,55 @@ static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt, ...@@ -1558,6 +1541,55 @@ static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt,
} }
} }
static void skl_clear_pin_config(struct snd_soc_platform *platform,
struct snd_soc_dapm_widget *w)
{
int i;
struct skl_module_cfg *mconfig;
struct skl_pipe *pipe;
if (!strncmp(w->dapm->component->name, platform->component.name,
strlen(platform->component.name))) {
mconfig = w->priv;
pipe = mconfig->pipe;
for (i = 0; i < mconfig->max_in_queue; i++) {
mconfig->m_in_pin[i].in_use = false;
mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND;
}
for (i = 0; i < mconfig->max_out_queue; i++) {
mconfig->m_out_pin[i].in_use = false;
mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND;
}
pipe->state = SKL_PIPE_INVALID;
mconfig->m_state = SKL_MODULE_UNINIT;
}
}
void skl_cleanup_resources(struct skl *skl)
{
struct skl_sst *ctx = skl->skl_sst;
struct snd_soc_platform *soc_platform = skl->platform;
struct snd_soc_dapm_widget *w;
struct snd_soc_card *card;
if (soc_platform == NULL)
return;
card = soc_platform->component.card;
if (!card || !card->instantiated)
return;
skl->resource.mem = 0;
skl->resource.mcps = 0;
list_for_each_entry(w, &card->widgets, list) {
if (is_skl_dsp_widget_type(w) && (w->priv != NULL))
skl_clear_pin_config(soc_platform, w);
}
skl_clear_module_cnt(ctx->dsp);
}
/* /*
* Topology core widget load callback * Topology core widget load callback
* *
...@@ -1589,6 +1621,10 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, ...@@ -1589,6 +1621,10 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
w->priv = mconfig; w->priv = mconfig;
memcpy(&mconfig->guid, &dfw_config->uuid, 16); memcpy(&mconfig->guid, &dfw_config->uuid, 16);
ret = snd_skl_get_module_info(skl->skl_sst, mconfig->guid, dfw_config);
if (ret < 0)
return ret;
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;
...@@ -1738,6 +1774,60 @@ static struct snd_soc_tplg_ops skl_tplg_ops = { ...@@ -1738,6 +1774,60 @@ static struct snd_soc_tplg_ops skl_tplg_ops = {
.bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops),
}; };
/*
* A pipe can have multiple modules, each of them will be a DAPM widget as
* well. While managing a pipeline we need to get the list of all the
* widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list()
* helps to get the SKL type widgets in that pipeline
*/
static int skl_tplg_create_pipe_widget_list(struct snd_soc_platform *platform)
{
struct snd_soc_dapm_widget *w;
struct skl_module_cfg *mcfg = NULL;
struct skl_pipe_module *p_module = NULL;
struct skl_pipe *pipe;
list_for_each_entry(w, &platform->component.card->widgets, list) {
if (is_skl_dsp_widget_type(w) && w->priv != NULL) {
mcfg = w->priv;
pipe = mcfg->pipe;
p_module = devm_kzalloc(platform->dev,
sizeof(*p_module), GFP_KERNEL);
if (!p_module)
return -ENOMEM;
p_module->w = w;
list_add_tail(&p_module->node, &pipe->w_list);
}
}
return 0;
}
static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe)
{
struct skl_pipe_module *w_module;
struct snd_soc_dapm_widget *w;
struct skl_module_cfg *mconfig;
bool host_found = false, link_found = false;
list_for_each_entry(w_module, &pipe->w_list, node) {
w = w_module->w;
mconfig = w->priv;
if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
host_found = true;
else if (mconfig->dev_type != SKL_DEVICE_NONE)
link_found = true;
}
if (host_found && link_found)
pipe->passthru = true;
else
pipe->passthru = false;
}
/* This will be read from topology manifest, currently defined here */ /* This will be read from topology manifest, currently defined here */
#define SKL_MAX_MCPS 30000000 #define SKL_MAX_MCPS 30000000
#define SKL_FW_MAX_MEM 1000000 #define SKL_FW_MAX_MEM 1000000
...@@ -1751,6 +1841,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) ...@@ -1751,6 +1841,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
const struct firmware *fw; const struct firmware *fw;
struct hdac_bus *bus = ebus_to_hbus(ebus); struct hdac_bus *bus = ebus_to_hbus(ebus);
struct skl *skl = ebus_to_skl(ebus); struct skl *skl = ebus_to_skl(ebus);
struct skl_pipeline *ppl;
ret = request_firmware(&fw, skl->tplg_name, bus->dev); ret = request_firmware(&fw, skl->tplg_name, bus->dev);
if (ret < 0) { if (ret < 0) {
...@@ -1780,6 +1871,12 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) ...@@ -1780,6 +1871,12 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
skl->resource.max_mem = SKL_FW_MAX_MEM; skl->resource.max_mem = SKL_FW_MAX_MEM;
skl->tplg = fw; skl->tplg = fw;
ret = skl_tplg_create_pipe_widget_list(platform);
if (ret < 0)
return ret;
list_for_each_entry(ppl, &skl->ppl_list, node)
skl_tplg_set_pipe_type(skl, ppl->pipe);
return 0; return 0;
} }
...@@ -244,7 +244,8 @@ enum skl_pipe_state { ...@@ -244,7 +244,8 @@ enum skl_pipe_state {
SKL_PIPE_INVALID = 0, SKL_PIPE_INVALID = 0,
SKL_PIPE_CREATED = 1, SKL_PIPE_CREATED = 1,
SKL_PIPE_PAUSED = 2, SKL_PIPE_PAUSED = 2,
SKL_PIPE_STARTED = 3 SKL_PIPE_STARTED = 3,
SKL_PIPE_RESET = 4
}; };
struct skl_pipe_module { struct skl_pipe_module {
...@@ -270,6 +271,7 @@ struct skl_pipe { ...@@ -270,6 +271,7 @@ struct skl_pipe {
struct skl_pipe_params *p_params; struct skl_pipe_params *p_params;
enum skl_pipe_state state; enum skl_pipe_state state;
struct list_head w_list; struct list_head w_list;
bool passthru;
}; };
enum skl_module_state { enum skl_module_state {
...@@ -358,6 +360,8 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); ...@@ -358,6 +360,8 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
int skl_reset_pipe(struct skl_sst *ctx, struct skl_pipe *pipe);
int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config); int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config);
int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#include "skl-sst-dsp.h" #include "skl-sst-dsp.h"
#include "skl-sst-ipc.h" #include "skl-sst-ipc.h"
static struct skl_machine_pdata skl_dmic_data;
/* /*
* initialize the PCI registers * initialize the PCI registers
*/ */
...@@ -184,6 +186,7 @@ static int _skl_suspend(struct hdac_ext_bus *ebus) ...@@ -184,6 +186,7 @@ static int _skl_suspend(struct hdac_ext_bus *ebus)
{ {
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 pci_dev *pci = to_pci_dev(bus->dev);
int ret; int ret;
snd_hdac_ext_bus_link_power_down_all(ebus); snd_hdac_ext_bus_link_power_down_all(ebus);
...@@ -193,9 +196,12 @@ static int _skl_suspend(struct hdac_ext_bus *ebus) ...@@ -193,9 +196,12 @@ static int _skl_suspend(struct hdac_ext_bus *ebus)
return ret; return ret;
snd_hdac_bus_stop_chip(bus); snd_hdac_bus_stop_chip(bus);
update_pci_dword(pci, AZX_PCIREG_PGCTL,
AZX_PGCTL_LSRMD_MASK, AZX_PGCTL_LSRMD_MASK);
skl_enable_miscbdcge(bus->dev, false); skl_enable_miscbdcge(bus->dev, false);
snd_hdac_bus_enter_link_reset(bus); snd_hdac_bus_enter_link_reset(bus);
skl_enable_miscbdcge(bus->dev, true); skl_enable_miscbdcge(bus->dev, true);
skl_cleanup_resources(skl);
return 0; return 0;
} }
...@@ -242,6 +248,7 @@ static int skl_suspend(struct device *dev) ...@@ -242,6 +248,7 @@ static int skl_suspend(struct device *dev)
ret = _skl_suspend(ebus); ret = _skl_suspend(ebus);
if (ret < 0) if (ret < 0)
return ret; return ret;
skl->skl_sst->fw_loaded = false;
} }
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
...@@ -397,6 +404,10 @@ static int skl_machine_device_register(struct skl *skl, void *driver_data) ...@@ -397,6 +404,10 @@ static int skl_machine_device_register(struct skl *skl, void *driver_data)
platform_device_put(pdev); platform_device_put(pdev);
return -EIO; return -EIO;
} }
if (mach->pdata)
dev_set_drvdata(&pdev->dev, mach->pdata);
skl->i2s_dev = pdev; skl->i2s_dev = pdev;
return 0; return 0;
...@@ -657,6 +668,8 @@ static int skl_probe(struct pci_dev *pci, ...@@ -657,6 +668,8 @@ static int skl_probe(struct pci_dev *pci,
skl->pci_id = pci->device; skl->pci_id = pci->device;
device_disable_async_suspend(bus->dev);
skl->nhlt = skl_nhlt_init(bus->dev); skl->nhlt = skl_nhlt_init(bus->dev);
if (skl->nhlt == NULL) if (skl->nhlt == NULL)
...@@ -666,6 +679,8 @@ static int skl_probe(struct pci_dev *pci, ...@@ -666,6 +679,8 @@ static int skl_probe(struct pci_dev *pci,
pci_set_drvdata(skl->pci, ebus); pci_set_drvdata(skl->pci, ebus);
skl_dmic_data.dmic_num = skl_get_dmic_geo(skl);
/* check if dsp is there */ /* check if dsp is there */
if (ebus->ppcap) { if (ebus->ppcap) {
err = skl_machine_device_register(skl, err = skl_machine_device_register(skl,
...@@ -713,7 +728,7 @@ static int skl_probe(struct pci_dev *pci, ...@@ -713,7 +728,7 @@ static int skl_probe(struct pci_dev *pci,
list_for_each_entry(hlink, &ebus->hlink_list, list) list_for_each_entry(hlink, &ebus->hlink_list, list)
snd_hdac_ext_bus_link_put(ebus, hlink); 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);
...@@ -766,8 +781,7 @@ static void skl_remove(struct pci_dev *pci) ...@@ -766,8 +781,7 @@ static void skl_remove(struct pci_dev *pci)
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);
if (skl->tplg) release_firmware(skl->tplg);
release_firmware(skl->tplg);
if (pci_dev_run_wake(pci)) if (pci_dev_run_wake(pci))
pm_runtime_get_noresume(&pci->dev); pm_runtime_get_noresume(&pci->dev);
...@@ -786,15 +800,23 @@ static void skl_remove(struct pci_dev *pci) ...@@ -786,15 +800,23 @@ static void skl_remove(struct pci_dev *pci)
static struct sst_acpi_mach sst_skl_devdata[] = { static struct sst_acpi_mach sst_skl_devdata[] = {
{ "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL }, { "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL },
{ "INT343B", "skl_nau88l25_ssm4567_i2s", "intel/dsp_fw_release.bin", { "INT343B", "skl_n88l25_s4567", "intel/dsp_fw_release.bin",
NULL, NULL, NULL }, NULL, NULL, &skl_dmic_data },
{ "MX98357A", "skl_nau88l25_max98357a_i2s", "intel/dsp_fw_release.bin", { "MX98357A", "skl_n88l25_m98357a", "intel/dsp_fw_release.bin",
NULL, NULL, NULL }, NULL, NULL, &skl_dmic_data },
{} {}
}; };
static struct sst_acpi_mach sst_bxtp_devdata[] = { static struct sst_acpi_mach sst_bxtp_devdata[] = {
{ "INT343A", "bxt_alc298s_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL }, { "INT343A", "bxt_alc298s_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL },
{ "DLGS7219", "bxt_da7219_max98357a_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL },
};
static struct sst_acpi_mach sst_kbl_devdata[] = {
{ "INT343A", "kbl_alc286s_i2s", "intel/dsp_fw_kbl.bin", NULL, NULL, NULL },
{ "INT343B", "kbl_n88l25_s4567", "intel/dsp_fw_kbl.bin", NULL, NULL, &skl_dmic_data },
{ "MX98357A", "kbl_n88l25_m98357a", "intel/dsp_fw_kbl.bin", NULL, NULL, &skl_dmic_data },
{}
}; };
/* PCI IDs */ /* PCI IDs */
...@@ -805,6 +827,9 @@ static const struct pci_device_id skl_ids[] = { ...@@ -805,6 +827,9 @@ static const struct pci_device_id skl_ids[] = {
/* BXT-P */ /* BXT-P */
{ PCI_DEVICE(0x8086, 0x5a98), { PCI_DEVICE(0x8086, 0x5a98),
.driver_data = (unsigned long)&sst_bxtp_devdata}, .driver_data = (unsigned long)&sst_bxtp_devdata},
/* KBL */
{ PCI_DEVICE(0x8086, 0x9D71),
.driver_data = (unsigned long)&sst_kbl_devdata},
{ 0, } { 0, }
}; };
MODULE_DEVICE_TABLE(pci, skl_ids); MODULE_DEVICE_TABLE(pci, skl_ids);
......
...@@ -48,6 +48,8 @@ ...@@ -48,6 +48,8 @@
#define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094 #define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094
#define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20 #define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20
#define AZX_PCIREG_PGCTL 0x44
#define AZX_PGCTL_LSRMD_MASK (1 << 4)
#define AZX_PCIREG_CGCTL 0x48 #define AZX_PCIREG_CGCTL 0x48
#define AZX_CGCTL_MISCBDCGE_MASK (1 << 6) #define AZX_CGCTL_MISCBDCGE_MASK (1 << 6)
...@@ -65,6 +67,7 @@ struct skl { ...@@ -65,6 +67,7 @@ struct skl {
unsigned int init_failed:1; /* delayed init failed */ unsigned int init_failed:1; /* delayed init failed */
struct platform_device *dmic_dev; struct platform_device *dmic_dev;
struct platform_device *i2s_dev; struct platform_device *i2s_dev;
struct snd_soc_platform *platform;
struct nhlt_acpi_table *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 */
...@@ -90,6 +93,11 @@ struct skl_dma_params { ...@@ -90,6 +93,11 @@ struct skl_dma_params {
u8 stream_tag; u8 stream_tag;
}; };
/* to pass dmic data */
struct skl_machine_pdata {
u32 dmic_num;
};
struct skl_dsp_ops { struct skl_dsp_ops {
int id; int id;
struct skl_dsp_loader_ops (*loader_ops)(void); struct skl_dsp_loader_ops (*loader_ops)(void);
...@@ -108,9 +116,11 @@ void skl_nhlt_free(struct nhlt_acpi_table *addr); ...@@ -108,9 +116,11 @@ 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);
int skl_get_dmic_geo(struct skl *skl);
int skl_nhlt_update_topology_bin(struct skl *skl); int skl_nhlt_update_topology_bin(struct skl *skl);
int skl_init_dsp(struct skl *skl); int skl_init_dsp(struct skl *skl);
int skl_free_dsp(struct skl *skl); int skl_free_dsp(struct skl *skl);
int skl_suspend_dsp(struct skl *skl); int skl_suspend_dsp(struct skl *skl);
int skl_resume_dsp(struct skl *skl); int skl_resume_dsp(struct skl *skl);
void skl_cleanup_resources(struct skl *skl);
#endif /* __SOUND_SOC_SKL_H */ #endif /* __SOUND_SOC_SKL_H */
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