Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
This commit is contained in:
Коммит
44d624622e
|
@ -1124,8 +1124,10 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll)
|
|||
}
|
||||
hdac_hdmi_parse_eld(edev, pin);
|
||||
|
||||
print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET,
|
||||
pin->eld.eld_buffer, pin->eld.eld_size);
|
||||
print_hex_dump_debug("ELD: ",
|
||||
DUMP_PREFIX_OFFSET, 16, 1,
|
||||
pin->eld.eld_buffer, pin->eld.eld_size,
|
||||
true);
|
||||
} else {
|
||||
pin->eld.monitor_present = false;
|
||||
pin->eld.eld_valid = false;
|
||||
|
@ -1816,6 +1818,7 @@ static const struct dev_pm_ops hdac_hdmi_pm = {
|
|||
static const struct hda_device_id hdmi_list[] = {
|
||||
HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake 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[] = {
|
|||
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
|
|||
help
|
||||
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
|
||||
Say Y if you have such a device
|
||||
Say Y if you have such a device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SST_MFLD_PLATFORM
|
||||
|
@ -25,7 +25,6 @@ config SND_SST_IPC_ACPI
|
|||
tristate
|
||||
select SND_SST_IPC
|
||||
select SND_SOC_INTEL_SST
|
||||
depends on ACPI
|
||||
|
||||
config SND_SOC_INTEL_SST
|
||||
tristate
|
||||
|
@ -33,6 +32,12 @@ config SND_SOC_INTEL_SST
|
|||
select SND_SOC_INTEL_SST_MATCH if ACPI
|
||||
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
|
||||
tristate
|
||||
|
||||
|
@ -48,14 +53,31 @@ config SND_SOC_INTEL_BAYTRAIL
|
|||
config SND_SOC_INTEL_HASWELL_MACH
|
||||
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
|
||||
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_FIRMWARE
|
||||
select SND_SOC_INTEL_HASWELL
|
||||
select SND_SOC_RT5640
|
||||
help
|
||||
This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell
|
||||
Ultrabook platforms.
|
||||
Say Y if you have such a device
|
||||
Say Y if you have such a device.
|
||||
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
|
||||
|
@ -70,26 +92,28 @@ config SND_SOC_INTEL_BXT_RT298_MACH
|
|||
help
|
||||
This adds support for ASoC machine driver for Broxton platforms
|
||||
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".
|
||||
|
||||
config SND_SOC_INTEL_BYT_RT5640_MACH
|
||||
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
|
||||
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_FIRMWARE
|
||||
select SND_SOC_INTEL_BAYTRAIL
|
||||
select SND_SOC_RT5640
|
||||
help
|
||||
This adds audio driver for Intel Baytrail platform based boards
|
||||
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
|
||||
tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
|
||||
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_FIRMWARE
|
||||
select SND_SOC_INTEL_BAYTRAIL
|
||||
select SND_SOC_MAX98090
|
||||
help
|
||||
|
@ -100,19 +124,20 @@ config SND_SOC_INTEL_BROADWELL_MACH
|
|||
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
|
||||
depends on X86_INTEL_LPSS && I2C && DW_DMAC && \
|
||||
I2C_DESIGNWARE_PLATFORM
|
||||
depends on DW_DMAC_CORE=y
|
||||
depends on DW_DMAC_CORE
|
||||
select SND_SOC_INTEL_SST
|
||||
select SND_SOC_INTEL_SST_FIRMWARE
|
||||
select SND_SOC_INTEL_HASWELL
|
||||
select SND_SOC_RT286
|
||||
help
|
||||
This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell
|
||||
Ultrabook platforms.
|
||||
Say Y if you have such a device
|
||||
Say Y if you have such a device.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_INTEL_BYTCR_RT5640_MACH
|
||||
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_SST_MFLD_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
|
@ -120,12 +145,12 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH
|
|||
help
|
||||
This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
|
||||
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".
|
||||
|
||||
config SND_SOC_INTEL_BYTCR_RT5651_MACH
|
||||
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_SST_MFLD_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
|
@ -133,12 +158,12 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH
|
|||
help
|
||||
This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
|
||||
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".
|
||||
|
||||
config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
|
||||
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_SST_MFLD_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
|
@ -146,12 +171,12 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
|
|||
help
|
||||
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
|
||||
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".
|
||||
|
||||
config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
|
||||
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_SST_MFLD_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
|
@ -163,7 +188,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
|
|||
|
||||
config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
|
||||
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_TS3A227E
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
|
@ -192,7 +217,7 @@ config SND_SOC_INTEL_SKL_RT286_MACH
|
|||
help
|
||||
This adds support for ASoC machine driver for Skylake platforms
|
||||
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".
|
||||
|
||||
config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
|
||||
|
@ -207,7 +232,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
|
|||
help
|
||||
This adds support for ASoC Onboard Codec I2S machine driver. This will
|
||||
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".
|
||||
|
||||
config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
|
||||
|
@ -222,5 +247,5 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
|
|||
help
|
||||
This adds support for ASoC Onboard Codec I2S machine driver. This will
|
||||
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".
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/firmware.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <asm/platform_sst_audio.h>
|
||||
#include <sound/core.h>
|
||||
|
@ -237,6 +238,9 @@ static int sst_acpi_probe(struct platform_device *pdev)
|
|||
dev_err(dev, "No matching machine driver found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (mach->machine_quirk)
|
||||
mach = mach->machine_quirk(mach);
|
||||
|
||||
pdata = mach->pdata;
|
||||
|
||||
ret = kstrtouint(id->id, 16, &dev_id);
|
||||
|
@ -320,6 +324,44 @@ static int sst_acpi_remove(struct platform_device *pdev)
|
|||
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[] = {
|
||||
{"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL,
|
||||
&byt_rvp_platform_data },
|
||||
|
@ -343,7 +385,7 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
|
|||
{"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
|
||||
&chv_platform_data },
|
||||
/* 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 },
|
||||
|
||||
{},
|
||||
|
|
|
@ -2,6 +2,7 @@ snd-soc-sst-haswell-objs := haswell.o
|
|||
snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
|
||||
snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
|
||||
snd-soc-sst-broadwell-objs := broadwell.o
|
||||
snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o
|
||||
snd-soc-sst-bxt-rt298-objs := bxt_rt298.o
|
||||
snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
|
||||
snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o
|
||||
|
@ -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_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BXT_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_BROADWELL_MACH) += snd-soc-sst-broadwell.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
|
||||
|
|
|
@ -0,0 +1,460 @@
|
|||
/*
|
||||
* 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 {
|
|||
BXT_DPCM_AUDIO_PB = 0,
|
||||
BXT_DPCM_AUDIO_CP,
|
||||
BXT_DPCM_AUDIO_REF_CP,
|
||||
BXT_DPCM_AUDIO_DMIC_CP,
|
||||
BXT_DPCM_AUDIO_HDMI1_PB,
|
||||
BXT_DPCM_AUDIO_HDMI2_PB,
|
||||
BXT_DPCM_AUDIO_HDMI3_PB,
|
||||
|
@ -88,6 +89,7 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = {
|
|||
/* CODEC BE connections */
|
||||
{ "AIF1 Playback", NULL, "ssp5 Tx"},
|
||||
{ "ssp5 Tx", NULL, "codec0_out"},
|
||||
{ "ssp5 Tx", NULL, "codec1_out"},
|
||||
|
||||
{ "codec0_in", NULL, "ssp5 Rx" },
|
||||
{ "ssp5 Rx", NULL, "AIF1 Capture" },
|
||||
|
@ -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)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
|
@ -118,6 +131,9 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd)
|
|||
return ret;
|
||||
|
||||
rt298_mic_detect(codec, &broxton_headset);
|
||||
|
||||
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -169,6 +185,89 @@ static struct snd_soc_ops broxton_rt298_ops = {
|
|||
.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 */
|
||||
static struct snd_soc_dai_link broxton_rt298_dais[] = {
|
||||
/* Front End DAI links */
|
||||
|
@ -182,8 +281,10 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
|
|||
.dynamic = 1,
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.init = broxton_rt298_fe_init,
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
|
||||
.dpcm_playback = 1,
|
||||
.ops = &broxton_rt286_fe_ops,
|
||||
},
|
||||
[BXT_DPCM_AUDIO_CP]
|
||||
{
|
||||
|
@ -197,6 +298,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
|
|||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
|
||||
.dpcm_capture = 1,
|
||||
.ops = &broxton_rt286_fe_ops,
|
||||
},
|
||||
[BXT_DPCM_AUDIO_REF_CP]
|
||||
{
|
||||
|
@ -211,6 +313,20 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
|
|||
.nonatomic = 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]
|
||||
{
|
||||
.name = "Bxt HDMI Port1",
|
||||
|
@ -276,6 +392,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = {
|
|||
.codec_name = "dmic-codec",
|
||||
.codec_dai_name = "dmic-hifi",
|
||||
.platform_name = "0000:00:0e.0",
|
||||
.be_hw_params_fixup = broxton_dmic_fixup,
|
||||
.ignore_suspend = 1,
|
||||
.dpcm_capture = 1,
|
||||
.no_pcm = 1,
|
||||
|
@ -341,6 +458,7 @@ static struct platform_driver broxton_audio = {
|
|||
.probe = broxton_audio_probe,
|
||||
.driver = {
|
||||
.name = "bxt_alc298s_i2s",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(broxton_audio)
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <sound/jack.h>
|
||||
#include "../../codecs/rt5645.h"
|
||||
#include "../atom/sst-atom-controls.h"
|
||||
#include "../common/sst-acpi.h"
|
||||
|
||||
#define CHT_PLAT_CLK_3_HZ 19200000
|
||||
#define CHT_CODEC_DAI "rt5645-aif1"
|
||||
|
@ -340,10 +341,13 @@ static struct snd_soc_card snd_soc_card_chtrt5650 = {
|
|||
};
|
||||
|
||||
static struct cht_acpi_card snd_soc_cards[] = {
|
||||
{"10EC5640", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
|
||||
{"10EC5645", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645},
|
||||
{"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)
|
||||
{
|
||||
int ret_val = 0;
|
||||
|
@ -351,6 +355,9 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
|||
struct cht_mc_private *drv;
|
||||
struct snd_soc_card *card = snd_soc_cards[0].soc_card;
|
||||
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);
|
||||
if (!drv)
|
||||
|
@ -366,12 +373,23 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
card->dev = &pdev->dev;
|
||||
mach = card->dev->platform_data;
|
||||
sprintf(codec_name, "i2c-%s:00", drv->acpi_card->codec_id);
|
||||
|
||||
/* set correct codec name */
|
||||
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);
|
||||
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);
|
||||
ret_val = devm_snd_soc_register_card(&pdev->dev, card);
|
||||
|
|
|
@ -23,12 +23,15 @@
|
|||
#include <sound/soc.h>
|
||||
#include "../../codecs/nau8825.h"
|
||||
#include "../../codecs/hdac_hdmi.h"
|
||||
#include "../skylake/skl.h"
|
||||
|
||||
#define SKL_NUVOTON_CODEC_DAI "nau8825-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_card skylake_audio_card;
|
||||
static const struct snd_pcm_hw_constraint_list *dmic_constraints;
|
||||
|
||||
struct skl_hdmi_pcm {
|
||||
struct list_head head;
|
||||
|
@ -339,7 +342,7 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
|
|||
struct snd_interval *channels = hw_param_interval(params,
|
||||
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;
|
||||
else
|
||||
channels->min = channels->max = 4;
|
||||
|
@ -357,13 +360,23 @@ static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
|
|||
.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)
|
||||
{
|
||||
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,
|
||||
&constraints_dmic_channels);
|
||||
dmic_constraints);
|
||||
|
||||
return snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
|
||||
|
@ -382,8 +395,22 @@ static struct snd_pcm_hw_constraint_list constraints_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)
|
||||
{
|
||||
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,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_16000);
|
||||
|
@ -610,6 +637,7 @@ static struct snd_soc_card skylake_audio_card = {
|
|||
static int skylake_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct skl_nau8825_private *ctx;
|
||||
struct skl_machine_pdata *pdata;
|
||||
|
||||
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
|
||||
if (!ctx)
|
||||
|
@ -620,15 +648,27 @@ static int skylake_audio_probe(struct platform_device *pdev)
|
|||
skylake_audio_card.dev = &pdev->dev;
|
||||
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);
|
||||
}
|
||||
|
||||
static const struct platform_device_id skl_board_ids[] = {
|
||||
{ .name = "skl_n88l25_m98357a" },
|
||||
{ .name = "kbl_n88l25_m98357a" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver skylake_audio = {
|
||||
.probe = skylake_audio_probe,
|
||||
.driver = {
|
||||
.name = "skl_nau88l25_max98357a_i2s",
|
||||
.name = "skl_n88l25_m98357a",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.id_table = skl_board_ids,
|
||||
};
|
||||
|
||||
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_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com");
|
||||
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 @@
|
|||
#include <sound/pcm_params.h>
|
||||
#include "../../codecs/nau8825.h"
|
||||
#include "../../codecs/hdac_hdmi.h"
|
||||
#include "../skylake/skl.h"
|
||||
|
||||
#define SKL_NUVOTON_CODEC_DAI "nau8825-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_card skylake_audio_card;
|
||||
static const struct snd_pcm_hw_constraint_list *dmic_constraints;
|
||||
|
||||
struct skl_hdmi_pcm {
|
||||
struct list_head head;
|
||||
|
@ -367,7 +370,7 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
|
|||
{
|
||||
struct snd_interval *channels = hw_param_interval(params,
|
||||
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;
|
||||
else
|
||||
channels->min = channels->max = 4;
|
||||
|
@ -405,13 +408,23 @@ static struct snd_pcm_hw_constraint_list constraints_dmic_channels = {
|
|||
.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)
|
||||
{
|
||||
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,
|
||||
&constraints_dmic_channels);
|
||||
dmic_constraints);
|
||||
|
||||
return snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
|
||||
|
@ -430,8 +443,22 @@ static struct snd_pcm_hw_constraint_list constraints_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)
|
||||
{
|
||||
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,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_16000);
|
||||
|
@ -662,6 +689,7 @@ static struct snd_soc_card skylake_audio_card = {
|
|||
static int skylake_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct skl_nau88125_private *ctx;
|
||||
struct skl_machine_pdata *pdata;
|
||||
|
||||
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
|
||||
if (!ctx)
|
||||
|
@ -672,15 +700,27 @@ static int skylake_audio_probe(struct platform_device *pdev)
|
|||
skylake_audio_card.dev = &pdev->dev;
|
||||
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);
|
||||
}
|
||||
|
||||
static const struct platform_device_id skl_board_ids[] = {
|
||||
{ .name = "skl_n88l25_s4567" },
|
||||
{ .name = "kbl_n88l25_s4567" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver skylake_audio = {
|
||||
.probe = skylake_audio_probe,
|
||||
.driver = {
|
||||
.name = "skl_nau88l25_ssm4567_i2s",
|
||||
.name = "skl_n88l25_s4567",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.id_table = skl_board_ids,
|
||||
};
|
||||
|
||||
module_platform_driver(skylake_audio)
|
||||
|
@ -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_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode");
|
||||
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)
|
|||
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 = {
|
||||
.probe = skylake_audio_probe,
|
||||
.driver = {
|
||||
.name = "skl_alc286s_i2s",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.id_table = skl_board_ids,
|
||||
|
||||
};
|
||||
|
||||
module_platform_driver(skylake_audio)
|
||||
|
@ -520,3 +528,4 @@ MODULE_AUTHOR("Omair Mohammed Abdullah <omair.m.abdullah@intel.com>");
|
|||
MODULE_DESCRIPTION("Intel SST Audio for Skylake");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:skl_alc286s_i2s");
|
||||
MODULE_ALIAS("platform:kbl_alc286s_i2s");
|
||||
|
|
|
@ -2,9 +2,9 @@ snd-soc-sst-dsp-objs := sst-dsp.o
|
|||
snd-soc-sst-acpi-objs := sst-acpi.o
|
||||
snd-soc-sst-match-objs := sst-match-acpi.o
|
||||
snd-soc-sst-ipc-objs := sst-ipc.o
|
||||
|
||||
snd-soc-sst-dsp-$(CONFIG_DW_DMAC_CORE) += sst-firmware.o
|
||||
snd-soc-sst-firmware-objs := 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_ACPI) += snd-soc-sst-acpi.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 @@
|
|||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]);
|
||||
#else
|
||||
inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
|
||||
static inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN])
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
@ -40,6 +40,6 @@ struct sst_acpi_mach {
|
|||
|
||||
/* board name */
|
||||
const char *board;
|
||||
void (*machine_quirk)(void);
|
||||
struct sst_acpi_mach * (*machine_quirk)(void *arg);
|
||||
void *pdata;
|
||||
};
|
||||
|
|
|
@ -383,10 +383,6 @@ struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
|
|||
u32 index, void *private);
|
||||
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,
|
||||
enum sst_mem_type type);
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
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");
|
||||
ret = time < timeout ? 0 : -ETIME;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
#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_AUTHOR("Liam Girdwood");
|
||||
MODULE_DESCRIPTION("Intel SST Core");
|
||||
|
|
|
@ -216,7 +216,7 @@ struct sst_pdata {
|
|||
void *dsp;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DW_DMAC_CORE
|
||||
#if IS_ENABLED(CONFIG_DW_DMAC_CORE)
|
||||
/* Initialization */
|
||||
struct sst_dsp *sst_dsp_new(struct device *dev,
|
||||
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,
|
|||
}
|
||||
}
|
||||
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)
|
|||
mutex_lock(&pcm_data->mutex);
|
||||
pm_runtime_get_sync(pdata->dev);
|
||||
|
||||
snd_soc_pcm_set_drvdata(rtd, pcm_data);
|
||||
pcm_data->substream = substream;
|
||||
|
||||
snd_soc_set_runtime_hwparams(substream, &hsw_pcm_hardware);
|
||||
|
|
|
@ -5,6 +5,6 @@ obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
|
|||
|
||||
# Skylake IPC Support
|
||||
snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \
|
||||
skl-sst.o bxt-sst.o
|
||||
skl-sst.o bxt-sst.o skl-sst-utils.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o
|
||||
|
|
|
@ -37,11 +37,19 @@
|
|||
|
||||
#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)
|
||||
{
|
||||
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,
|
||||
const void *fwdata, u32 fwsize)
|
||||
{
|
||||
|
@ -49,7 +57,7 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
|
|||
u32 reg;
|
||||
|
||||
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",
|
||||
stream_tag);
|
||||
return stream_tag;
|
||||
|
@ -58,17 +66,27 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
|
|||
ctx->dsp_ops.stream_tag = stream_tag;
|
||||
memcpy(ctx->dmab.area, fwdata, fwsize);
|
||||
|
||||
/* Purge FW request */
|
||||
sst_dsp_shim_write(ctx, SKL_ADSP_REG_HIPCI, SKL_ADSP_REG_HIPCI_BUSY |
|
||||
BXT_IPC_PURGE_FW | (stream_tag - 1));
|
||||
|
||||
ret = skl_dsp_enable_core(ctx);
|
||||
/* 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, "Boot dsp core failed ret: %d\n", ret);
|
||||
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 |
|
||||
(BXT_IPC_PURGE_FW | ((stream_tag - 1) << 9)));
|
||||
|
||||
/* Step 3: Unset core0 reset state & unstall/run core0 */
|
||||
ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Start dsp core failed ret: %d\n", ret);
|
||||
ret = -EIO;
|
||||
goto base_fw_load_failed;
|
||||
}
|
||||
|
||||
/* Step 4: Wait for DONE Bit */
|
||||
for (i = BXT_INIT_TIMEOUT; i > 0; --i) {
|
||||
reg = sst_dsp_shim_read(ctx, SKL_ADSP_REG_HIPCIE);
|
||||
|
||||
|
@ -88,10 +106,18 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
|
|||
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_op_int_enable(ctx);
|
||||
|
||||
/* Step 7: Wait for ROM init */
|
||||
for (i = BXT_INIT_TIMEOUT; i > 0; --i) {
|
||||
if (SKL_FW_INIT ==
|
||||
(sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS) &
|
||||
|
@ -112,7 +138,8 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx,
|
|||
|
||||
base_fw_load_failed:
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -130,23 +157,41 @@ static int sst_transfer_fw_host_dma(struct sst_dsp *ctx)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000
|
||||
|
||||
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;
|
||||
int ret;
|
||||
|
||||
ret = request_firmware(&fw, ctx->fw_name, ctx->dev);
|
||||
ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Request firmware failed %d\n", ret);
|
||||
goto sst_load_base_firmware_failed;
|
||||
}
|
||||
|
||||
ret = sst_bxt_prepare_fw(ctx, fw->data, fw->size);
|
||||
/* 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 */
|
||||
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) {
|
||||
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);
|
||||
goto sst_load_base_firmware_failed;
|
||||
}
|
||||
|
@ -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_FW_STATUS));
|
||||
|
||||
skl_dsp_disable_core(ctx);
|
||||
skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
|
||||
} else {
|
||||
dev_dbg(ctx->dev, "Firmware download successful\n");
|
||||
ret = wait_event_timeout(skl->boot_wait, skl->boot_complete,
|
||||
msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
|
||||
if (ret == 0) {
|
||||
dev_err(ctx->dev, "DSP boot fail, FW Ready timeout\n");
|
||||
skl_dsp_disable_core(ctx);
|
||||
skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
|
||||
ret = -EIO;
|
||||
} else {
|
||||
skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
|
||||
ret = 0;
|
||||
skl->fw_loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
sst_load_base_firmware_failed:
|
||||
release_firmware(fw);
|
||||
release_firmware(ctx->fw);
|
||||
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;
|
||||
int ret;
|
||||
struct skl_ipc_dxstate_info dx;
|
||||
unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
|
||||
|
||||
if (skl->fw_loaded == false) {
|
||||
skl->boot_complete = false;
|
||||
|
||||
ret = skl_dsp_enable_core(ctx);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "enable dsp core failed ret: %d\n", ret);
|
||||
ret = bxt_load_base_firmware(ctx);
|
||||
if (ret < 0)
|
||||
dev_err(ctx->dev, "reload fw failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* enable interrupt */
|
||||
/* If core 0 is being turned on, turn on core 1 as well */
|
||||
if (core_id == SKL_DSP_CORE0_ID)
|
||||
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);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
if (core_id == SKL_DSP_CORE0_ID) {
|
||||
ret = wait_event_timeout(skl->boot_wait,
|
||||
skl->boot_complete,
|
||||
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, "ipc: error DSP boot timeout\n");
|
||||
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));
|
||||
return -EIO;
|
||||
dev_err(ctx->dev, "Failed to set core0 to D0 state\n");
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
|
||||
/* 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->cores.state[core_id] = SKL_DSP_RUNNING;
|
||||
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_sst *skl = ctx->thread_context;
|
||||
int ret = 0;
|
||||
unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
|
||||
|
||||
if (!is_skl_dsp_running(ctx))
|
||||
return ret;
|
||||
|
||||
dx.core_mask = SKL_DSP_CORE0_MASK;
|
||||
dx.core_mask = core_mask;
|
||||
dx.dx_mask = SKL_IPC_D3_MASK;
|
||||
|
||||
ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID,
|
||||
SKL_BASE_FW_MODULE_ID, &dx);
|
||||
dev_dbg(ctx->dev, "core mask=%x dx_mask=%x\n",
|
||||
dx.core_mask, dx.dx_mask);
|
||||
|
||||
ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID,
|
||||
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, core_mask);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Failed to set DSP to D3 state: %d\n", ret);
|
||||
dev_err(ctx->dev, "Failed to disable core %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = skl_dsp_disable_core(ctx);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "disbale dsp core failed: %d\n", ret);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
skl_dsp_set_state_locked(ctx, SKL_DSP_RESET);
|
||||
skl->cores.state[core_id] = SKL_DSP_RESET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -274,6 +371,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
|||
|
||||
skl->dev = dev;
|
||||
skl_dev.thread_context = skl;
|
||||
INIT_LIST_HEAD(&skl->uuid_list);
|
||||
|
||||
skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq);
|
||||
if (!skl->dsp) {
|
||||
|
@ -296,6 +394,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
skl->cores.count = 2;
|
||||
skl->boot_complete = false;
|
||||
init_waitqueue_head(&skl->boot_wait);
|
||||
|
||||
|
@ -305,6 +404,8 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
|||
return ret;
|
||||
}
|
||||
|
||||
skl_dsp_init_core_state(sst);
|
||||
|
||||
if (dsp)
|
||||
*dsp = skl;
|
||||
|
||||
|
@ -315,6 +416,7 @@ EXPORT_SYMBOL_GPL(bxt_sst_dsp_init);
|
|||
|
||||
void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
|
||||
{
|
||||
skl_freeup_uuid_list(ctx);
|
||||
skl_ipc_free(&ctx->ipc);
|
||||
ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
|
||||
|
||||
|
|
|
@ -205,6 +205,12 @@ static const struct skl_dsp_ops dsp_ops[] = {
|
|||
.init = skl_sst_dsp_init,
|
||||
.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,
|
||||
.loader_ops = bxt_get_loader_ops,
|
||||
|
@ -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",
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
/* 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) {
|
||||
ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED);
|
||||
if (ret < 0) {
|
||||
|
@ -1055,17 +1061,19 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
|
|||
}
|
||||
|
||||
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 (ret < 0)
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Failed to delete pipeline\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pipe->state = SKL_PIPE_INVALID;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1125,7 +1133,30 @@ int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
*/
|
||||
#include <linux/pci.h>
|
||||
#include "skl.h"
|
||||
|
||||
/* Unique identification for getting NHLT blobs */
|
||||
|
@ -149,6 +150,45 @@ struct nhlt_specific_cfg
|
|||
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)
|
||||
{
|
||||
char *s = skl->tplg_name;
|
||||
|
|
|
@ -103,4 +103,26 @@ struct nhlt_resource_desc {
|
|||
u64 length;
|
||||
} __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
|
||||
|
|
|
@ -227,16 +227,25 @@ static int skl_pcm_prepare(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
|
||||
struct skl *skl = get_skl_ctx(dai->dev);
|
||||
unsigned int format_val;
|
||||
int err;
|
||||
struct skl_module_cfg *mconfig;
|
||||
|
||||
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);
|
||||
dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n",
|
||||
hdac_stream(stream)->stream_tag, format_val);
|
||||
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);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -521,6 +530,8 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
|
|||
struct skl_dma_params *dma_params;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
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 *)
|
||||
snd_soc_dai_get_dma_data(codec_dai, substream);
|
||||
|
@ -535,6 +546,12 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream,
|
|||
|
||||
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_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,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* calculate runtime delay from LPIB */
|
||||
static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus,
|
||||
struct hdac_ext_stream *sstream,
|
||||
unsigned int pos)
|
||||
static snd_pcm_uframes_t skl_platform_pcm_pointer
|
||||
(struct snd_pcm_substream *substream)
|
||||
{
|
||||
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 snd_pcm_substream *substream = hstr->substream;
|
||||
struct hdac_ext_bus *ebus;
|
||||
struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream);
|
||||
unsigned int pos;
|
||||
int delay;
|
||||
|
||||
/* use the position buffer as default */
|
||||
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,
|
|||
if (pos >= hdac_stream(hstream)->bufsize)
|
||||
pos = 0;
|
||||
|
||||
if (substream->runtime) {
|
||||
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));
|
||||
return bytes_to_frames(substream->runtime, pos);
|
||||
}
|
||||
|
||||
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)
|
|||
static int skl_platform_soc_probe(struct snd_soc_platform *platform)
|
||||
{
|
||||
struct hdac_ext_bus *ebus = dev_get_drvdata(platform->dev);
|
||||
struct skl *skl = ebus_to_skl(ebus);
|
||||
int ret;
|
||||
|
||||
if (ebus->ppcap)
|
||||
return skl_tplg_init(platform, ebus);
|
||||
if (ebus->ppcap) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -34,33 +34,84 @@ void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state)
|
|||
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;
|
||||
|
||||
/* update bits */
|
||||
sst_dsp_shim_update_bits_unlocked(ctx,
|
||||
SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK,
|
||||
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK));
|
||||
SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK(core_mask),
|
||||
SKL_ADSPCS_CRST_MASK(core_mask));
|
||||
|
||||
/* poll with timeout to check if operation successful */
|
||||
ret = sst_dsp_register_poll(ctx,
|
||||
SKL_ADSP_REG_ADSPCS,
|
||||
SKL_ADSPCS_CRST_MASK,
|
||||
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK),
|
||||
SKL_ADSPCS_CRST_MASK(core_mask),
|
||||
SKL_ADSPCS_CRST_MASK(core_mask),
|
||||
SKL_DSP_RESET_TO,
|
||||
"Set reset");
|
||||
if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
|
||||
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) !=
|
||||
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) {
|
||||
dev_err(ctx->dev, "Set reset state failed\n");
|
||||
SKL_ADSPCS_CRST_MASK(core_mask)) !=
|
||||
SKL_ADSPCS_CRST_MASK(core_mask)) {
|
||||
dev_err(ctx->dev, "Set reset state failed: core_mask %x\n",
|
||||
core_mask);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -68,152 +119,160 @@ static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx)
|
|||
|
||||
/* update bits */
|
||||
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 */
|
||||
ret = sst_dsp_register_poll(ctx,
|
||||
SKL_ADSP_REG_ADSPCS,
|
||||
SKL_ADSPCS_CRST_MASK,
|
||||
SKL_ADSPCS_CRST_MASK(core_mask),
|
||||
0,
|
||||
SKL_DSP_RESET_TO,
|
||||
"Unset reset");
|
||||
|
||||
if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
|
||||
SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != 0) {
|
||||
dev_err(ctx->dev, "Unset reset state failed\n");
|
||||
SKL_ADSPCS_CRST_MASK(core_mask)) != 0) {
|
||||
dev_err(ctx->dev, "Unset reset state failed: core_mask %x\n",
|
||||
core_mask);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
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;
|
||||
bool is_enable;
|
||||
|
||||
val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS);
|
||||
|
||||
is_enable = ((val & SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) &&
|
||||
(val & SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)) &&
|
||||
!(val & SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) &&
|
||||
!(val & SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)));
|
||||
is_enable = ((val & SKL_ADSPCS_CPA_MASK(core_mask)) &&
|
||||
(val & SKL_ADSPCS_SPA_MASK(core_mask)) &&
|
||||
!(val & SKL_ADSPCS_CRST_MASK(core_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;
|
||||
}
|
||||
|
||||
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 */
|
||||
sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
|
||||
sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
|
||||
SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK));
|
||||
sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
|
||||
SKL_ADSPCS_CSTALL_MASK(core_mask),
|
||||
SKL_ADSPCS_CSTALL_MASK(core_mask));
|
||||
|
||||
/* 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;
|
||||
|
||||
/* unset reset state */
|
||||
ret = skl_dsp_core_unset_reset_state(ctx);
|
||||
if (ret < 0) {
|
||||
dev_dbg(ctx->dev, "dsp unset reset fails\n");
|
||||
ret = skl_dsp_core_unset_reset_state(ctx, core_mask);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* run core */
|
||||
dev_dbg(ctx->dev, "run core...\n");
|
||||
sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
|
||||
sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
|
||||
~SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK));
|
||||
dev_dbg(ctx->dev, "unstall/run core: core_mask = %x\n", core_mask);
|
||||
sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS,
|
||||
SKL_ADSPCS_CSTALL_MASK(core_mask), 0);
|
||||
|
||||
if (!is_skl_dsp_core_enable(ctx)) {
|
||||
skl_dsp_reset_core(ctx);
|
||||
dev_err(ctx->dev, "DSP core enable failed\n");
|
||||
if (!is_skl_dsp_core_enable(ctx, core_mask)) {
|
||||
skl_dsp_reset_core(ctx, core_mask);
|
||||
dev_err(ctx->dev, "DSP start core failed: core_mask %x\n",
|
||||
core_mask);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* update bits */
|
||||
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 */
|
||||
ret = sst_dsp_register_poll(ctx,
|
||||
SKL_ADSP_REG_ADSPCS,
|
||||
SKL_ADSPCS_CPA_MASK,
|
||||
SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK),
|
||||
SKL_ADSPCS_CPA_MASK(core_mask),
|
||||
SKL_ADSPCS_CPA_MASK(core_mask),
|
||||
SKL_DSP_PU_TO,
|
||||
"Power up");
|
||||
|
||||
if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) &
|
||||
SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) !=
|
||||
SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) {
|
||||
dev_err(ctx->dev, "DSP core power up failed\n");
|
||||
SKL_ADSPCS_CPA_MASK(core_mask)) !=
|
||||
SKL_ADSPCS_CPA_MASK(core_mask)) {
|
||||
dev_err(ctx->dev, "DSP core power up failed: core_mask %x\n",
|
||||
core_mask);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
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 */
|
||||
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 */
|
||||
return sst_dsp_register_poll(ctx,
|
||||
SKL_ADSP_REG_ADSPCS,
|
||||
SKL_ADSPCS_CPA_MASK,
|
||||
SKL_ADSPCS_CPA_MASK(core_mask),
|
||||
0,
|
||||
SKL_DSP_PD_TO,
|
||||
"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;
|
||||
|
||||
/* power up */
|
||||
ret = skl_dsp_core_power_up(ctx);
|
||||
ret = skl_dsp_core_power_up(ctx, core_mask);
|
||||
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 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;
|
||||
|
||||
ret = skl_dsp_reset_core(ctx);
|
||||
ret = skl_dsp_reset_core(ctx, core_mask);
|
||||
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;
|
||||
}
|
||||
|
||||
/* power down core*/
|
||||
ret = skl_dsp_core_power_down(ctx);
|
||||
ret = skl_dsp_core_power_down(ctx, core_mask);
|
||||
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;
|
||||
}
|
||||
|
||||
if (is_skl_dsp_core_enable(ctx)) {
|
||||
dev_err(ctx->dev, "DSP core disable failed\n");
|
||||
if (is_skl_dsp_core_enable(ctx, core_mask)) {
|
||||
dev_err(ctx->dev, "dsp core disable fail mask %x: %d\n",
|
||||
core_mask, ret);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
|
@ -224,28 +283,25 @@ int skl_dsp_boot(struct sst_dsp *ctx)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (is_skl_dsp_core_enable(ctx)) {
|
||||
dev_dbg(ctx->dev, "dsp core is already enabled, so reset the dap core\n");
|
||||
ret = skl_dsp_reset_core(ctx);
|
||||
if (is_skl_dsp_core_enable(ctx, SKL_DSP_CORE0_MASK)) {
|
||||
ret = skl_dsp_reset_core(ctx, SKL_DSP_CORE0_MASK);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "dsp reset failed\n");
|
||||
dev_err(ctx->dev, "dsp core0 reset fail: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = skl_dsp_start_core(ctx);
|
||||
ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "dsp start failed\n");
|
||||
dev_err(ctx->dev, "dsp core0 start fail: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
dev_dbg(ctx->dev, "disable and enable to make sure DSP is invalid state\n");
|
||||
ret = skl_dsp_disable_core(ctx);
|
||||
|
||||
ret = skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
|
||||
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;
|
||||
}
|
||||
ret = skl_dsp_enable_core(ctx);
|
||||
ret = skl_dsp_enable_core(ctx, SKL_DSP_CORE0_MASK);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -281,16 +337,74 @@ irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id)
|
|||
|
||||
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)
|
||||
{
|
||||
return ctx->fw_ops.set_state_D0(ctx);
|
||||
return skl_dsp_get_core(ctx, SKL_DSP_CORE0_ID);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(skl_dsp_wake);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -337,9 +451,7 @@ void skl_dsp_free(struct sst_dsp *dsp)
|
|||
|
||||
free_irq(dsp->irq, dsp);
|
||||
skl_ipc_op_int_disable(dsp);
|
||||
skl_ipc_int_disable(dsp);
|
||||
|
||||
skl_dsp_disable_core(dsp);
|
||||
skl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(skl_dsp_free);
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <sound/memalloc.h>
|
||||
#include "skl-sst-cldma.h"
|
||||
#include "skl-tplg-interface.h"
|
||||
|
||||
struct sst_dsp;
|
||||
struct skl_sst;
|
||||
|
@ -76,35 +77,53 @@ struct sst_dsp_device;
|
|||
#define SKL_ADSPIC_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 */
|
||||
#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 */
|
||||
/*
|
||||
* Core Reset - asserted high
|
||||
* CRST Mask for a given core mask pattern, cm
|
||||
*/
|
||||
#define SKL_ADSPCS_CRST_SHIFT 0
|
||||
#define SKL_ADSPCS_CRST_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_CRST_SHIFT)
|
||||
#define SKL_ADSPCS_CRST(x) ((x << SKL_ADSPCS_CRST_SHIFT) & SKL_ADSPCS_CRST_MASK)
|
||||
#define SKL_ADSPCS_CRST_MASK(cm) ((cm) << SKL_ADSPCS_CRST_SHIFT)
|
||||
|
||||
/* Core run/stall - when set to '1' core is stalled */
|
||||
/*
|
||||
* Core run/stall - when set to '1' core is stalled
|
||||
* CSTALL Mask for a given core mask pattern, cm
|
||||
*/
|
||||
#define SKL_ADSPCS_CSTALL_SHIFT 8
|
||||
#define SKL_ADSPCS_CSTALL_MASK (SKL_DSP_CORES_MASK << \
|
||||
SKL_ADSPCS_CSTALL_SHIFT)
|
||||
#define SKL_ADSPCS_CSTALL(x) ((x << SKL_ADSPCS_CSTALL_SHIFT) & \
|
||||
SKL_ADSPCS_CSTALL_MASK)
|
||||
#define SKL_ADSPCS_CSTALL_MASK(cm) ((cm) << SKL_ADSPCS_CSTALL_SHIFT)
|
||||
|
||||
/* Set Power Active - when set to '1' turn cores on */
|
||||
/*
|
||||
* Set Power Active - when set to '1' turn cores on
|
||||
* SPA Mask for a given core mask pattern, cm
|
||||
*/
|
||||
#define SKL_ADSPCS_SPA_SHIFT 16
|
||||
#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_MASK(cm) ((cm) << SKL_ADSPCS_SPA_SHIFT)
|
||||
|
||||
/* Current Power Active - power status of cores, set by hardware */
|
||||
/*
|
||||
* Current Power Active - power status of cores, set by hardware
|
||||
* CPA Mask for a given core mask pattern, cm
|
||||
*/
|
||||
#define SKL_ADSPCS_CPA_SHIFT 24
|
||||
#define SKL_ADSPCS_CPA_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_CPA_SHIFT)
|
||||
#define SKL_ADSPCS_CPA(x) ((x << SKL_ADSPCS_CPA_SHIFT) & SKL_ADSPCS_CPA_MASK)
|
||||
|
||||
#define SST_DSP_POWER_D0 0x0 /* full On */
|
||||
#define SST_DSP_POWER_D3 0x3 /* Off */
|
||||
#define SKL_ADSPCS_CPA_MASK(cm) ((cm) << SKL_ADSPCS_CPA_SHIFT)
|
||||
|
||||
enum skl_dsp_states {
|
||||
SKL_DSP_RUNNING = 1,
|
||||
|
@ -115,8 +134,8 @@ struct skl_dsp_fw_ops {
|
|||
int (*load_fw)(struct sst_dsp *ctx);
|
||||
/* FW module parser/loader */
|
||||
int (*parse_fw)(struct sst_dsp *ctx);
|
||||
int (*set_state_D0)(struct sst_dsp *ctx);
|
||||
int (*set_state_D3)(struct sst_dsp *ctx);
|
||||
int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id);
|
||||
int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id);
|
||||
unsigned int (*get_fw_errcode)(struct sst_dsp *ctx);
|
||||
int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name);
|
||||
int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id);
|
||||
|
@ -157,14 +176,26 @@ int skl_cldma_prepare(struct sst_dsp *ctx);
|
|||
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_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);
|
||||
|
||||
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);
|
||||
int skl_dsp_wake(struct sst_dsp *ctx);
|
||||
int skl_dsp_sleep(struct sst_dsp *ctx);
|
||||
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_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
||||
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,
|
|||
void skl_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__*/
|
||||
|
|
|
@ -363,7 +363,7 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
|
|||
/* first process the header */
|
||||
switch (reply) {
|
||||
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 */
|
||||
sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size);
|
||||
break;
|
||||
|
@ -692,7 +692,7 @@ int skl_ipc_init_instance(struct sst_generic_ipc *ipc,
|
|||
/* param_block_size must be in dwords */
|
||||
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);
|
||||
|
||||
header.primary = IPC_MSG_TARGET(IPC_MOD_MSG);
|
||||
|
|
|
@ -45,6 +45,14 @@ struct skl_ipc_header {
|
|||
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 device *dev;
|
||||
struct sst_dsp *dsp;
|
||||
|
@ -60,6 +68,15 @@ struct skl_sst {
|
|||
void (*enable_miscbdcge)(struct device *dev, bool enable);
|
||||
/*Is CGCTL.MISCBDCGE 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 {
|
||||
|
@ -136,5 +153,6 @@ void skl_ipc_int_disable(struct sst_dsp *dsp);
|
|||
bool skl_ipc_int_status(struct sst_dsp *dsp);
|
||||
void skl_ipc_free(struct sst_generic_ipc *ipc);
|
||||
int skl_ipc_init(struct device *dev, struct skl_sst *skl);
|
||||
void skl_clear_module_cnt(struct sst_dsp *ctx);
|
||||
|
||||
#endif /* __SKL_IPC_H */
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* 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,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define SKL_ADSP_FW_BIN_HDR_OFFSET 0x284
|
||||
|
||||
static int skl_load_base_firmware(struct sst_dsp *ctx)
|
||||
{
|
||||
int ret = 0, i;
|
||||
struct skl_sst *skl = ctx->thread_context;
|
||||
struct firmware stripped_fw;
|
||||
u32 reg;
|
||||
|
||||
skl->boot_complete = false;
|
||||
|
@ -81,11 +84,25 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
|
|||
ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Request firmware failed %d\n", ret);
|
||||
skl_dsp_disable_core(ctx);
|
||||
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);
|
||||
if (ret < 0) {
|
||||
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)
|
|||
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) {
|
||||
dev_err(ctx->dev, "Transfer firmware failed%d\n", ret);
|
||||
goto transfer_firmware_failed;
|
||||
|
@ -133,67 +150,87 @@ static int skl_load_base_firmware(struct sst_dsp *ctx)
|
|||
}
|
||||
|
||||
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;
|
||||
transfer_firmware_failed:
|
||||
ctx->cl_dev.ops.cl_cleanup_controller(ctx);
|
||||
skl_load_base_firmware_failed:
|
||||
skl_dsp_disable_core(ctx);
|
||||
skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
|
||||
release_firmware(ctx->fw);
|
||||
ctx->fw = NULL;
|
||||
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;
|
||||
struct skl_ipc_dxstate_info dx;
|
||||
struct skl_sst *skl = ctx->thread_context;
|
||||
unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
|
||||
|
||||
/* If core0 is being turned on, we need to load the FW */
|
||||
if (core_id == SKL_DSP_CORE0_ID) {
|
||||
ret = skl_load_base_firmware(ctx);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
struct skl_ipc_dxstate_info dx;
|
||||
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__);
|
||||
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.core_mask = core_mask;
|
||||
dx.dx_mask = SKL_IPC_D3_MASK;
|
||||
|
||||
ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx);
|
||||
if (ret < 0)
|
||||
dev_err(ctx->dev,
|
||||
"D3 request to FW failed, continuing reset: %d", ret);
|
||||
dev_err(ctx->dev, "set Dx core %d fail: %d\n", core_id, ret);
|
||||
|
||||
if (core_id == SKL_DSP_CORE0_ID) {
|
||||
/* disable Interrupt */
|
||||
ctx->cl_dev.ops.cl_cleanup_controller(ctx);
|
||||
skl_cldma_int_disable(ctx);
|
||||
skl_ipc_op_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;
|
||||
}
|
||||
|
||||
|
@ -360,6 +397,19 @@ static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id)
|
|||
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)
|
||||
{
|
||||
struct skl_module_table *module, *tmp;
|
||||
|
@ -409,6 +459,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
|||
|
||||
skl->dev = dev;
|
||||
skl_dev.thread_context = skl;
|
||||
INIT_LIST_HEAD(&skl->uuid_list);
|
||||
|
||||
skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq);
|
||||
if (!skl->dsp) {
|
||||
|
@ -432,12 +483,16 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
skl->cores.count = 2;
|
||||
|
||||
ret = sst->fw_ops.load_fw(sst);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Load base fw failed : %d", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
skl_dsp_init_core_state(sst);
|
||||
|
||||
if (dsp)
|
||||
*dsp = skl;
|
||||
|
||||
|
@ -452,6 +507,7 @@ EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
|
|||
void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
|
||||
{
|
||||
skl_clear_module_table(ctx->dsp);
|
||||
skl_freeup_uuid_list(ctx);
|
||||
skl_ipc_free(&ctx->ipc);
|
||||
ctx->dsp->ops->free(ctx->dsp);
|
||||
if (ctx->boot_complete) {
|
||||
|
|
|
@ -378,43 +378,6 @@ static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
|
|||
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
|
||||
* 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)
|
|||
if (!skl_is_pipe_mcps_avail(skl, mconfig))
|
||||
return -ENOMEM;
|
||||
|
||||
skl_tplg_alloc_pipe_mcps(skl, mconfig);
|
||||
|
||||
if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
|
||||
ret = ctx->dsp->fw_ops.load_mod(ctx->dsp,
|
||||
mconfig->id.module_id, mconfig->guid);
|
||||
|
@ -539,6 +500,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
skl_tplg_alloc_pipe_mcps(skl, mconfig);
|
||||
ret = skl_tplg_set_module_params(w, ctx);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -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))
|
||||
return -ENOMEM;
|
||||
|
||||
skl_tplg_alloc_pipe_mem(skl, mconfig);
|
||||
skl_tplg_alloc_pipe_mcps(skl, mconfig);
|
||||
|
||||
/*
|
||||
* Create a list of modules for pipe.
|
||||
* 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,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* we create a w_list of all widgets in that pipe. This list is not
|
||||
* 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;
|
||||
}
|
||||
skl_tplg_alloc_pipe_mem(skl, mconfig);
|
||||
skl_tplg_alloc_pipe_mcps(skl, mconfig);
|
||||
|
||||
/* Init all pipe modules from source to sink */
|
||||
ret = skl_tplg_init_pipe_modules(skl, s_pipe);
|
||||
|
@ -949,12 +897,16 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
|
|||
struct skl_pipe *s_pipe = mconfig->pipe;
|
||||
int ret = 0;
|
||||
|
||||
if (s_pipe->state == SKL_PIPE_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
skl_tplg_free_pipe_mcps(skl, mconfig);
|
||||
skl_tplg_free_pipe_mem(skl, mconfig);
|
||||
|
||||
list_for_each_entry(w_module, &s_pipe->w_list, node) {
|
||||
dst_module = w_module->w->priv;
|
||||
|
||||
if (mconfig->m_state >= SKL_MODULE_INIT_DONE)
|
||||
skl_tplg_free_pipe_mcps(skl, dst_module);
|
||||
if (src_module == NULL) {
|
||||
src_module = dst_module;
|
||||
|
@ -1162,6 +1114,39 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol,
|
|||
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.
|
||||
* 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,
|
|||
struct skl_module_cfg *mconfig,
|
||||
struct skl_pipe_params *params)
|
||||
{
|
||||
struct skl_pipe *pipe = mconfig->pipe;
|
||||
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)
|
||||
format = &mconfig->in_fmt[0];
|
||||
|
@ -1362,12 +1346,11 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
|
|||
struct skl_module_cfg *mconfig,
|
||||
struct skl_pipe_params *params)
|
||||
{
|
||||
struct skl_pipe *pipe = mconfig->pipe;
|
||||
struct nhlt_specific_cfg *cfg;
|
||||
struct skl *skl = get_skl_ctx(dai->dev);
|
||||
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)
|
||||
return 0;
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -1589,6 +1621,10 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
|
|||
w->priv = mconfig;
|
||||
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.instance_id = dfw_config->instance_id;
|
||||
mconfig->mcps = dfw_config->max_mcps;
|
||||
|
@ -1738,6 +1774,60 @@ static struct snd_soc_tplg_ops skl_tplg_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 */
|
||||
#define SKL_MAX_MCPS 30000000
|
||||
#define SKL_FW_MAX_MEM 1000000
|
||||
|
@ -1751,6 +1841,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
|
|||
const struct firmware *fw;
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
struct skl *skl = ebus_to_skl(ebus);
|
||||
struct skl_pipeline *ppl;
|
||||
|
||||
ret = request_firmware(&fw, skl->tplg_name, bus->dev);
|
||||
if (ret < 0) {
|
||||
|
@ -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->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;
|
||||
}
|
||||
|
|
|
@ -244,7 +244,8 @@ enum skl_pipe_state {
|
|||
SKL_PIPE_INVALID = 0,
|
||||
SKL_PIPE_CREATED = 1,
|
||||
SKL_PIPE_PAUSED = 2,
|
||||
SKL_PIPE_STARTED = 3
|
||||
SKL_PIPE_STARTED = 3,
|
||||
SKL_PIPE_RESET = 4
|
||||
};
|
||||
|
||||
struct skl_pipe_module {
|
||||
|
@ -270,6 +271,7 @@ struct skl_pipe {
|
|||
struct skl_pipe_params *p_params;
|
||||
enum skl_pipe_state state;
|
||||
struct list_head w_list;
|
||||
bool passthru;
|
||||
};
|
||||
|
||||
enum skl_module_state {
|
||||
|
@ -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_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_bind_modules(struct skl_sst *ctx, struct skl_module_cfg
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include "skl-sst-dsp.h"
|
||||
#include "skl-sst-ipc.h"
|
||||
|
||||
static struct skl_machine_pdata skl_dmic_data;
|
||||
|
||||
/*
|
||||
* initialize the PCI registers
|
||||
*/
|
||||
|
@ -184,6 +186,7 @@ static int _skl_suspend(struct hdac_ext_bus *ebus)
|
|||
{
|
||||
struct skl *skl = ebus_to_skl(ebus);
|
||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||
struct pci_dev *pci = to_pci_dev(bus->dev);
|
||||
int ret;
|
||||
|
||||
snd_hdac_ext_bus_link_power_down_all(ebus);
|
||||
|
@ -193,9 +196,12 @@ static int _skl_suspend(struct hdac_ext_bus *ebus)
|
|||
return ret;
|
||||
|
||||
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);
|
||||
snd_hdac_bus_enter_link_reset(bus);
|
||||
skl_enable_miscbdcge(bus->dev, true);
|
||||
skl_cleanup_resources(skl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -242,6 +248,7 @@ static int skl_suspend(struct device *dev)
|
|||
ret = _skl_suspend(ebus);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
skl->skl_sst->fw_loaded = false;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
|
||||
|
@ -397,6 +404,10 @@ static int skl_machine_device_register(struct skl *skl, void *driver_data)
|
|||
platform_device_put(pdev);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (mach->pdata)
|
||||
dev_set_drvdata(&pdev->dev, mach->pdata);
|
||||
|
||||
skl->i2s_dev = pdev;
|
||||
|
||||
return 0;
|
||||
|
@ -657,6 +668,8 @@ static int skl_probe(struct pci_dev *pci,
|
|||
|
||||
skl->pci_id = pci->device;
|
||||
|
||||
device_disable_async_suspend(bus->dev);
|
||||
|
||||
skl->nhlt = skl_nhlt_init(bus->dev);
|
||||
|
||||
if (skl->nhlt == NULL)
|
||||
|
@ -666,6 +679,8 @@ static int skl_probe(struct pci_dev *pci,
|
|||
|
||||
pci_set_drvdata(skl->pci, ebus);
|
||||
|
||||
skl_dmic_data.dmic_num = skl_get_dmic_geo(skl);
|
||||
|
||||
/* check if dsp is there */
|
||||
if (ebus->ppcap) {
|
||||
err = skl_machine_device_register(skl,
|
||||
|
@ -713,7 +728,7 @@ static int skl_probe(struct pci_dev *pci,
|
|||
list_for_each_entry(hlink, &ebus->hlink_list, list)
|
||||
snd_hdac_ext_bus_link_put(ebus, hlink);
|
||||
|
||||
/*configure PM */
|
||||
/* configure PM */
|
||||
pm_runtime_put_noidle(bus->dev);
|
||||
pm_runtime_allow(bus->dev);
|
||||
|
||||
|
@ -766,7 +781,6 @@ static void skl_remove(struct pci_dev *pci)
|
|||
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
|
||||
struct skl *skl = ebus_to_skl(ebus);
|
||||
|
||||
if (skl->tplg)
|
||||
release_firmware(skl->tplg);
|
||||
|
||||
if (pci_dev_run_wake(pci))
|
||||
|
@ -786,15 +800,23 @@ static void skl_remove(struct pci_dev *pci)
|
|||
|
||||
static struct sst_acpi_mach sst_skl_devdata[] = {
|
||||
{ "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL },
|
||||
{ "INT343B", "skl_nau88l25_ssm4567_i2s", "intel/dsp_fw_release.bin",
|
||||
NULL, NULL, NULL },
|
||||
{ "MX98357A", "skl_nau88l25_max98357a_i2s", "intel/dsp_fw_release.bin",
|
||||
NULL, NULL, NULL },
|
||||
{ "INT343B", "skl_n88l25_s4567", "intel/dsp_fw_release.bin",
|
||||
NULL, NULL, &skl_dmic_data },
|
||||
{ "MX98357A", "skl_n88l25_m98357a", "intel/dsp_fw_release.bin",
|
||||
NULL, NULL, &skl_dmic_data },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct sst_acpi_mach sst_bxtp_devdata[] = {
|
||||
{ "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 */
|
||||
|
@ -805,6 +827,9 @@ static const struct pci_device_id skl_ids[] = {
|
|||
/* BXT-P */
|
||||
{ PCI_DEVICE(0x8086, 0x5a98),
|
||||
.driver_data = (unsigned long)&sst_bxtp_devdata},
|
||||
/* KBL */
|
||||
{ PCI_DEVICE(0x8086, 0x9D71),
|
||||
.driver_data = (unsigned long)&sst_kbl_devdata},
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, skl_ids);
|
||||
|
|
|
@ -48,6 +48,8 @@
|
|||
#define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094
|
||||
#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_CGCTL_MISCBDCGE_MASK (1 << 6)
|
||||
|
||||
|
@ -65,6 +67,7 @@ struct skl {
|
|||
unsigned int init_failed:1; /* delayed init failed */
|
||||
struct platform_device *dmic_dev;
|
||||
struct platform_device *i2s_dev;
|
||||
struct snd_soc_platform *platform;
|
||||
|
||||
struct nhlt_acpi_table *nhlt; /* nhlt ptr */
|
||||
struct skl_sst *skl_sst; /* sst skl ctx */
|
||||
|
@ -90,6 +93,11 @@ struct skl_dma_params {
|
|||
u8 stream_tag;
|
||||
};
|
||||
|
||||
/* to pass dmic data */
|
||||
struct skl_machine_pdata {
|
||||
u32 dmic_num;
|
||||
};
|
||||
|
||||
struct skl_dsp_ops {
|
||||
int id;
|
||||
struct skl_dsp_loader_ops (*loader_ops)(void);
|
||||
|
@ -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,
|
||||
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_init_dsp(struct skl *skl);
|
||||
int skl_free_dsp(struct skl *skl);
|
||||
int skl_suspend_dsp(struct skl *skl);
|
||||
int skl_resume_dsp(struct skl *skl);
|
||||
void skl_cleanup_resources(struct skl *skl);
|
||||
#endif /* __SOUND_SOC_SKL_H */
|
||||
|
|
Загрузка…
Ссылка в новой задаче