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

This commit is contained in:
Mark Brown 2017-09-01 12:12:19 +01:00
Родитель 39e0a0ae69 38a770859e
Коммит 460f623a6e
30 изменённых файлов: 2419 добавлений и 277 удалений

Просмотреть файл

@ -163,8 +163,71 @@
* *
* %SKL_TKN_U32_DMA_BUF_SIZE: DMA buffer size in millisec * %SKL_TKN_U32_DMA_BUF_SIZE: DMA buffer size in millisec
* *
* %SKL_TKN_U32_PIPE_DIR: Specifies pipe direction. Can be
* playback/capture.
*
* %SKL_TKN_U32_NUM_CONFIGS: Number of pipe configs
*
* %SKL_TKN_U32_PATH_MEM_PGS: Size of memory (in pages) required for pipeline
* and its data
*
* %SKL_TKN_U32_PIPE_CONFIG_ID: Config id for the modules in the pipe
* and PCM params supported by that pipe
* config. This is used as index to fill
* up the pipe config and module config
* structure.
*
* %SKL_TKN_U32_CFG_FREQ:
* %SKL_TKN_U8_CFG_CHAN:
* %SKL_TKN_U8_CFG_BPS: PCM params (freq, channels, bits per sample)
* supported for each of the pipe configs.
*
* %SKL_TKN_CFG_MOD_RES_ID: Module's resource index for each of the
* pipe config
*
* %SKL_TKN_CFG_MOD_FMT_ID: Module's interface index for each of the
* pipe config
*
* %SKL_TKN_U8_NUM_MOD: Number of modules in the manifest
*
* %SKL_TKN_MM_U8_MOD_IDX: Current index of the module in the manifest
*
* %SKL_TKN_MM_U8_NUM_RES: Number of resources for the module
*
* %SKL_TKN_MM_U8_NUM_INTF: Number of interfaces for the module
*
* %SKL_TKN_MM_U32_RES_ID: Resource index for the resource info to
* be filled into.
* A module can support multiple resource
* configuration and is represnted as a
* resource table. This index is used to
* fill information into appropriate index.
*
* %SKL_TKN_MM_U32_CPS: DSP cycles per second
*
* %SKL_TKN_MM_U32_DMA_SIZE: Allocated buffer size for gateway DMA
*
* %SKL_TKN_MM_U32_CPC: DSP cycles allocated per frame
*
* %SKL_TKN_MM_U32_RES_PIN_ID: Resource pin index in the module
*
* %SKL_TKN_MM_U32_INTF_PIN_ID: Interface index in the module
*
* %SKL_TKN_MM_U32_PIN_BUF: Buffer size of the module pin
*
* %SKL_TKN_MM_U32_FMT_ID: Format index for each of the interface/
* format information to be filled into.
*
* %SKL_TKN_MM_U32_NUM_IN_FMT: Number of input formats
* %SKL_TKN_MM_U32_NUM_OUT_FMT: Number of output formats
*
* module_id and loadable flags dont have tokens as these values will be * module_id and loadable flags dont have tokens as these values will be
* read from the DSP FW manifest * read from the DSP FW manifest
*
* Tokens defined can be used either in the manifest or widget private data.
*
* SKL_TKN_MM is used as a suffix for all tokens that represent
* module data in the manifest.
*/ */
enum SKL_TKNS { enum SKL_TKNS {
SKL_TKN_UUID = 1, SKL_TKN_UUID = 1,
@ -218,7 +281,34 @@ enum SKL_TKNS {
SKL_TKL_U32_D0I3_CAPS, /* Typo added at v4.10 */ SKL_TKL_U32_D0I3_CAPS, /* Typo added at v4.10 */
SKL_TKN_U32_D0I3_CAPS = SKL_TKL_U32_D0I3_CAPS, SKL_TKN_U32_D0I3_CAPS = SKL_TKL_U32_D0I3_CAPS,
SKL_TKN_U32_DMA_BUF_SIZE, SKL_TKN_U32_DMA_BUF_SIZE,
SKL_TKN_MAX = SKL_TKN_U32_DMA_BUF_SIZE,
SKL_TKN_U32_PIPE_DIRECTION,
SKL_TKN_U32_PIPE_CONFIG_ID,
SKL_TKN_U32_NUM_CONFIGS,
SKL_TKN_U32_PATH_MEM_PGS,
SKL_TKN_U32_CFG_FREQ,
SKL_TKN_U8_CFG_CHAN,
SKL_TKN_U8_CFG_BPS,
SKL_TKN_CFG_MOD_RES_ID,
SKL_TKN_CFG_MOD_FMT_ID,
SKL_TKN_U8_NUM_MOD,
SKL_TKN_MM_U8_MOD_IDX,
SKL_TKN_MM_U8_NUM_RES,
SKL_TKN_MM_U8_NUM_INTF,
SKL_TKN_MM_U32_RES_ID,
SKL_TKN_MM_U32_CPS,
SKL_TKN_MM_U32_DMA_SIZE,
SKL_TKN_MM_U32_CPC,
SKL_TKN_MM_U32_RES_PIN_ID,
SKL_TKN_MM_U32_INTF_PIN_ID,
SKL_TKN_MM_U32_PIN_BUF,
SKL_TKN_MM_U32_FMT_ID,
SKL_TKN_MM_U32_NUM_IN_FMT,
SKL_TKN_MM_U32_NUM_OUT_FMT,
SKL_TKN_MAX = SKL_TKN_MM_U32_NUM_OUT_FMT,
}; };
#endif #endif

Просмотреть файл

@ -321,6 +321,7 @@ obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o
obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o
obj-$(CONFIG_SND_SOC_MAX98371) += snd-soc-max98371.o
obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o
obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o
obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o

Просмотреть файл

@ -121,6 +121,10 @@ struct hdac_hdmi_dai_port_map {
struct hdac_hdmi_cvt *cvt; struct hdac_hdmi_cvt *cvt;
}; };
struct hdac_hdmi_drv_data {
unsigned int vendor_nid;
};
struct hdac_hdmi_priv { struct hdac_hdmi_priv {
struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS]; struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS];
struct list_head pin_list; struct list_head pin_list;
@ -131,6 +135,7 @@ struct hdac_hdmi_priv {
int num_ports; int num_ports;
struct mutex pin_mutex; struct mutex pin_mutex;
struct hdac_chmap chmap; struct hdac_chmap chmap;
struct hdac_hdmi_drv_data *drv_data;
}; };
static struct hdac_hdmi_pcm * static struct hdac_hdmi_pcm *
@ -1321,6 +1326,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
} }
#define INTEL_VENDOR_NID 0x08 #define INTEL_VENDOR_NID 0x08
#define INTEL_GLK_VENDOR_NID 0x0b
#define INTEL_GET_VENDOR_VERB 0xf81 #define INTEL_GET_VENDOR_VERB 0xf81
#define INTEL_SET_VENDOR_VERB 0x781 #define INTEL_SET_VENDOR_VERB 0x781
#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ #define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */
@ -1329,14 +1335,17 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac) static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
{ {
unsigned int vendor_param; unsigned int vendor_param;
struct hdac_ext_device *edev = to_ehdac_device(hdac);
struct hdac_hdmi_priv *hdmi = edev->private_data;
unsigned int vendor_nid = hdmi->drv_data->vendor_nid;
vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
INTEL_GET_VENDOR_VERB, 0); INTEL_GET_VENDOR_VERB, 0);
if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS) if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
return; return;
vendor_param |= INTEL_EN_ALL_PIN_CVTS; vendor_param |= INTEL_EN_ALL_PIN_CVTS;
vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
INTEL_SET_VENDOR_VERB, vendor_param); INTEL_SET_VENDOR_VERB, vendor_param);
if (vendor_param == -1) if (vendor_param == -1)
return; return;
@ -1345,15 +1354,18 @@ static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac)
static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac) static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac)
{ {
unsigned int vendor_param; unsigned int vendor_param;
struct hdac_ext_device *edev = to_ehdac_device(hdac);
struct hdac_hdmi_priv *hdmi = edev->private_data;
unsigned int vendor_nid = hdmi->drv_data->vendor_nid;
vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
INTEL_GET_VENDOR_VERB, 0); INTEL_GET_VENDOR_VERB, 0);
if (vendor_param == -1 || vendor_param & INTEL_EN_DP12) if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
return; return;
/* enable DP1.2 mode */ /* enable DP1.2 mode */
vendor_param |= INTEL_EN_DP12; vendor_param |= INTEL_EN_DP12;
vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, vendor_param = snd_hdac_codec_read(hdac, vendor_nid, 0,
INTEL_SET_VENDOR_VERB, vendor_param); INTEL_SET_VENDOR_VERB, vendor_param);
if (vendor_param == -1) if (vendor_param == -1)
return; return;
@ -1927,6 +1939,14 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
return port->eld.info.spk_alloc; return port->eld.info.spk_alloc;
} }
static struct hdac_hdmi_drv_data intel_glk_drv_data = {
.vendor_nid = INTEL_GLK_VENDOR_NID,
};
static struct hdac_hdmi_drv_data intel_drv_data = {
.vendor_nid = INTEL_VENDOR_NID,
};
static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
{ {
struct hdac_device *codec = &edev->hdac; struct hdac_device *codec = &edev->hdac;
@ -1935,6 +1955,8 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
struct hdac_ext_link *hlink = NULL; struct hdac_ext_link *hlink = NULL;
int num_dais = 0; int num_dais = 0;
int ret = 0; int ret = 0;
struct hdac_driver *hdrv = drv_to_hdac_driver(codec->dev.driver);
const struct hda_device_id *hdac_id = hdac_get_device_id(codec, hdrv);
/* hold the ref while we probe */ /* hold the ref while we probe */
hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev));
@ -1956,6 +1978,12 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached; hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached;
hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc; hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
if (hdac_id->driver_data)
hdmi_priv->drv_data =
(struct hdac_hdmi_drv_data *)hdac_id->driver_data;
else
hdmi_priv->drv_data = &intel_drv_data;
dev_set_drvdata(&codec->dev, edev); dev_set_drvdata(&codec->dev, edev);
INIT_LIST_HEAD(&hdmi_priv->pin_list); INIT_LIST_HEAD(&hdmi_priv->pin_list);
@ -2127,7 +2155,8 @@ static const struct hda_device_id hdmi_list[] = {
HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0), HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0), HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", 0), HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI",
&intel_glk_drv_data),
{} {}
}; };

Просмотреть файл

@ -349,12 +349,14 @@ static struct snd_soc_dai_driver max98371_dai[] = {
}; };
static const struct snd_soc_codec_driver max98371_codec = { static const struct snd_soc_codec_driver max98371_codec = {
.controls = max98371_snd_controls, .component_driver = {
.num_controls = ARRAY_SIZE(max98371_snd_controls), .controls = max98371_snd_controls,
.dapm_routes = max98371_audio_map, .num_controls = ARRAY_SIZE(max98371_snd_controls),
.num_dapm_routes = ARRAY_SIZE(max98371_audio_map), .dapm_routes = max98371_audio_map,
.dapm_widgets = max98371_dapm_widgets, .num_dapm_routes = ARRAY_SIZE(max98371_audio_map),
.num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets), .dapm_widgets = max98371_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets),
},
}; };
static const struct regmap_config max98371_regmap = { static const struct regmap_config max98371_regmap = {

Просмотреть файл

@ -255,11 +255,12 @@ config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH
config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH
tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode" tristate "ASoC Audio driver for KBL with RT5663, RT5514 and MAX98927 in I2S Mode"
depends on X86_INTEL_LPSS && I2C depends on X86_INTEL_LPSS && I2C && SPI
select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE select SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT5663 select SND_SOC_RT5663
select SND_SOC_RT5514 select SND_SOC_RT5514
select SND_SOC_RT5514_SPI
select SND_SOC_MAX98927 select SND_SOC_MAX98927
select SND_SOC_HDAC_HDMI select SND_SOC_HDAC_HDMI
help help

Просмотреть файл

@ -76,7 +76,7 @@ int sst_unregister_dsp(struct sst_device *dev)
} }
EXPORT_SYMBOL_GPL(sst_unregister_dsp); EXPORT_SYMBOL_GPL(sst_unregister_dsp);
static struct snd_pcm_hardware sst_platform_pcm_hw = { static const struct snd_pcm_hardware sst_platform_pcm_hw = {
.info = (SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_DOUBLE | SNDRV_PCM_INFO_DOUBLE |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_PAUSE |
@ -471,7 +471,7 @@ static void sst_disable_ssp(struct snd_pcm_substream *substream,
} }
} }
static struct snd_soc_dai_ops sst_media_dai_ops = { static const struct snd_soc_dai_ops sst_media_dai_ops = {
.startup = sst_media_open, .startup = sst_media_open,
.shutdown = sst_media_close, .shutdown = sst_media_close,
.prepare = sst_media_prepare, .prepare = sst_media_prepare,
@ -480,11 +480,11 @@ static struct snd_soc_dai_ops sst_media_dai_ops = {
.mute_stream = sst_media_digital_mute, .mute_stream = sst_media_digital_mute,
}; };
static struct snd_soc_dai_ops sst_compr_dai_ops = { static const struct snd_soc_dai_ops sst_compr_dai_ops = {
.mute_stream = sst_media_digital_mute, .mute_stream = sst_media_digital_mute,
}; };
static struct snd_soc_dai_ops sst_be_dai_ops = { static const struct snd_soc_dai_ops sst_be_dai_ops = {
.startup = sst_enable_ssp, .startup = sst_enable_ssp,
.hw_params = sst_be_hw_params, .hw_params = sst_be_hw_params,
.set_fmt = sst_set_format, .set_fmt = sst_set_format,
@ -705,7 +705,7 @@ static int sst_soc_probe(struct snd_soc_platform *platform)
return sst_dsp_init_v2_dpcm(platform); return sst_dsp_init_v2_dpcm(platform);
} }
static struct snd_soc_platform_driver sst_soc_platform_drv = { static const struct snd_soc_platform_driver sst_soc_platform_drv = {
.probe = sst_soc_probe, .probe = sst_soc_probe,
.ops = &sst_platform_ops, .ops = &sst_platform_ops,
.compr_ops = &sst_platform_compr_ops, .compr_ops = &sst_platform_compr_ops,

Просмотреть файл

@ -407,7 +407,7 @@ static int sst_cdev_caps(struct snd_compr_caps *caps)
return 0; return 0;
} }
static struct snd_compr_codec_caps caps_mp3 = { static const struct snd_compr_codec_caps caps_mp3 = {
.num_descriptors = 1, .num_descriptors = 1,
.descriptor[0].max_ch = 2, .descriptor[0].max_ch = 2,
.descriptor[0].sample_rates[0] = 48000, .descriptor[0].sample_rates[0] = 48000,
@ -424,7 +424,7 @@ static struct snd_compr_codec_caps caps_mp3 = {
.descriptor[0].formats = 0, .descriptor[0].formats = 0,
}; };
static struct snd_compr_codec_caps caps_aac = { static const struct snd_compr_codec_caps caps_aac = {
.num_descriptors = 2, .num_descriptors = 2,
.descriptor[1].max_ch = 2, .descriptor[1].max_ch = 2,
.descriptor[0].sample_rates[0] = 48000, .descriptor[0].sample_rates[0] = 48000,

Просмотреть файл

@ -181,7 +181,7 @@ static void intel_sst_remove(struct pci_dev *pci)
} }
/* PCI Routines */ /* PCI Routines */
static struct pci_device_id intel_sst_ids[] = { static const struct pci_device_id intel_sst_ids[] = {
{ PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0}, { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
{ 0, } { 0, }
}; };

Просмотреть файл

@ -309,7 +309,7 @@ static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
return snd_pcm_lib_default_mmap(substream, vma); return snd_pcm_lib_default_mmap(substream, vma);
} }
static struct snd_pcm_ops sst_byt_pcm_ops = { static const struct snd_pcm_ops sst_byt_pcm_ops = {
.open = sst_byt_pcm_open, .open = sst_byt_pcm_open,
.close = sst_byt_pcm_close, .close = sst_byt_pcm_close,
.ioctl = snd_pcm_lib_ioctl, .ioctl = snd_pcm_lib_ioctl,
@ -395,7 +395,7 @@ static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
return 0; return 0;
} }
static struct snd_soc_platform_driver byt_soc_platform = { static const struct snd_soc_platform_driver byt_soc_platform = {
.probe = sst_byt_pcm_probe, .probe = sst_byt_pcm_probe,
.remove = sst_byt_pcm_remove, .remove = sst_byt_pcm_remove,
.ops = &sst_byt_pcm_ops, .ops = &sst_byt_pcm_ops,

Просмотреть файл

@ -114,7 +114,44 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = {
{ "iDisp2 Tx", NULL, "iDisp2_out"}, { "iDisp2 Tx", NULL, "iDisp2_out"},
{ "hifi1", NULL, "iDisp1 Tx"}, { "hifi1", NULL, "iDisp1 Tx"},
{ "iDisp1 Tx", NULL, "iDisp1_out"}, { "iDisp1 Tx", NULL, "iDisp1_out"},
};
static const struct snd_soc_dapm_route geminilake_rt298_map[] = {
/* speaker */
{"Speaker", NULL, "SPOR"},
{"Speaker", NULL, "SPOL"},
/* HP jack connectors - unknown if we have jack detect */
{"Headphone Jack", NULL, "HPO Pin"},
/* other jacks */
{"MIC1", NULL, "Mic Jack"},
/* digital mics */
{"DMIC1 Pin", NULL, "DMIC2"},
{"DMic", NULL, "SoC DMIC"},
{"HDMI1", NULL, "hif5-0 Output"},
{"HDMI2", NULL, "hif6-0 Output"},
{"HDMI2", NULL, "hif7-0 Output"},
/* CODEC BE connections */
{ "AIF1 Playback", NULL, "ssp2 Tx"},
{ "ssp2 Tx", NULL, "codec0_out"},
{ "ssp2 Tx", NULL, "codec1_out"},
{ "codec0_in", NULL, "ssp2 Rx" },
{ "ssp2 Rx", NULL, "AIF1 Capture" },
{ "dmic01_hifi", NULL, "DMIC01 Rx" },
{ "DMIC01 Rx", NULL, "Capture" },
{ "hifi3", NULL, "iDisp3 Tx"},
{ "iDisp3 Tx", NULL, "iDisp3_out"},
{ "hifi2", NULL, "iDisp2 Tx"},
{ "iDisp2 Tx", NULL, "iDisp2_out"},
{ "hifi1", NULL, "iDisp1 Tx"},
{ "iDisp1 Tx", NULL, "iDisp1_out"},
}; };
static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime *rtd) static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime *rtd)
@ -492,7 +529,6 @@ static int bxt_card_late_probe(struct snd_soc_card *card)
/* broxton audio machine driver for SPT + RT298S */ /* broxton audio machine driver for SPT + RT298S */
static struct snd_soc_card broxton_rt298 = { static struct snd_soc_card broxton_rt298 = {
.name = "broxton-rt298", .name = "broxton-rt298",
.owner = THIS_MODULE,
.dai_link = broxton_rt298_dais, .dai_link = broxton_rt298_dais,
.num_links = ARRAY_SIZE(broxton_rt298_dais), .num_links = ARRAY_SIZE(broxton_rt298_dais),
.controls = broxton_controls, .controls = broxton_controls,
@ -506,9 +542,41 @@ static struct snd_soc_card broxton_rt298 = {
}; };
static struct snd_soc_card geminilake_rt298 = {
.name = "geminilake-rt298",
.dai_link = broxton_rt298_dais,
.num_links = ARRAY_SIZE(broxton_rt298_dais),
.controls = broxton_controls,
.num_controls = ARRAY_SIZE(broxton_controls),
.dapm_widgets = broxton_widgets,
.num_dapm_widgets = ARRAY_SIZE(broxton_widgets),
.dapm_routes = geminilake_rt298_map,
.num_dapm_routes = ARRAY_SIZE(geminilake_rt298_map),
.fully_routed = true,
.late_probe = bxt_card_late_probe,
};
static int broxton_audio_probe(struct platform_device *pdev) static int broxton_audio_probe(struct platform_device *pdev)
{ {
struct bxt_rt286_private *ctx; struct bxt_rt286_private *ctx;
struct snd_soc_card *card =
(struct snd_soc_card *)pdev->id_entry->driver_data;
int i;
for (i = 0; i < ARRAY_SIZE(broxton_rt298_dais); i++) {
if (!strncmp(card->dai_link[i].codec_name, "i2c-INT343A:00",
I2C_NAME_SIZE)) {
if (!strncmp(card->name, "broxton-rt298",
PLATFORM_NAME_SIZE)) {
card->dai_link[i].name = "SSP5-Codec";
card->dai_link[i].cpu_dai_name = "SSP5 Pin";
} else if (!strncmp(card->name, "geminilake-rt298",
PLATFORM_NAME_SIZE)) {
card->dai_link[i].name = "SSP2-Codec";
card->dai_link[i].cpu_dai_name = "SSP2 Pin";
}
}
}
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
if (!ctx) if (!ctx)
@ -516,18 +584,27 @@ static int broxton_audio_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&ctx->hdmi_pcm_list); INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
broxton_rt298.dev = &pdev->dev; card->dev = &pdev->dev;
snd_soc_card_set_drvdata(&broxton_rt298, ctx); snd_soc_card_set_drvdata(card, ctx);
return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298); return devm_snd_soc_register_card(&pdev->dev, card);
} }
static const struct platform_device_id bxt_board_ids[] = {
{ .name = "bxt_alc298s_i2s", .driver_data =
(unsigned long)&broxton_rt298 },
{ .name = "glk_alc298s_i2s", .driver_data =
(unsigned long)&geminilake_rt298 },
{}
};
static struct platform_driver broxton_audio = { static struct platform_driver broxton_audio = {
.probe = broxton_audio_probe, .probe = broxton_audio_probe,
.driver = { .driver = {
.name = "bxt_alc298s_i2s", .name = "bxt_alc298s_i2s",
.pm = &snd_soc_pm_ops, .pm = &snd_soc_pm_ops,
}, },
.id_table = bxt_board_ids,
}; };
module_platform_driver(broxton_audio) module_platform_driver(broxton_audio)
@ -537,3 +614,4 @@ MODULE_AUTHOR("Senthilnathan Veppur <senthilnathanx.veppur@intel.com>");
MODULE_DESCRIPTION("Intel SST Audio for Broxton"); MODULE_DESCRIPTION("Intel SST Audio for Broxton");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:bxt_alc298s_i2s"); MODULE_ALIAS("platform:bxt_alc298s_i2s");
MODULE_ALIAS("platform:glk_alc298s_i2s");

Просмотреть файл

@ -34,7 +34,7 @@
#define MAXIM_DEV0_NAME "i2c-MX98927:00" #define MAXIM_DEV0_NAME "i2c-MX98927:00"
#define MAXIM_DEV1_NAME "i2c-MX98927:01" #define MAXIM_DEV1_NAME "i2c-MX98927:01"
static struct snd_soc_card kabylake_audio_card; static struct snd_soc_card *kabylake_audio_card;
static const struct snd_pcm_hw_constraint_list *dmic_constraints; static const struct snd_pcm_hw_constraint_list *dmic_constraints;
static struct snd_soc_jack skylake_hdmi[3]; static struct snd_soc_jack skylake_hdmi[3];
@ -52,6 +52,8 @@ struct kbl_rt5663_private {
enum { enum {
KBL_DPCM_AUDIO_PB = 0, KBL_DPCM_AUDIO_PB = 0,
KBL_DPCM_AUDIO_CP, KBL_DPCM_AUDIO_CP,
KBL_DPCM_AUDIO_HS_PB,
KBL_DPCM_AUDIO_ECHO_REF_CP,
KBL_DPCM_AUDIO_REF_CP, KBL_DPCM_AUDIO_REF_CP,
KBL_DPCM_AUDIO_DMIC_CP, KBL_DPCM_AUDIO_DMIC_CP,
KBL_DPCM_AUDIO_HDMI1_PB, KBL_DPCM_AUDIO_HDMI1_PB,
@ -72,8 +74,9 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
SND_SOC_DAPM_SPK("Left Spk", NULL), SND_SOC_DAPM_SPK("Left Spk", NULL),
SND_SOC_DAPM_SPK("Right Spk", NULL), SND_SOC_DAPM_SPK("Right Spk", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL),
SND_SOC_DAPM_SPK("DP", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL),
SND_SOC_DAPM_SPK("HDMI", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL),
SND_SOC_DAPM_SPK("HDMI3", NULL),
}; };
@ -91,20 +94,22 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
{ "IN1N", NULL, "Headset Mic" }, { "IN1N", NULL, "Headset Mic" },
{ "DMic", NULL, "SoC DMIC" }, { "DMic", NULL, "SoC DMIC" },
{ "HDMI", NULL, "hif5 Output" },
{ "DP", NULL, "hif6 Output" },
/* CODEC BE connections */ /* CODEC BE connections */
{ "Left HiFi Playback", NULL, "ssp0 Tx" }, { "Left HiFi Playback", NULL, "ssp0 Tx" },
{ "Right HiFi Playback", NULL, "ssp0 Tx" }, { "Right HiFi Playback", NULL, "ssp0 Tx" },
{ "ssp0 Tx", NULL, "codec0_out" }, { "ssp0 Tx", NULL, "spk_out" },
{ "AIF Playback", NULL, "ssp1 Tx" }, { "AIF Playback", NULL, "ssp1 Tx" },
{ "ssp1 Tx", NULL, "codec1_out" }, { "ssp1 Tx", NULL, "hs_out" },
{ "codec0_in", NULL, "ssp1 Rx" }, { "hs_in", NULL, "ssp1 Rx" },
{ "ssp1 Rx", NULL, "AIF Capture" }, { "ssp1 Rx", NULL, "AIF Capture" },
/* IV feedback path */
{ "codec0_fb_in", NULL, "ssp0 Rx"},
{ "ssp0 Rx", NULL, "Left HiFi Capture" },
{ "ssp0 Rx", NULL, "Right HiFi Capture" },
/* DMIC */ /* DMIC */
{ "dmic01_hifi", NULL, "DMIC01 Rx" }, { "dmic01_hifi", NULL, "DMIC01 Rx" },
{ "DMIC01 Rx", NULL, "DMIC AIF" }, { "DMIC01 Rx", NULL, "DMIC AIF" },
@ -117,6 +122,49 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
{ "iDisp1 Tx", NULL, "iDisp1_out"}, { "iDisp1 Tx", NULL, "iDisp1_out"},
}; };
enum {
KBL_DPCM_AUDIO_5663_PB = 0,
KBL_DPCM_AUDIO_5663_CP,
KBL_DPCM_AUDIO_5663_HDMI1_PB,
KBL_DPCM_AUDIO_5663_HDMI2_PB,
};
static const struct snd_kcontrol_new kabylake_5663_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
};
static const struct snd_soc_dapm_widget kabylake_5663_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_SPK("DP", NULL),
SND_SOC_DAPM_SPK("HDMI", NULL),
};
static const struct snd_soc_dapm_route kabylake_5663_map[] = {
{ "Headphone Jack", NULL, "HPOL" },
{ "Headphone Jack", NULL, "HPOR" },
/* other jacks */
{ "IN1P", NULL, "Headset Mic" },
{ "IN1N", NULL, "Headset Mic" },
{ "HDMI", NULL, "hif5 Output" },
{ "DP", NULL, "hif6 Output" },
/* CODEC BE connections */
{ "AIF Playback", NULL, "ssp1 Tx" },
{ "ssp1 Tx", NULL, "codec1_out" },
{ "codec0_in", NULL, "ssp1 Rx" },
{ "ssp1 Rx", NULL, "AIF Capture" },
{ "hifi2", NULL, "iDisp2 Tx"},
{ "iDisp2 Tx", NULL, "iDisp2_out"},
{ "hifi1", NULL, "iDisp1 Tx"},
{ "iDisp1 Tx", NULL, "iDisp1_out"},
};
static struct snd_soc_codec_conf max98927_codec_conf[] = { static struct snd_soc_codec_conf max98927_codec_conf[] = {
{ {
.dev_name = MAXIM_DEV0_NAME, .dev_name = MAXIM_DEV0_NAME,
@ -165,7 +213,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
* Headset buttons map to the google Reference headset. * Headset buttons map to the google Reference headset.
* These can be configured by userspace. * These can be configured by userspace.
*/ */
ret = snd_soc_card_jack_new(&kabylake_audio_card, "Headset Jack", ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset, SND_JACK_BTN_2 | SND_JACK_BTN_3, &ctx->kabylake_headset,
NULL, 0); NULL, 0);
@ -173,8 +221,18 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret);
return ret; return ret;
} }
rt5663_set_jack_detect(codec, &ctx->kabylake_headset); rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
return ret;
}
static int kabylake_rt5663_max98927_codec_init(struct snd_soc_pcm_runtime *rtd)
{
int ret;
ret = kabylake_rt5663_codec_init(rtd);
if (ret)
return ret;
ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
if (ret) { if (ret) {
dev_err(rtd->dev, "SoC DMIC ignore suspend failed %d\n", ret); dev_err(rtd->dev, "SoC DMIC ignore suspend failed %d\n", ret);
@ -184,7 +242,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret; return ret;
} }
static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device)
{ {
struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *dai = rtd->codec_dai; struct snd_soc_dai *dai = rtd->codec_dai;
@ -194,7 +252,7 @@ static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
if (!pcm) if (!pcm)
return -ENOMEM; return -ENOMEM;
pcm->device = KBL_DPCM_AUDIO_HDMI1_PB; pcm->device = device;
pcm->codec_dai = dai; pcm->codec_dai = dai;
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
@ -202,47 +260,36 @@ static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
return 0; return 0;
} }
static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
{
return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB);
}
static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB);
struct snd_soc_dai *dai = rtd->codec_dai;
struct kbl_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
pcm->device = KBL_DPCM_AUDIO_HDMI2_PB;
pcm->codec_dai = dai;
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
return 0;
} }
static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB);
struct snd_soc_dai *dai = rtd->codec_dai; }
struct kbl_hdmi_pcm *pcm;
pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); static int kabylake_5663_hdmi1_init(struct snd_soc_pcm_runtime *rtd)
if (!pcm) {
return -ENOMEM; return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI1_PB);
}
pcm->device = KBL_DPCM_AUDIO_HDMI3_PB; static int kabylake_5663_hdmi2_init(struct snd_soc_pcm_runtime *rtd)
pcm->codec_dai = dai; {
return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI2_PB);
list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
return 0;
} }
static unsigned int rates[] = { static unsigned int rates[] = {
48000, 48000,
}; };
static struct snd_pcm_hw_constraint_list constraints_rates = { static const struct snd_pcm_hw_constraint_list constraints_rates = {
.count = ARRAY_SIZE(rates), .count = ARRAY_SIZE(rates),
.list = rates, .list = rates,
.mask = 0, .mask = 0,
@ -252,7 +299,7 @@ static unsigned int channels[] = {
2, 2,
}; };
static struct snd_pcm_hw_constraint_list constraints_channels = { static const struct snd_pcm_hw_constraint_list constraints_channels = {
.count = ARRAY_SIZE(channels), .count = ARRAY_SIZE(channels),
.list = channels, .list = channels,
.mask = 0, .mask = 0,
@ -312,11 +359,13 @@ static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret; int ret;
/* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
rt5663_sel_asrc_clk_src(codec_dai->codec,
RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
RT5663_CLK_SEL_I2S1_ASRC);
ret = snd_soc_dai_set_sysclk(codec_dai, ret = snd_soc_dai_set_sysclk(codec_dai,
RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN);
/* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */
rt5663_sel_asrc_clk_src(codec_dai->codec, RT5663_DA_STEREO_FILTER, 1);
if (ret < 0) if (ret < 0)
dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
@ -381,7 +430,7 @@ static unsigned int rates_16000[] = {
16000, 16000,
}; };
static struct snd_pcm_hw_constraint_list constraints_16000 = { static const struct snd_pcm_hw_constraint_list constraints_16000 = {
.count = ARRAY_SIZE(rates_16000), .count = ARRAY_SIZE(rates_16000),
.list = rates_16000, .list = rates_16000,
}; };
@ -443,6 +492,28 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.dpcm_capture = 1, .dpcm_capture = 1,
.ops = &kabylake_rt5663_fe_ops, .ops = &kabylake_rt5663_fe_ops,
}, },
[KBL_DPCM_AUDIO_HS_PB] = {
.name = "Kbl Audio Headset Playback",
.stream_name = "Headset Audio",
.cpu_dai_name = "System Pin2",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
.nonatomic = 1,
.dynamic = 1,
},
[KBL_DPCM_AUDIO_ECHO_REF_CP] = {
.name = "Kbl Audio Echo Reference cap",
.stream_name = "Echoreference Capture",
.cpu_dai_name = "Echoref Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
.init = NULL,
.capture_only = 1,
.nonatomic = 1,
},
[KBL_DPCM_AUDIO_REF_CP] = { [KBL_DPCM_AUDIO_REF_CP] = {
.name = "Kbl Audio Reference cap", .name = "Kbl Audio Reference cap",
.stream_name = "Wake on Voice", .stream_name = "Wake on Voice",
@ -538,7 +609,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.no_pcm = 1, .no_pcm = 1,
.codec_name = "i2c-10EC5663:00", .codec_name = "i2c-10EC5663:00",
.codec_dai_name = KBL_REALTEK_CODEC_DAI, .codec_dai_name = KBL_REALTEK_CODEC_DAI,
.init = kabylake_rt5663_codec_init, .init = kabylake_rt5663_max98927_codec_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAIFMT_CBS_CFS,
.ignore_pmdown_time = 1, .ignore_pmdown_time = 1,
@ -594,15 +665,119 @@ static struct snd_soc_dai_link kabylake_dais[] = {
}, },
}; };
static struct snd_soc_dai_link kabylake_5663_dais[] = {
/* Front End DAI links */
[KBL_DPCM_AUDIO_5663_PB] = {
.name = "Kbl Audio Port",
.stream_name = "Audio",
.cpu_dai_name = "System Pin",
.platform_name = "0000:00:1f.3",
.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_playback = 1,
.ops = &kabylake_rt5663_fe_ops,
},
[KBL_DPCM_AUDIO_5663_CP] = {
.name = "Kbl Audio Capture Port",
.stream_name = "Audio Record",
.cpu_dai_name = "System Pin",
.platform_name = "0000:00:1f.3",
.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 = &kabylake_rt5663_fe_ops,
},
[KBL_DPCM_AUDIO_5663_HDMI1_PB] = {
.name = "Kbl 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:1f.3",
.dpcm_playback = 1,
.init = NULL,
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.nonatomic = 1,
.dynamic = 1,
},
[KBL_DPCM_AUDIO_5663_HDMI2_PB] = {
.name = "Kbl 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:1f.3",
.dpcm_playback = 1,
.init = NULL,
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.nonatomic = 1,
.dynamic = 1,
},
/* Back End DAI links */
{
/* SSP1 - Codec */
.name = "SSP1-Codec",
.id = 0,
.cpu_dai_name = "SSP1 Pin",
.platform_name = "0000:00:1f.3",
.no_pcm = 1,
.codec_name = "i2c-10EC5663:00",
.codec_dai_name = KBL_REALTEK_CODEC_DAI,
.init = kabylake_rt5663_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 = kabylake_ssp_fixup,
.ops = &kabylake_rt5663_ops,
.dpcm_playback = 1,
.dpcm_capture = 1,
},
{
.name = "iDisp1",
.id = 1,
.cpu_dai_name = "iDisp1 Pin",
.codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi1",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
.init = kabylake_5663_hdmi1_init,
.no_pcm = 1,
},
{
.name = "iDisp2",
.id = 2,
.cpu_dai_name = "iDisp2 Pin",
.codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi2",
.platform_name = "0000:00:1f.3",
.init = kabylake_5663_hdmi2_init,
.dpcm_playback = 1,
.no_pcm = 1,
},
};
#define NAME_SIZE 32 #define NAME_SIZE 32
static int kabylake_card_late_probe(struct snd_soc_card *card) static int kabylake_card_late_probe(struct snd_soc_card *card)
{ {
struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card); struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card);
struct kbl_hdmi_pcm *pcm; struct kbl_hdmi_pcm *pcm;
struct snd_soc_codec *codec = NULL;
int err, i = 0; int err, i = 0;
char jack_name[NAME_SIZE]; char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
codec = pcm->codec_dai->codec;
snprintf(jack_name, sizeof(jack_name), snprintf(jack_name, sizeof(jack_name),
"HDMI/DP, pcm=%d Jack", pcm->device); "HDMI/DP, pcm=%d Jack", pcm->device);
err = snd_soc_card_jack_new(card, jack_name, err = snd_soc_card_jack_new(card, jack_name,
@ -620,11 +795,14 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
i++; i++;
} }
return 0; if (!codec)
return -EINVAL;
return hdac_hdmi_jack_port_init(codec, &card->dapm);
} }
/* kabylake audio machine driver for SPT + RT5663 */ /* kabylake audio machine driver for SPT + RT5663 */
static struct snd_soc_card kabylake_audio_card = { static struct snd_soc_card kabylake_audio_card_rt5663_m98927 = {
.name = "kblrt5663max", .name = "kblrt5663max",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.dai_link = kabylake_dais, .dai_link = kabylake_dais,
@ -641,6 +819,22 @@ static struct snd_soc_card kabylake_audio_card = {
.late_probe = kabylake_card_late_probe, .late_probe = kabylake_card_late_probe,
}; };
/* kabylake audio machine driver for RT5663 */
static struct snd_soc_card kabylake_audio_card_rt5663 = {
.name = "kblrt5663",
.owner = THIS_MODULE,
.dai_link = kabylake_5663_dais,
.num_links = ARRAY_SIZE(kabylake_5663_dais),
.controls = kabylake_5663_controls,
.num_controls = ARRAY_SIZE(kabylake_5663_controls),
.dapm_widgets = kabylake_5663_widgets,
.num_dapm_widgets = ARRAY_SIZE(kabylake_5663_widgets),
.dapm_routes = kabylake_5663_map,
.num_dapm_routes = ARRAY_SIZE(kabylake_5663_map),
.fully_routed = true,
.late_probe = kabylake_card_late_probe,
};
static int kabylake_audio_probe(struct platform_device *pdev) static int kabylake_audio_probe(struct platform_device *pdev)
{ {
struct kbl_rt5663_private *ctx; struct kbl_rt5663_private *ctx;
@ -652,19 +846,30 @@ static int kabylake_audio_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&ctx->hdmi_pcm_list); INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
kabylake_audio_card.dev = &pdev->dev; kabylake_audio_card =
snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); (struct snd_soc_card *)pdev->id_entry->driver_data;
kabylake_audio_card->dev = &pdev->dev;
snd_soc_card_set_drvdata(kabylake_audio_card, ctx);
pdata = dev_get_drvdata(&pdev->dev); pdata = dev_get_drvdata(&pdev->dev);
if (pdata) if (pdata)
dmic_constraints = pdata->dmic_num == 2 ? dmic_constraints = pdata->dmic_num == 2 ?
&constraints_dmic_2ch : &constraints_dmic_channels; &constraints_dmic_2ch : &constraints_dmic_channels;
return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card); return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card);
} }
static const struct platform_device_id kbl_board_ids[] = { static const struct platform_device_id kbl_board_ids[] = {
{ .name = "kbl_rt5663_m98927" }, {
.name = "kbl_rt5663",
.driver_data = (kernel_ulong_t)&kabylake_audio_card_rt5663,
},
{
.name = "kbl_rt5663_m98927",
.driver_data =
(kernel_ulong_t)&kabylake_audio_card_rt5663_m98927,
},
{ } { }
}; };
@ -684,4 +889,5 @@ MODULE_DESCRIPTION("Audio Machine driver-RT5663 & MAX98927 in I2S mode");
MODULE_AUTHOR("Naveen M <naveen.m@intel.com>"); MODULE_AUTHOR("Naveen M <naveen.m@intel.com>");
MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:kbl_rt5663");
MODULE_ALIAS("platform:kbl_rt5663_m98927"); MODULE_ALIAS("platform:kbl_rt5663_m98927");

Просмотреть файл

@ -18,6 +18,7 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/input.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <sound/core.h> #include <sound/core.h>
@ -62,7 +63,10 @@ struct kbl_codec_private {
enum { enum {
KBL_DPCM_AUDIO_PB = 0, KBL_DPCM_AUDIO_PB = 0,
KBL_DPCM_AUDIO_CP, KBL_DPCM_AUDIO_CP,
KBL_DPCM_AUDIO_HS_PB,
KBL_DPCM_AUDIO_ECHO_REF_CP,
KBL_DPCM_AUDIO_DMIC_CP, KBL_DPCM_AUDIO_DMIC_CP,
KBL_DPCM_AUDIO_RT5514_DSP,
KBL_DPCM_AUDIO_HDMI1_PB, KBL_DPCM_AUDIO_HDMI1_PB,
KBL_DPCM_AUDIO_HDMI2_PB, KBL_DPCM_AUDIO_HDMI2_PB,
}; };
@ -81,8 +85,8 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = {
SND_SOC_DAPM_SPK("Left Spk", NULL), SND_SOC_DAPM_SPK("Left Spk", NULL),
SND_SOC_DAPM_SPK("Right Spk", NULL), SND_SOC_DAPM_SPK("Right Spk", NULL),
SND_SOC_DAPM_MIC("DMIC", NULL), SND_SOC_DAPM_MIC("DMIC", NULL),
SND_SOC_DAPM_SPK("DP", NULL), SND_SOC_DAPM_SPK("HDMI1", NULL),
SND_SOC_DAPM_SPK("HDMI", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL),
}; };
@ -99,23 +103,25 @@ static const struct snd_soc_dapm_route kabylake_map[] = {
{ "IN1P", NULL, "Headset Mic" }, { "IN1P", NULL, "Headset Mic" },
{ "IN1N", NULL, "Headset Mic" }, { "IN1N", NULL, "Headset Mic" },
{ "HDMI", NULL, "hif5 Output" },
{ "DP", NULL, "hif6 Output" },
/* CODEC BE connections */ /* CODEC BE connections */
{ "Left HiFi Playback", NULL, "ssp0 Tx" }, { "Left HiFi Playback", NULL, "ssp0 Tx" },
{ "Right HiFi Playback", NULL, "ssp0 Tx" }, { "Right HiFi Playback", NULL, "ssp0 Tx" },
{ "ssp0 Tx", NULL, "codec0_out" }, { "ssp0 Tx", NULL, "spk_out" },
{ "AIF Playback", NULL, "ssp1 Tx" }, { "AIF Playback", NULL, "ssp1 Tx" },
{ "ssp1 Tx", NULL, "codec1_out" }, { "ssp1 Tx", NULL, "hs_out" },
{ "codec0_in", NULL, "ssp1 Rx" }, { "hs_in", NULL, "ssp1 Rx" },
{ "ssp1 Rx", NULL, "AIF Capture" }, { "ssp1 Rx", NULL, "AIF Capture" },
{ "codec1_in", NULL, "ssp0 Rx" }, { "codec1_in", NULL, "ssp0 Rx" },
{ "ssp0 Rx", NULL, "AIF1 Capture" }, { "ssp0 Rx", NULL, "AIF1 Capture" },
/* IV feedback path */
{ "codec0_fb_in", NULL, "ssp0 Rx"},
{ "ssp0 Rx", NULL, "Left HiFi Capture" },
{ "ssp0 Rx", NULL, "Right HiFi Capture" },
/* DMIC */ /* DMIC */
{ "DMIC1L", NULL, "DMIC" }, { "DMIC1L", NULL, "DMIC" },
{ "DMIC1R", NULL, "DMIC" }, { "DMIC1R", NULL, "DMIC" },
@ -173,6 +179,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
int ret; int ret;
struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_codec *codec = rtd->codec; struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_jack *jack;
/* /*
* Headset buttons map to the google Reference headset. * Headset buttons map to the google Reference headset.
@ -187,6 +194,12 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret; return ret;
} }
jack = &ctx->kabylake_headset;
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
rt5663_set_jack_detect(codec, &ctx->kabylake_headset); rt5663_set_jack_detect(codec, &ctx->kabylake_headset);
ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC"); ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC");
@ -358,11 +371,18 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream,
return ret; return ret;
} }
} }
if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME) || if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) {
!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16);
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF0, 3, 8, 16);
if (ret < 0) { if (ret < 0) {
dev_err(rtd->dev, "set TDM slot err:%d\n", ret); dev_err(rtd->dev, "DEV0 TDM slot err:%d\n", ret);
return ret;
}
}
if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) {
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16);
if (ret < 0) {
dev_err(rtd->dev, "DEV1 TDM slot err:%d\n", ret);
return ret; return ret;
} }
} }
@ -442,6 +462,36 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.dpcm_capture = 1, .dpcm_capture = 1,
.ops = &kabylake_rt5663_fe_ops, .ops = &kabylake_rt5663_fe_ops,
}, },
[KBL_DPCM_AUDIO_HS_PB] = {
.name = "Kbl Audio Headset Playback",
.stream_name = "Headset Audio",
.cpu_dai_name = "System Pin2",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
.nonatomic = 1,
.dynamic = 1,
},
[KBL_DPCM_AUDIO_ECHO_REF_CP] = {
.name = "Kbl Audio Echo Reference cap",
.stream_name = "Echoreference Capture",
.cpu_dai_name = "Echoref Pin",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3",
.init = NULL,
.capture_only = 1,
.nonatomic = 1,
},
[KBL_DPCM_AUDIO_RT5514_DSP] = {
.name = "rt5514 dsp",
.stream_name = "Wake on Voice",
.cpu_dai_name = "spi-PRP0001:00",
.platform_name = "spi-PRP0001:00",
.codec_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai",
},
[KBL_DPCM_AUDIO_DMIC_CP] = { [KBL_DPCM_AUDIO_DMIC_CP] = {
.name = "Kbl Audio DMIC cap", .name = "Kbl Audio DMIC cap",
.stream_name = "dmiccap", .stream_name = "dmiccap",
@ -548,10 +598,12 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
{ {
struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card);
struct kbl_hdmi_pcm *pcm; struct kbl_hdmi_pcm *pcm;
struct snd_soc_codec *codec = NULL;
int err, i = 0; int err, i = 0;
char jack_name[NAME_SIZE]; char jack_name[NAME_SIZE];
list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
codec = pcm->codec_dai->codec;
err = snd_soc_card_jack_new(card, jack_name, err = snd_soc_card_jack_new(card, jack_name,
SND_JACK_AVOUT, &ctx->kabylake_hdmi[i], SND_JACK_AVOUT, &ctx->kabylake_hdmi[i],
NULL, 0); NULL, 0);
@ -565,7 +617,10 @@ static int kabylake_card_late_probe(struct snd_soc_card *card)
i++; i++;
} }
return 0; if (!codec)
return -EINVAL;
return hdac_hdmi_jack_port_init(codec, &card->dapm);
} }
/* /*

Просмотреть файл

@ -376,10 +376,8 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
/* audio interrupt base of SRAM location where /* audio interrupt base of SRAM location where
* interrupts are stored by System FW */ * interrupts are stored by System FW */
mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC); mc_drv_ctx = devm_kzalloc(&pdev->dev, sizeof(*mc_drv_ctx), GFP_ATOMIC);
if (!mc_drv_ctx) { if (!mc_drv_ctx)
pr_err("allocation failed\n");
return -ENOMEM; return -ENOMEM;
}
irq_mem = platform_get_resource_byname( irq_mem = platform_get_resource_byname(
pdev, IORESOURCE_MEM, "IRQ_BASE"); pdev, IORESOURCE_MEM, "IRQ_BASE");

Просмотреть файл

@ -1135,7 +1135,7 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform)
return 0; return 0;
} }
static struct snd_soc_platform_driver hsw_soc_platform = { static const struct snd_soc_platform_driver hsw_soc_platform = {
.probe = hsw_pcm_probe, .probe = hsw_pcm_probe,
.remove = hsw_pcm_remove, .remove = hsw_pcm_remove,
.ops = &hsw_pcm_ops, .ops = &hsw_pcm_ops,

Просмотреть файл

@ -8,7 +8,8 @@ endif
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o
# Skylake IPC Support # Skylake IPC Support
snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \ snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o \
skl-sst.o bxt-sst.o skl-sst-utils.o skl-sst-cldma.o skl-sst.o bxt-sst.o cnl-sst.o \
skl-sst-utils.o
obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o

Просмотреть файл

@ -530,7 +530,7 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
return 0; return 0;
} }
static struct skl_dsp_fw_ops bxt_fw_ops = { static const struct skl_dsp_fw_ops bxt_fw_ops = {
.set_state_D0 = bxt_set_dsp_D0, .set_state_D0 = bxt_set_dsp_D0,
.set_state_D3 = bxt_set_dsp_D3, .set_state_D3 = bxt_set_dsp_D3,
.set_state_D0i3 = bxt_schedule_dsp_D0i3, .set_state_D0i3 = bxt_schedule_dsp_D0i3,
@ -581,10 +581,15 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
ret = skl_ipc_init(dev, skl);
if (ret) {
skl_dsp_free(sst);
return ret;
}
/* set the D0i3 check */ /* set the D0i3 check */
skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0; skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0;
skl->cores.count = 2;
skl->boot_complete = false; skl->boot_complete = false;
init_waitqueue_head(&skl->boot_wait); init_waitqueue_head(&skl->boot_wait);
INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3); INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
@ -629,11 +634,6 @@ void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
release_firmware(ctx->dsp->fw); release_firmware(ctx->dsp->fw);
skl_freeup_uuid_list(ctx); skl_freeup_uuid_list(ctx);
skl_ipc_free(&ctx->ipc); skl_ipc_free(&ctx->ipc);
ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
if (ctx->dsp->addr.lpe)
iounmap(ctx->dsp->addr.lpe);
ctx->dsp->ops->free(ctx->dsp); ctx->dsp->ops->free(ctx->dsp);
} }
EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup); EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup);

Просмотреть файл

@ -0,0 +1,274 @@
/*
* cnl-sst-dsp.c - CNL SST library generic function
*
* Copyright (C) 2016-17, Intel Corporation.
* Author: Guneshwor Singh <guneshwor.o.singh@intel.com>
*
* Modified from:
* SKL SST library generic function
* Copyright (C) 2014-15, Intel Corporation.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* 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 "../common/sst-dsp.h"
#include "../common/sst-ipc.h"
#include "../common/sst-dsp-priv.h"
#include "cnl-sst-dsp.h"
/* various timeout values */
#define CNL_DSP_PU_TO 50
#define CNL_DSP_PD_TO 50
#define CNL_DSP_RESET_TO 50
static int
cnl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
{
/* update bits */
sst_dsp_shim_update_bits_unlocked(ctx,
CNL_ADSP_REG_ADSPCS, CNL_ADSPCS_CRST(core_mask),
CNL_ADSPCS_CRST(core_mask));
/* poll with timeout to check if operation successful */
return sst_dsp_register_poll(ctx,
CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_CRST(core_mask),
CNL_ADSPCS_CRST(core_mask),
CNL_DSP_RESET_TO,
"Set reset");
}
static int
cnl_dsp_core_unset_reset_state(struct sst_dsp *ctx, unsigned int core_mask)
{
/* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_CRST(core_mask), 0);
/* poll with timeout to check if operation successful */
return sst_dsp_register_poll(ctx,
CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_CRST(core_mask),
0,
CNL_DSP_RESET_TO,
"Unset reset");
}
static bool is_cnl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask)
{
int val;
bool is_enable;
val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPCS);
is_enable = (val & CNL_ADSPCS_CPA(core_mask)) &&
(val & CNL_ADSPCS_SPA(core_mask)) &&
!(val & CNL_ADSPCS_CRST(core_mask)) &&
!(val & CNL_ADSPCS_CSTALL(core_mask));
dev_dbg(ctx->dev, "DSP core(s) enabled? %d: core_mask %#x\n",
is_enable, core_mask);
return is_enable;
}
static int cnl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask)
{
/* stall core */
sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_CSTALL(core_mask),
CNL_ADSPCS_CSTALL(core_mask));
/* set reset state */
return cnl_dsp_core_set_reset_state(ctx, core_mask);
}
static int cnl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask)
{
int ret;
/* unset reset state */
ret = cnl_dsp_core_unset_reset_state(ctx, core_mask);
if (ret < 0)
return ret;
/* run core */
sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_CSTALL(core_mask), 0);
if (!is_cnl_dsp_core_enable(ctx, core_mask)) {
cnl_dsp_reset_core(ctx, core_mask);
dev_err(ctx->dev, "DSP core mask %#x enable failed\n",
core_mask);
ret = -EIO;
}
return ret;
}
static int cnl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask)
{
/* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_SPA(core_mask),
CNL_ADSPCS_SPA(core_mask));
/* poll with timeout to check if operation successful */
return sst_dsp_register_poll(ctx, CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_CPA(core_mask),
CNL_ADSPCS_CPA(core_mask),
CNL_DSP_PU_TO,
"Power up");
}
static int cnl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask)
{
/* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_SPA(core_mask), 0);
/* poll with timeout to check if operation successful */
return sst_dsp_register_poll(ctx,
CNL_ADSP_REG_ADSPCS,
CNL_ADSPCS_CPA(core_mask),
0,
CNL_DSP_PD_TO,
"Power down");
}
int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask)
{
int ret;
/* power up */
ret = cnl_dsp_core_power_up(ctx, core_mask);
if (ret < 0) {
dev_dbg(ctx->dev, "DSP core mask %#x power up failed",
core_mask);
return ret;
}
return cnl_dsp_start_core(ctx, core_mask);
}
int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask)
{
int ret;
ret = cnl_dsp_reset_core(ctx, core_mask);
if (ret < 0) {
dev_err(ctx->dev, "DSP core mask %#x reset failed\n",
core_mask);
return ret;
}
/* power down core*/
ret = cnl_dsp_core_power_down(ctx, core_mask);
if (ret < 0) {
dev_err(ctx->dev, "DSP core mask %#x power down failed\n",
core_mask);
return ret;
}
if (is_cnl_dsp_core_enable(ctx, core_mask)) {
dev_err(ctx->dev, "DSP core mask %#x disable failed\n",
core_mask);
ret = -EIO;
}
return ret;
}
irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id)
{
struct sst_dsp *ctx = dev_id;
u32 val;
irqreturn_t ret = IRQ_NONE;
spin_lock(&ctx->spinlock);
val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS);
ctx->intr_status = val;
if (val == 0xffffffff) {
spin_unlock(&ctx->spinlock);
return IRQ_NONE;
}
if (val & CNL_ADSPIS_IPC) {
cnl_ipc_int_disable(ctx);
ret = IRQ_WAKE_THREAD;
}
spin_unlock(&ctx->spinlock);
return ret;
}
void cnl_dsp_free(struct sst_dsp *dsp)
{
cnl_ipc_int_disable(dsp);
free_irq(dsp->irq, dsp);
cnl_ipc_op_int_disable(dsp);
cnl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK);
}
EXPORT_SYMBOL_GPL(cnl_dsp_free);
void cnl_ipc_int_enable(struct sst_dsp *ctx)
{
sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_ADSPIC,
CNL_ADSPIC_IPC, CNL_ADSPIC_IPC);
}
void cnl_ipc_int_disable(struct sst_dsp *ctx)
{
sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPIC,
CNL_ADSPIC_IPC, 0);
}
void cnl_ipc_op_int_enable(struct sst_dsp *ctx)
{
/* enable IPC DONE interrupt */
sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
CNL_ADSP_REG_HIPCCTL_DONE,
CNL_ADSP_REG_HIPCCTL_DONE);
/* enable IPC BUSY interrupt */
sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
CNL_ADSP_REG_HIPCCTL_BUSY,
CNL_ADSP_REG_HIPCCTL_BUSY);
}
void cnl_ipc_op_int_disable(struct sst_dsp *ctx)
{
/* disable IPC DONE interrupt */
sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
CNL_ADSP_REG_HIPCCTL_DONE, 0);
/* disable IPC BUSY interrupt */
sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL,
CNL_ADSP_REG_HIPCCTL_BUSY, 0);
}
bool cnl_ipc_int_status(struct sst_dsp *ctx)
{
return sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS) &
CNL_ADSPIS_IPC;
}
void cnl_ipc_free(struct sst_generic_ipc *ipc)
{
cnl_ipc_op_int_disable(ipc->dsp);
sst_ipc_fini(ipc);
}

Просмотреть файл

@ -0,0 +1,112 @@
/*
* Cannonlake SST DSP Support
*
* Copyright (C) 2016-17, Intel Corporation.
*
* 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.
*/
#ifndef __CNL_SST_DSP_H__
#define __CNL_SST_DSP_H__
struct sst_dsp;
struct skl_sst;
struct sst_dsp_device;
struct sst_generic_ipc;
/* Intel HD Audio General DSP Registers */
#define CNL_ADSP_GEN_BASE 0x0
#define CNL_ADSP_REG_ADSPCS (CNL_ADSP_GEN_BASE + 0x04)
#define CNL_ADSP_REG_ADSPIC (CNL_ADSP_GEN_BASE + 0x08)
#define CNL_ADSP_REG_ADSPIS (CNL_ADSP_GEN_BASE + 0x0c)
/* Intel HD Audio Inter-Processor Communication Registers */
#define CNL_ADSP_IPC_BASE 0xc0
#define CNL_ADSP_REG_HIPCTDR (CNL_ADSP_IPC_BASE + 0x00)
#define CNL_ADSP_REG_HIPCTDA (CNL_ADSP_IPC_BASE + 0x04)
#define CNL_ADSP_REG_HIPCTDD (CNL_ADSP_IPC_BASE + 0x08)
#define CNL_ADSP_REG_HIPCIDR (CNL_ADSP_IPC_BASE + 0x10)
#define CNL_ADSP_REG_HIPCIDA (CNL_ADSP_IPC_BASE + 0x14)
#define CNL_ADSP_REG_HIPCIDD (CNL_ADSP_IPC_BASE + 0x18)
#define CNL_ADSP_REG_HIPCCTL (CNL_ADSP_IPC_BASE + 0x28)
/* HIPCTDR */
#define CNL_ADSP_REG_HIPCTDR_BUSY BIT(31)
/* HIPCTDA */
#define CNL_ADSP_REG_HIPCTDA_DONE BIT(31)
/* HIPCIDR */
#define CNL_ADSP_REG_HIPCIDR_BUSY BIT(31)
/* HIPCIDA */
#define CNL_ADSP_REG_HIPCIDA_DONE BIT(31)
/* CNL HIPCCTL */
#define CNL_ADSP_REG_HIPCCTL_DONE BIT(1)
#define CNL_ADSP_REG_HIPCCTL_BUSY BIT(0)
/* CNL HIPCT */
#define CNL_ADSP_REG_HIPCT_BUSY BIT(31)
/* Intel HD Audio SRAM Window 1 */
#define CNL_ADSP_SRAM1_BASE 0xa0000
#define CNL_ADSP_MMIO_LEN 0x10000
#define CNL_ADSP_W0_STAT_SZ 0x1000
#define CNL_ADSP_W0_UP_SZ 0x1000
#define CNL_ADSP_W1_SZ 0x1000
#define CNL_FW_STS_MASK 0xf
#define CNL_ADSPIC_IPC 0x1
#define CNL_ADSPIS_IPC 0x1
#define CNL_DSP_CORES 4
#define CNL_DSP_CORES_MASK ((1 << CNL_DSP_CORES) - 1)
/* core reset - asserted high */
#define CNL_ADSPCS_CRST_SHIFT 0
#define CNL_ADSPCS_CRST(x) (x << CNL_ADSPCS_CRST_SHIFT)
/* core run/stall - when set to 1 core is stalled */
#define CNL_ADSPCS_CSTALL_SHIFT 8
#define CNL_ADSPCS_CSTALL(x) (x << CNL_ADSPCS_CSTALL_SHIFT)
/* set power active - when set to 1 turn core on */
#define CNL_ADSPCS_SPA_SHIFT 16
#define CNL_ADSPCS_SPA(x) (x << CNL_ADSPCS_SPA_SHIFT)
/* current power active - power status of cores, set by hardware */
#define CNL_ADSPCS_CPA_SHIFT 24
#define CNL_ADSPCS_CPA(x) (x << CNL_ADSPCS_CPA_SHIFT)
int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core);
int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core);
irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id);
void cnl_dsp_free(struct sst_dsp *dsp);
void cnl_ipc_int_enable(struct sst_dsp *ctx);
void cnl_ipc_int_disable(struct sst_dsp *ctx);
void cnl_ipc_op_int_enable(struct sst_dsp *ctx);
void cnl_ipc_op_int_disable(struct sst_dsp *ctx);
bool cnl_ipc_int_status(struct sst_dsp *ctx);
void cnl_ipc_free(struct sst_generic_ipc *ipc);
int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
struct skl_sst **dsp);
int cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx);
void cnl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx);
#endif /*__CNL_SST_DSP_H__*/

Просмотреть файл

@ -0,0 +1,497 @@
/*
* cnl-sst.c - DSP library functions for CNL platform
*
* Copyright (C) 2016-17, Intel Corporation.
*
* Author: Guneshwor Singh <guneshwor.o.singh@intel.com>
*
* Modified from:
* HDA DSP library functions for SKL platform
* Copyright (C) 2014-15, Intel Corporation.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* 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/module.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/device.h>
#include "../common/sst-dsp.h"
#include "../common/sst-dsp-priv.h"
#include "../common/sst-ipc.h"
#include "cnl-sst-dsp.h"
#include "skl-sst-dsp.h"
#include "skl-sst-ipc.h"
#define CNL_FW_ROM_INIT 0x1
#define CNL_FW_INIT 0x5
#define CNL_IPC_PURGE 0x01004000
#define CNL_INIT_TIMEOUT 300
#define CNL_BASEFW_TIMEOUT 3000
#define CNL_ADSP_SRAM0_BASE 0x80000
/* Firmware status window */
#define CNL_ADSP_FW_STATUS CNL_ADSP_SRAM0_BASE
#define CNL_ADSP_ERROR_CODE (CNL_ADSP_FW_STATUS + 0x4)
#define CNL_INSTANCE_ID 0
#define CNL_BASE_FW_MODULE_ID 0
#define CNL_ADSP_FW_HDR_OFFSET 0x2000
#define CNL_ROM_CTRL_DMA_ID 0x9
static int cnl_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize)
{
int ret, stream_tag;
stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab);
if (stream_tag <= 0) {
dev_err(ctx->dev, "dma prepare failed: 0%#x\n", stream_tag);
return stream_tag;
}
ctx->dsp_ops.stream_tag = stream_tag;
memcpy(ctx->dmab.area, fwdata, fwsize);
/* purge FW request */
sst_dsp_shim_write(ctx, CNL_ADSP_REG_HIPCIDR,
CNL_ADSP_REG_HIPCIDR_BUSY | (CNL_IPC_PURGE |
((stream_tag - 1) << CNL_ROM_CTRL_DMA_ID)));
ret = cnl_dsp_enable_core(ctx, SKL_DSP_CORE0_MASK);
if (ret < 0) {
dev_err(ctx->dev, "dsp boot core failed ret: %d\n", ret);
ret = -EIO;
goto base_fw_load_failed;
}
/* enable interrupt */
cnl_ipc_int_enable(ctx);
cnl_ipc_op_int_enable(ctx);
ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK,
CNL_FW_ROM_INIT, CNL_INIT_TIMEOUT,
"rom load");
if (ret < 0) {
dev_err(ctx->dev, "rom init timeout, ret: %d\n", ret);
goto base_fw_load_failed;
}
return 0;
base_fw_load_failed:
ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag);
cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
return ret;
}
static int sst_transfer_fw_host_dma(struct sst_dsp *ctx)
{
int ret;
ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag);
ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK,
CNL_FW_INIT, CNL_BASEFW_TIMEOUT,
"firmware boot");
ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag);
ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag);
return ret;
}
static int cnl_load_base_firmware(struct sst_dsp *ctx)
{
struct firmware stripped_fw;
struct skl_sst *cnl = ctx->thread_context;
int ret;
if (!ctx->fw) {
ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
if (ret < 0) {
dev_err(ctx->dev, "request firmware failed: %d\n", ret);
goto cnl_load_base_firmware_failed;
}
}
/* parse uuids if first boot */
if (cnl->is_first_boot) {
ret = snd_skl_parse_uuids(ctx, ctx->fw,
CNL_ADSP_FW_HDR_OFFSET, 0);
if (ret < 0)
goto cnl_load_base_firmware_failed;
}
stripped_fw.data = ctx->fw->data;
stripped_fw.size = ctx->fw->size;
skl_dsp_strip_extended_manifest(&stripped_fw);
ret = cnl_prepare_fw(ctx, stripped_fw.data, stripped_fw.size);
if (ret < 0) {
dev_err(ctx->dev, "prepare firmware failed: %d\n", ret);
goto cnl_load_base_firmware_failed;
}
ret = sst_transfer_fw_host_dma(ctx);
if (ret < 0) {
dev_err(ctx->dev, "transfer firmware failed: %d\n", ret);
cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
goto cnl_load_base_firmware_failed;
}
ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete,
msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
if (ret == 0) {
dev_err(ctx->dev, "FW ready timed-out\n");
cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK);
ret = -EIO;
goto cnl_load_base_firmware_failed;
}
cnl->fw_loaded = true;
return 0;
cnl_load_base_firmware_failed:
release_firmware(ctx->fw);
ctx->fw = NULL;
return ret;
}
static int cnl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
{
struct skl_sst *cnl = ctx->thread_context;
unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
struct skl_ipc_dxstate_info dx;
int ret;
if (!cnl->fw_loaded) {
cnl->boot_complete = false;
ret = cnl_load_base_firmware(ctx);
if (ret < 0) {
dev_err(ctx->dev, "fw reload failed: %d\n", ret);
return ret;
}
cnl->cores.state[core_id] = SKL_DSP_RUNNING;
return ret;
}
ret = cnl_dsp_enable_core(ctx, core_mask);
if (ret < 0) {
dev_err(ctx->dev, "enable dsp core %d failed: %d\n",
core_id, ret);
goto err;
}
if (core_id == SKL_DSP_CORE0_ID) {
/* enable interrupt */
cnl_ipc_int_enable(ctx);
cnl_ipc_op_int_enable(ctx);
cnl->boot_complete = false;
ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete,
msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
if (ret == 0) {
dev_err(ctx->dev,
"dsp boot timeout, status=%#x error=%#x\n",
sst_dsp_shim_read(ctx, CNL_ADSP_FW_STATUS),
sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE));
goto err;
}
} else {
dx.core_mask = core_mask;
dx.dx_mask = core_mask;
ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID,
CNL_BASE_FW_MODULE_ID, &dx);
if (ret < 0) {
dev_err(ctx->dev, "set_dx failed, core: %d ret: %d\n",
core_id, ret);
goto err;
}
}
cnl->cores.state[core_id] = SKL_DSP_RUNNING;
return 0;
err:
cnl_dsp_disable_core(ctx, core_mask);
return ret;
}
static int cnl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id)
{
struct skl_sst *cnl = ctx->thread_context;
unsigned int core_mask = SKL_DSP_CORE_MASK(core_id);
struct skl_ipc_dxstate_info dx;
int ret;
dx.core_mask = core_mask;
dx.dx_mask = SKL_IPC_D3_MASK;
ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID,
CNL_BASE_FW_MODULE_ID, &dx);
if (ret < 0) {
dev_err(ctx->dev,
"dsp core %d to d3 failed; continue reset\n",
core_id);
cnl->fw_loaded = false;
}
/* disable interrupts if core 0 */
if (core_id == SKL_DSP_CORE0_ID) {
skl_ipc_op_int_disable(ctx);
skl_ipc_int_disable(ctx);
}
ret = cnl_dsp_disable_core(ctx, core_mask);
if (ret < 0) {
dev_err(ctx->dev, "disable dsp core %d failed: %d\n",
core_id, ret);
return ret;
}
cnl->cores.state[core_id] = SKL_DSP_RESET;
return ret;
}
static unsigned int cnl_get_errno(struct sst_dsp *ctx)
{
return sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE);
}
static const struct skl_dsp_fw_ops cnl_fw_ops = {
.set_state_D0 = cnl_set_dsp_D0,
.set_state_D3 = cnl_set_dsp_D3,
.load_fw = cnl_load_base_firmware,
.get_fw_errcode = cnl_get_errno,
};
static struct sst_ops cnl_ops = {
.irq_handler = cnl_dsp_sst_interrupt,
.write = sst_shim32_write,
.read = sst_shim32_read,
.ram_read = sst_memcpy_fromio_32,
.ram_write = sst_memcpy_toio_32,
.free = cnl_dsp_free,
};
#define CNL_IPC_GLB_NOTIFY_RSP_SHIFT 29
#define CNL_IPC_GLB_NOTIFY_RSP_MASK 0x1
#define CNL_IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> CNL_IPC_GLB_NOTIFY_RSP_SHIFT) \
& CNL_IPC_GLB_NOTIFY_RSP_MASK)
static irqreturn_t cnl_dsp_irq_thread_handler(int irq, void *context)
{
struct sst_dsp *dsp = context;
struct skl_sst *cnl = sst_dsp_get_thread_context(dsp);
struct sst_generic_ipc *ipc = &cnl->ipc;
struct skl_ipc_header header = {0};
u32 hipcida, hipctdr, hipctdd;
int ipc_irq = 0;
/* here we handle ipc interrupts only */
if (!(dsp->intr_status & CNL_ADSPIS_IPC))
return IRQ_NONE;
hipcida = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDA);
hipctdr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDR);
/* reply message from dsp */
if (hipcida & CNL_ADSP_REG_HIPCIDA_DONE) {
sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL,
CNL_ADSP_REG_HIPCCTL_DONE, 0);
/* clear done bit - tell dsp operation is complete */
sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCIDA,
CNL_ADSP_REG_HIPCIDA_DONE, CNL_ADSP_REG_HIPCIDA_DONE);
ipc_irq = 1;
/* unmask done interrupt */
sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL,
CNL_ADSP_REG_HIPCCTL_DONE, CNL_ADSP_REG_HIPCCTL_DONE);
}
/* new message from dsp */
if (hipctdr & CNL_ADSP_REG_HIPCTDR_BUSY) {
hipctdd = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDD);
header.primary = hipctdr;
header.extension = hipctdd;
dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x",
header.primary);
dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x",
header.extension);
if (CNL_IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) {
/* Handle Immediate reply from DSP Core */
skl_ipc_process_reply(ipc, header);
} else {
dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n");
skl_ipc_process_notification(ipc, header);
}
/* clear busy interrupt */
sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDR,
CNL_ADSP_REG_HIPCTDR_BUSY, CNL_ADSP_REG_HIPCTDR_BUSY);
/* set done bit to ack dsp */
sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDA,
CNL_ADSP_REG_HIPCTDA_DONE, CNL_ADSP_REG_HIPCTDA_DONE);
ipc_irq = 1;
}
if (ipc_irq == 0)
return IRQ_NONE;
cnl_ipc_int_enable(dsp);
/* continue to send any remaining messages */
schedule_work(&ipc->kwork);
return IRQ_HANDLED;
}
static struct sst_dsp_device cnl_dev = {
.thread = cnl_dsp_irq_thread_handler,
.ops = &cnl_ops,
};
static void cnl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg)
{
struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header);
if (msg->tx_size)
sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size);
sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDD,
header->extension);
sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDR,
header->primary | CNL_ADSP_REG_HIPCIDR_BUSY);
}
static bool cnl_ipc_is_dsp_busy(struct sst_dsp *dsp)
{
u32 hipcidr;
hipcidr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDR);
return (hipcidr & CNL_ADSP_REG_HIPCIDR_BUSY);
}
static int cnl_ipc_init(struct device *dev, struct skl_sst *cnl)
{
struct sst_generic_ipc *ipc;
int err;
ipc = &cnl->ipc;
ipc->dsp = cnl->dsp;
ipc->dev = dev;
ipc->tx_data_max_size = CNL_ADSP_W1_SZ;
ipc->rx_data_max_size = CNL_ADSP_W0_UP_SZ;
err = sst_ipc_init(ipc);
if (err)
return err;
/*
* overriding tx_msg and is_dsp_busy since
* ipc registers are different for cnl
*/
ipc->ops.tx_msg = cnl_ipc_tx_msg;
ipc->ops.tx_data_copy = skl_ipc_tx_data_copy;
ipc->ops.is_dsp_busy = cnl_ipc_is_dsp_busy;
return 0;
}
int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
const char *fw_name, struct skl_dsp_loader_ops dsp_ops,
struct skl_sst **dsp)
{
struct skl_sst *cnl;
struct sst_dsp *sst;
int ret;
ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &cnl_dev);
if (ret < 0) {
dev_err(dev, "%s: no device\n", __func__);
return ret;
}
cnl = *dsp;
sst = cnl->dsp;
sst->fw_ops = cnl_fw_ops;
sst->addr.lpe = mmio_base;
sst->addr.shim = mmio_base;
sst->addr.sram0_base = CNL_ADSP_SRAM0_BASE;
sst->addr.sram1_base = CNL_ADSP_SRAM1_BASE;
sst->addr.w0_stat_sz = CNL_ADSP_W0_STAT_SZ;
sst->addr.w0_up_sz = CNL_ADSP_W0_UP_SZ;
sst_dsp_mailbox_init(sst, (CNL_ADSP_SRAM0_BASE + CNL_ADSP_W0_STAT_SZ),
CNL_ADSP_W0_UP_SZ, CNL_ADSP_SRAM1_BASE,
CNL_ADSP_W1_SZ);
ret = cnl_ipc_init(dev, cnl);
if (ret) {
skl_dsp_free(sst);
return ret;
}
cnl->boot_complete = false;
init_waitqueue_head(&cnl->boot_wait);
return 0;
}
EXPORT_SYMBOL_GPL(cnl_sst_dsp_init);
int cnl_sst_init_fw(struct device *dev, struct skl_sst *ctx)
{
int ret;
struct sst_dsp *sst = ctx->dsp;
ret = ctx->dsp->fw_ops.load_fw(sst);
if (ret < 0) {
dev_err(dev, "load base fw failed: %d", ret);
return ret;
}
skl_dsp_init_core_state(sst);
ctx->is_first_boot = false;
return 0;
}
EXPORT_SYMBOL_GPL(cnl_sst_init_fw);
void cnl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
{
if (ctx->dsp->fw)
release_firmware(ctx->dsp->fw);
skl_freeup_uuid_list(ctx);
cnl_ipc_free(&ctx->ipc);
ctx->dsp->ops->free(ctx->dsp);
}
EXPORT_SYMBOL_GPL(cnl_sst_dsp_cleanup);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Intel Cannonlake IPC driver");

Просмотреть файл

@ -22,6 +22,7 @@
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include "skl-sst-dsp.h" #include "skl-sst-dsp.h"
#include "cnl-sst-dsp.h"
#include "skl-sst-ipc.h" #include "skl-sst-ipc.h"
#include "skl.h" #include "skl.h"
#include "../common/sst-dsp.h" #include "../common/sst-dsp.h"
@ -201,6 +202,7 @@ static struct skl_dsp_loader_ops bxt_get_loader_ops(void)
static const struct skl_dsp_ops dsp_ops[] = { static const struct skl_dsp_ops dsp_ops[] = {
{ {
.id = 0x9d70, .id = 0x9d70,
.num_cores = 2,
.loader_ops = skl_get_loader_ops, .loader_ops = skl_get_loader_ops,
.init = skl_sst_dsp_init, .init = skl_sst_dsp_init,
.init_fw = skl_sst_init_fw, .init_fw = skl_sst_init_fw,
@ -208,6 +210,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
}, },
{ {
.id = 0x9d71, .id = 0x9d71,
.num_cores = 2,
.loader_ops = skl_get_loader_ops, .loader_ops = skl_get_loader_ops,
.init = kbl_sst_dsp_init, .init = kbl_sst_dsp_init,
.init_fw = skl_sst_init_fw, .init_fw = skl_sst_init_fw,
@ -215,6 +218,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
}, },
{ {
.id = 0x5a98, .id = 0x5a98,
.num_cores = 2,
.loader_ops = bxt_get_loader_ops, .loader_ops = bxt_get_loader_ops,
.init = bxt_sst_dsp_init, .init = bxt_sst_dsp_init,
.init_fw = bxt_sst_init_fw, .init_fw = bxt_sst_init_fw,
@ -222,11 +226,20 @@ static const struct skl_dsp_ops dsp_ops[] = {
}, },
{ {
.id = 0x3198, .id = 0x3198,
.num_cores = 2,
.loader_ops = bxt_get_loader_ops, .loader_ops = bxt_get_loader_ops,
.init = bxt_sst_dsp_init, .init = bxt_sst_dsp_init,
.init_fw = bxt_sst_init_fw, .init_fw = bxt_sst_init_fw,
.cleanup = bxt_sst_dsp_cleanup .cleanup = bxt_sst_dsp_cleanup
}, },
{
.id = 0x9dc8,
.num_cores = 4,
.loader_ops = bxt_get_loader_ops,
.init = cnl_sst_dsp_init,
.init_fw = cnl_sst_init_fw,
.cleanup = cnl_sst_dsp_cleanup
},
}; };
const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
@ -249,6 +262,7 @@ int skl_init_dsp(struct skl *skl)
struct skl_dsp_loader_ops loader_ops; struct skl_dsp_loader_ops loader_ops;
int irq = bus->irq; int irq = bus->irq;
const struct skl_dsp_ops *ops; const struct skl_dsp_ops *ops;
struct skl_dsp_cores *cores;
int ret; int ret;
/* enable ppcap interrupt */ /* enable ppcap interrupt */
@ -263,8 +277,10 @@ int skl_init_dsp(struct skl *skl)
} }
ops = skl_get_dsp_ops(skl->pci->device); ops = skl_get_dsp_ops(skl->pci->device);
if (!ops) if (!ops) {
return -EIO; ret = -EIO;
goto unmap_mmio;
}
loader_ops = ops->loader_ops(); loader_ops = ops->loader_ops();
ret = ops->init(bus->dev, mmio_base, irq, ret = ops->init(bus->dev, mmio_base, irq,
@ -272,11 +288,35 @@ int skl_init_dsp(struct skl *skl)
&skl->skl_sst); &skl->skl_sst);
if (ret < 0) if (ret < 0)
return ret; goto unmap_mmio;
skl->skl_sst->dsp_ops = ops; skl->skl_sst->dsp_ops = ops;
cores = &skl->skl_sst->cores;
cores->count = ops->num_cores;
cores->state = kcalloc(cores->count, sizeof(*cores->state), GFP_KERNEL);
if (!cores->state) {
ret = -ENOMEM;
goto unmap_mmio;
}
cores->usage_count = kcalloc(cores->count, sizeof(*cores->usage_count),
GFP_KERNEL);
if (!cores->usage_count) {
ret = -ENOMEM;
goto free_core_state;
}
dev_dbg(bus->dev, "dsp registration status=%d\n", ret); dev_dbg(bus->dev, "dsp registration status=%d\n", ret);
return 0;
free_core_state:
kfree(cores->state);
unmap_mmio:
iounmap(mmio_base);
return ret; return ret;
} }
@ -291,6 +331,9 @@ int skl_free_dsp(struct skl *skl)
ctx->dsp_ops->cleanup(bus->dev, ctx); ctx->dsp_ops->cleanup(bus->dev, ctx);
kfree(ctx->cores.state);
kfree(ctx->cores.usage_count);
if (ctx->dsp->addr.lpe) if (ctx->dsp->addr.lpe)
iounmap(ctx->dsp->addr.lpe); iounmap(ctx->dsp->addr.lpe);
@ -400,9 +443,12 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig, struct skl_module_cfg *mconfig,
struct skl_base_cfg *base_cfg) struct skl_base_cfg *base_cfg)
{ {
struct skl_module_fmt *format = &mconfig->in_fmt[0]; struct skl_module *module = mconfig->module;
struct skl_module_res *res = &module->resources[mconfig->res_idx];
struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx];
struct skl_module_fmt *format = &fmt->inputs[0].fmt;
base_cfg->audio_fmt.number_of_channels = (u8)format->channels; base_cfg->audio_fmt.number_of_channels = format->channels;
base_cfg->audio_fmt.s_freq = format->s_freq; base_cfg->audio_fmt.s_freq = format->s_freq;
base_cfg->audio_fmt.bit_depth = format->bit_depth; base_cfg->audio_fmt.bit_depth = format->bit_depth;
@ -417,10 +463,10 @@ static void skl_set_base_module_format(struct skl_sst *ctx,
base_cfg->audio_fmt.interleaving = format->interleaving_style; base_cfg->audio_fmt.interleaving = format->interleaving_style;
base_cfg->cps = mconfig->mcps; base_cfg->cps = res->cps;
base_cfg->ibs = mconfig->ibs; base_cfg->ibs = res->ibs;
base_cfg->obs = mconfig->obs; base_cfg->obs = res->obs;
base_cfg->is_pages = mconfig->mem_pages; base_cfg->is_pages = res->is_pages;
} }
/* /*
@ -508,6 +554,9 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
struct skl_cpr_cfg *cpr_mconfig) struct skl_cpr_cfg *cpr_mconfig)
{ {
u32 dma_io_buf; u32 dma_io_buf;
struct skl_module_res *res;
int res_idx = mconfig->res_idx;
struct skl *skl = get_skl_ctx(ctx->dev);
cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig); cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig);
@ -516,19 +565,27 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
return; return;
} }
if (skl->nr_modules) {
res = &mconfig->module->resources[mconfig->res_idx];
cpr_mconfig->gtw_cfg.dma_buffer_size = res->dma_buffer_size;
goto skip_buf_size_calc;
} else {
res = &mconfig->module->resources[res_idx];
}
switch (mconfig->hw_conn_type) { switch (mconfig->hw_conn_type) {
case SKL_CONN_SOURCE: case SKL_CONN_SOURCE:
if (mconfig->dev_type == SKL_DEVICE_HDAHOST) if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
dma_io_buf = mconfig->ibs; dma_io_buf = res->ibs;
else else
dma_io_buf = mconfig->obs; dma_io_buf = res->obs;
break; break;
case SKL_CONN_SINK: case SKL_CONN_SINK:
if (mconfig->dev_type == SKL_DEVICE_HDAHOST) if (mconfig->dev_type == SKL_DEVICE_HDAHOST)
dma_io_buf = mconfig->obs; dma_io_buf = res->obs;
else else
dma_io_buf = mconfig->ibs; dma_io_buf = res->ibs;
break; break;
default: default:
@ -543,11 +600,12 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
/* fallback to 2ms default value */ /* fallback to 2ms default value */
if (!cpr_mconfig->gtw_cfg.dma_buffer_size) { if (!cpr_mconfig->gtw_cfg.dma_buffer_size) {
if (mconfig->hw_conn_type == SKL_CONN_SOURCE) if (mconfig->hw_conn_type == SKL_CONN_SOURCE)
cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->obs; cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->obs;
else else
cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->ibs; cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->ibs;
} }
skip_buf_size_calc:
cpr_mconfig->cpr_feature_mask = 0; cpr_mconfig->cpr_feature_mask = 0;
cpr_mconfig->gtw_cfg.config_length = 0; cpr_mconfig->gtw_cfg.config_length = 0;
@ -595,7 +653,9 @@ static void skl_setup_out_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig, struct skl_module_cfg *mconfig,
struct skl_audio_data_format *out_fmt) struct skl_audio_data_format *out_fmt)
{ {
struct skl_module_fmt *format = &mconfig->out_fmt[0]; struct skl_module *module = mconfig->module;
struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx];
struct skl_module_fmt *format = &fmt->outputs[0].fmt;
out_fmt->number_of_channels = (u8)format->channels; out_fmt->number_of_channels = (u8)format->channels;
out_fmt->s_freq = format->s_freq; out_fmt->s_freq = format->s_freq;
@ -620,7 +680,9 @@ static void skl_set_src_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig, struct skl_module_cfg *mconfig,
struct skl_src_module_cfg *src_mconfig) struct skl_src_module_cfg *src_mconfig)
{ {
struct skl_module_fmt *fmt = &mconfig->out_fmt[0]; struct skl_module *module = mconfig->module;
struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx];
struct skl_module_fmt *fmt = &iface->outputs[0].fmt;
skl_set_base_module_format(ctx, mconfig, skl_set_base_module_format(ctx, mconfig,
(struct skl_base_cfg *)src_mconfig); (struct skl_base_cfg *)src_mconfig);
@ -637,7 +699,9 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig, struct skl_module_cfg *mconfig,
struct skl_up_down_mixer_cfg *mixer_mconfig) struct skl_up_down_mixer_cfg *mixer_mconfig)
{ {
struct skl_module_fmt *fmt = &mconfig->out_fmt[0]; struct skl_module *module = mconfig->module;
struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx];
struct skl_module_fmt *fmt = &iface->outputs[0].fmt;
int i = 0; int i = 0;
skl_set_base_module_format(ctx, mconfig, skl_set_base_module_format(ctx, mconfig,
@ -950,7 +1014,7 @@ static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg
{ {
dev_dbg(ctx->dev, "%s: src module_id = %d src_instance=%d\n", dev_dbg(ctx->dev, "%s: src module_id = %d src_instance=%d\n",
__func__, src_module->id.module_id, src_module->id.pvt_id); __func__, src_module->id.module_id, src_module->id.pvt_id);
dev_dbg(ctx->dev, "%s: dst_module=%d dst_instacne=%d\n", __func__, dev_dbg(ctx->dev, "%s: dst_module=%d dst_instance=%d\n", __func__,
dst_module->id.module_id, dst_module->id.pvt_id); dst_module->id.module_id, dst_module->id.pvt_id);
dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n", dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n",
@ -970,8 +1034,8 @@ int skl_unbind_modules(struct skl_sst *ctx,
struct skl_ipc_bind_unbind_msg msg; struct skl_ipc_bind_unbind_msg msg;
struct skl_module_inst_id src_id = src_mcfg->id; struct skl_module_inst_id src_id = src_mcfg->id;
struct skl_module_inst_id dst_id = dst_mcfg->id; struct skl_module_inst_id dst_id = dst_mcfg->id;
int in_max = dst_mcfg->max_in_queue; int in_max = dst_mcfg->module->max_input_pins;
int out_max = src_mcfg->max_out_queue; int out_max = src_mcfg->module->max_output_pins;
int src_index, dst_index, src_pin_state, dst_pin_state; int src_index, dst_index, src_pin_state, dst_pin_state;
skl_dump_bind_info(ctx, src_mcfg, dst_mcfg); skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
@ -1019,6 +1083,21 @@ int skl_unbind_modules(struct skl_sst *ctx,
return ret; return ret;
} }
static void fill_pin_params(struct skl_audio_data_format *pin_fmt,
struct skl_module_fmt *format)
{
pin_fmt->number_of_channels = format->channels;
pin_fmt->s_freq = format->s_freq;
pin_fmt->bit_depth = format->bit_depth;
pin_fmt->valid_bit_depth = format->valid_bit_depth;
pin_fmt->ch_cfg = format->ch_cfg;
pin_fmt->sample_type = format->sample_type;
pin_fmt->channel_map = format->ch_map;
pin_fmt->interleaving = format->interleaving_style;
}
#define CPR_SINK_FMT_PARAM_ID 2
/* /*
* Once a module is instantiated it need to be 'bind' with other modules in * Once a module is instantiated it need to be 'bind' with other modules in
* the pipeline. For binding we need to find the module pins which are bind * the pipeline. For binding we need to find the module pins which are bind
@ -1030,11 +1109,15 @@ int skl_bind_modules(struct skl_sst *ctx,
struct skl_module_cfg *src_mcfg, struct skl_module_cfg *src_mcfg,
struct skl_module_cfg *dst_mcfg) struct skl_module_cfg *dst_mcfg)
{ {
int ret; int ret = 0;
struct skl_ipc_bind_unbind_msg msg; struct skl_ipc_bind_unbind_msg msg;
int in_max = dst_mcfg->max_in_queue; int in_max = dst_mcfg->module->max_input_pins;
int out_max = src_mcfg->max_out_queue; int out_max = src_mcfg->module->max_output_pins;
int src_index, dst_index; int src_index, dst_index;
struct skl_module_fmt *format;
struct skl_cpr_pin_fmt pin_fmt;
struct skl_module *module;
struct skl_module_iface *fmt;
skl_dump_bind_info(ctx, src_mcfg, dst_mcfg); skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
@ -1053,6 +1136,29 @@ int skl_bind_modules(struct skl_sst *ctx,
return -EINVAL; return -EINVAL;
} }
/*
* Copier module requires the separate large_config_set_ipc to
* configure the pins other than 0
*/
if (src_mcfg->m_type == SKL_MODULE_TYPE_COPIER && src_index > 0) {
pin_fmt.sink_id = src_index;
module = src_mcfg->module;
fmt = &module->formats[src_mcfg->fmt_idx];
/* Input fmt is same as that of src module input cfg */
format = &fmt->inputs[0].fmt;
fill_pin_params(&(pin_fmt.src_fmt), format);
format = &fmt->outputs[src_index].fmt;
fill_pin_params(&(pin_fmt.dst_fmt), format);
ret = skl_set_module_params(ctx, (void *)&pin_fmt,
sizeof(struct skl_cpr_pin_fmt),
CPR_SINK_FMT_PARAM_ID, src_mcfg);
if (ret < 0)
goto out;
}
msg.dst_queue = dst_index; msg.dst_queue = dst_index;
dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n", dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n",
@ -1070,11 +1176,12 @@ int skl_bind_modules(struct skl_sst *ctx,
src_mcfg->m_state = SKL_MODULE_BIND_DONE; src_mcfg->m_state = SKL_MODULE_BIND_DONE;
src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE; src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE;
dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE; dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE;
} else { return ret;
/* error case , if IPC fails, clear the queue index */
skl_free_queue(src_mcfg->m_out_pin, src_index);
skl_free_queue(dst_mcfg->m_in_pin, dst_index);
} }
out:
/* error case , if IPC fails, clear the queue index */
skl_free_queue(src_mcfg->m_out_pin, src_index);
skl_free_queue(dst_mcfg->m_in_pin, dst_index);
return ret; return ret;
} }

Просмотреть файл

@ -33,7 +33,7 @@
#define HDA_STEREO 2 #define HDA_STEREO 2
#define HDA_QUAD 4 #define HDA_QUAD 4
static struct snd_pcm_hardware azx_pcm_hw = { static const struct snd_pcm_hardware azx_pcm_hw = {
.info = (SNDRV_PCM_INFO_MMAP | .info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER |
@ -628,7 +628,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
return 0; return 0;
} }
static struct snd_soc_dai_ops skl_pcm_dai_ops = { static const struct snd_soc_dai_ops skl_pcm_dai_ops = {
.startup = skl_pcm_open, .startup = skl_pcm_open,
.shutdown = skl_pcm_close, .shutdown = skl_pcm_close,
.prepare = skl_pcm_prepare, .prepare = skl_pcm_prepare,
@ -637,15 +637,15 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = {
.trigger = skl_pcm_trigger, .trigger = skl_pcm_trigger,
}; };
static struct snd_soc_dai_ops skl_dmic_dai_ops = { static const struct snd_soc_dai_ops skl_dmic_dai_ops = {
.hw_params = skl_be_hw_params, .hw_params = skl_be_hw_params,
}; };
static struct snd_soc_dai_ops skl_be_ssp_dai_ops = { static const struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
.hw_params = skl_be_hw_params, .hw_params = skl_be_hw_params,
}; };
static struct snd_soc_dai_ops skl_link_dai_ops = { static const struct snd_soc_dai_ops skl_link_dai_ops = {
.prepare = skl_link_pcm_prepare, .prepare = skl_link_pcm_prepare,
.hw_params = skl_link_hw_params, .hw_params = skl_link_hw_params,
.hw_free = skl_link_hw_free, .hw_free = skl_link_hw_free,
@ -674,6 +674,32 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.sig_bits = 32, .sig_bits = 32,
}, },
}, },
{
.name = "System Pin2",
.ops = &skl_pcm_dai_ops,
.playback = {
.stream_name = "Headset Playback",
.channels_min = HDA_MONO,
.channels_max = HDA_STEREO,
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
},
},
{
.name = "Echoref Pin",
.ops = &skl_pcm_dai_ops,
.capture = {
.stream_name = "Echoreference Capture",
.channels_min = HDA_STEREO,
.channels_max = HDA_STEREO,
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 |
SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
},
},
{ {
.name = "Reference Pin", .name = "Reference Pin",
.ops = &skl_pcm_dai_ops, .ops = &skl_pcm_dai_ops,
@ -1194,8 +1220,11 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig) static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig)
{ {
struct skl_sst *ctx = skl->skl_sst; struct skl_sst *ctx = skl->skl_sst;
struct skl_module_inst_id *pin_id;
uuid_le *uuid_mod, *uuid_tplg;
struct skl_module *skl_module;
struct uuid_module *module; struct uuid_module *module;
uuid_le *uuid_mod; int i, ret = -EIO;
uuid_mod = (uuid_le *)mconfig->guid; uuid_mod = (uuid_le *)mconfig->guid;
@ -1207,12 +1236,45 @@ static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig)
list_for_each_entry(module, &ctx->uuid_list, list) { list_for_each_entry(module, &ctx->uuid_list, list) {
if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) {
mconfig->id.module_id = module->id; mconfig->id.module_id = module->id;
mconfig->is_loadable = module->is_loadable; if (mconfig->module)
return 0; mconfig->module->loadable = module->is_loadable;
ret = 0;
break;
} }
} }
return -EIO; if (ret)
return ret;
uuid_mod = &module->uuid;
ret = -EIO;
for (i = 0; i < skl->nr_modules; i++) {
skl_module = skl->modules[i];
uuid_tplg = &skl_module->uuid;
if (!uuid_le_cmp(*uuid_mod, *uuid_tplg)) {
mconfig->module = skl_module;
ret = 0;
break;
}
}
if (skl->nr_modules && ret)
return ret;
list_for_each_entry(module, &ctx->uuid_list, list) {
for (i = 0; i < MAX_IN_QUEUE; i++) {
pin_id = &mconfig->m_in_pin[i].id;
if (!uuid_le_cmp(pin_id->mod_uuid, module->uuid))
pin_id->module_id = module->id;
}
for (i = 0; i < MAX_OUT_QUEUE; i++) {
pin_id = &mconfig->m_out_pin[i].id;
if (!uuid_le_cmp(pin_id->mod_uuid, module->uuid))
pin_id->module_id = module->id;
}
}
return 0;
} }
static int skl_populate_modules(struct skl *skl) static int skl_populate_modules(struct skl *skl)
@ -1284,7 +1346,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
return 0; return 0;
} }
static struct snd_soc_platform_driver skl_platform_drv = { static const struct snd_soc_platform_driver skl_platform_drv = {
.probe = skl_platform_soc_probe, .probe = skl_platform_soc_probe,
.ops = &skl_platform_ops, .ops = &skl_platform_ops,
.pcm_new = skl_pcm_new, .pcm_new = skl_pcm_new,

Просмотреть файл

@ -47,7 +47,7 @@ void skl_dsp_init_core_state(struct sst_dsp *ctx)
skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING; skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING;
skl->cores.usage_count[SKL_DSP_CORE0_ID] = 1; skl->cores.usage_count[SKL_DSP_CORE0_ID] = 1;
for (i = SKL_DSP_CORE0_ID + 1; i < SKL_DSP_CORES_MAX; i++) { for (i = SKL_DSP_CORE0_ID + 1; i < skl->cores.count; i++) {
skl->cores.state[i] = SKL_DSP_RESET; skl->cores.state[i] = SKL_DSP_RESET;
skl->cores.usage_count[i] = 0; skl->cores.usage_count[i] = 0;
} }
@ -351,6 +351,8 @@ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id)
return -EINVAL; return -EINVAL;
} }
skl->cores.usage_count[core_id]++;
if (skl->cores.state[core_id] == SKL_DSP_RESET) { if (skl->cores.state[core_id] == SKL_DSP_RESET) {
ret = ctx->fw_ops.set_state_D0(ctx, core_id); ret = ctx->fw_ops.set_state_D0(ctx, core_id);
if (ret < 0) { if (ret < 0) {
@ -359,8 +361,6 @@ int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id)
} }
} }
skl->cores.usage_count[core_id]++;
out: out:
dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n", dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n",
core_id, skl->cores.state[core_id], core_id, skl->cores.state[core_id],

Просмотреть файл

@ -283,7 +283,7 @@ enum skl_ipc_module_msg {
IPC_MOD_SET_D0IX = 8 IPC_MOD_SET_D0IX = 8
}; };
static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data, void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
size_t tx_size) size_t tx_size)
{ {
if (tx_size) if (tx_size)
@ -347,7 +347,7 @@ out:
} }
static int skl_ipc_process_notification(struct sst_generic_ipc *ipc, int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
struct skl_ipc_header header) struct skl_ipc_header header)
{ {
struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc); struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc);
@ -406,7 +406,7 @@ static int skl_ipc_set_reply_error_code(u32 reply)
} }
} }
static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
struct skl_ipc_header header) struct skl_ipc_header header)
{ {
struct ipc_message *msg; struct ipc_message *msg;

Просмотреть файл

@ -44,12 +44,10 @@ struct skl_ipc_header {
u32 extension; u32 extension;
}; };
#define SKL_DSP_CORES_MAX 2
struct skl_dsp_cores { struct skl_dsp_cores {
unsigned int count; unsigned int count;
enum skl_dsp_states state[SKL_DSP_CORES_MAX]; enum skl_dsp_states *state;
int usage_count[SKL_DSP_CORES_MAX]; int *usage_count;
}; };
/** /**
@ -214,4 +212,10 @@ void skl_ipc_free(struct sst_generic_ipc *ipc);
int skl_ipc_init(struct device *dev, struct skl_sst *skl); int skl_ipc_init(struct device *dev, struct skl_sst *skl);
void skl_clear_module_cnt(struct sst_dsp *ctx); void skl_clear_module_cnt(struct sst_dsp *ctx);
void skl_ipc_process_reply(struct sst_generic_ipc *ipc,
struct skl_ipc_header header);
int skl_ipc_process_notification(struct sst_generic_ipc *ipc,
struct skl_ipc_header header);
void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data,
size_t tx_size);
#endif /* __SKL_IPC_H */ #endif /* __SKL_IPC_H */

Просмотреть файл

@ -368,7 +368,6 @@ int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
{ {
struct skl_sst *skl; struct skl_sst *skl;
struct sst_dsp *sst; struct sst_dsp *sst;
int ret;
skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL);
if (skl == NULL) if (skl == NULL)
@ -388,15 +387,12 @@ int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
sst->dsp_ops = dsp_ops; sst->dsp_ops = dsp_ops;
init_waitqueue_head(&skl->mod_load_wait); init_waitqueue_head(&skl->mod_load_wait);
INIT_LIST_HEAD(&sst->module_list); INIT_LIST_HEAD(&sst->module_list);
ret = skl_ipc_init(dev, skl);
if (ret)
return ret;
skl->is_first_boot = true; skl->is_first_boot = true;
if (dsp) if (dsp)
*dsp = skl; *dsp = skl;
return ret; return 0;
} }
int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo, int skl_prepare_lib_load(struct skl_sst *skl, struct skl_lib_info *linfo,

Просмотреть файл

@ -503,7 +503,7 @@ static void skl_clear_module_table(struct sst_dsp *ctx)
} }
} }
static struct skl_dsp_fw_ops skl_fw_ops = { static const struct skl_dsp_fw_ops skl_fw_ops = {
.set_state_D0 = skl_set_dsp_D0, .set_state_D0 = skl_set_dsp_D0,
.set_state_D3 = skl_set_dsp_D3, .set_state_D3 = skl_set_dsp_D3,
.load_fw = skl_load_base_firmware, .load_fw = skl_load_base_firmware,
@ -512,7 +512,7 @@ static struct skl_dsp_fw_ops skl_fw_ops = {
.unload_mod = skl_unload_module, .unload_mod = skl_unload_module,
}; };
static struct skl_dsp_fw_ops kbl_fw_ops = { static const struct skl_dsp_fw_ops kbl_fw_ops = {
.set_state_D0 = skl_set_dsp_D0, .set_state_D0 = skl_set_dsp_D0,
.set_state_D3 = skl_set_dsp_D3, .set_state_D3 = skl_set_dsp_D3,
.load_fw = skl_load_base_firmware, .load_fw = skl_load_base_firmware,
@ -561,9 +561,13 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
sst->fw_ops = skl_fw_ops; ret = skl_ipc_init(dev, skl);
if (ret) {
skl_dsp_free(sst);
return ret;
}
skl->cores.count = 2; sst->fw_ops = skl_fw_ops;
return 0; return 0;
} }

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -44,6 +44,13 @@
#define SKL_DEFAULT_MIC_SEL_GAIN 0x3FF #define SKL_DEFAULT_MIC_SEL_GAIN 0x3FF
#define SKL_MIC_SEL_SWITCH 0x3 #define SKL_MIC_SEL_SWITCH 0x3
#define SKL_OUTPUT_PIN 0
#define SKL_INPUT_PIN 1
#define SKL_MAX_PATH_CONFIGS 8
#define SKL_MAX_MODULES_IN_PIPE 8
#define SKL_MAX_MODULE_FORMATS 32
#define SKL_MAX_MODULE_RESOURCES 32
enum skl_channel_index { enum skl_channel_index {
SKL_CHANNEL_LEFT = 0, SKL_CHANNEL_LEFT = 0,
SKL_CHANNEL_RIGHT = 1, SKL_CHANNEL_RIGHT = 1,
@ -131,6 +138,11 @@ struct skl_cpr_cfg {
struct skl_cpr_gtw_cfg gtw_cfg; struct skl_cpr_gtw_cfg gtw_cfg;
} __packed; } __packed;
struct skl_cpr_pin_fmt {
u32 sink_id;
struct skl_audio_data_format src_fmt;
struct skl_audio_data_format dst_fmt;
} __packed;
struct skl_src_module_cfg { struct skl_src_module_cfg {
struct skl_base_cfg base_cfg; struct skl_base_cfg base_cfg;
@ -214,6 +226,7 @@ struct skl_kpb_params {
}; };
struct skl_module_inst_id { struct skl_module_inst_id {
uuid_le mod_uuid;
int module_id; int module_id;
u32 instance_id; u32 instance_id;
int pvt_id; int pvt_id;
@ -266,6 +279,23 @@ struct skl_pipe_params {
unsigned int link_bps; unsigned int link_bps;
}; };
struct skl_pipe_fmt {
u32 freq;
u8 channels;
u8 bps;
};
struct skl_pipe_mcfg {
u8 res_idx;
u8 fmt_idx;
};
struct skl_path_config {
u8 mem_pages;
struct skl_pipe_fmt in_fmt;
struct skl_pipe_fmt out_fmt;
};
struct skl_pipe { struct skl_pipe {
u8 ppl_id; u8 ppl_id;
u8 pipe_priority; u8 pipe_priority;
@ -274,6 +304,10 @@ struct skl_pipe {
u8 lp_mode; u8 lp_mode;
struct skl_pipe_params *p_params; struct skl_pipe_params *p_params;
enum skl_pipe_state state; enum skl_pipe_state state;
u8 direction;
u8 cur_config_idx;
u8 nr_cfgs;
struct skl_path_config configs[SKL_MAX_PATH_CONFIGS];
struct list_head w_list; struct list_head w_list;
bool passthru; bool passthru;
}; };
@ -292,9 +326,57 @@ enum d0i3_capability {
SKL_D0I3_NON_STREAMING = 2, SKL_D0I3_NON_STREAMING = 2,
}; };
struct skl_module_pin_fmt {
u8 id;
struct skl_module_fmt fmt;
};
struct skl_module_iface {
u8 fmt_idx;
u8 nr_in_fmt;
u8 nr_out_fmt;
struct skl_module_pin_fmt inputs[MAX_IN_QUEUE];
struct skl_module_pin_fmt outputs[MAX_OUT_QUEUE];
};
struct skl_module_pin_resources {
u8 pin_index;
u32 buf_size;
};
struct skl_module_res {
u8 id;
u32 is_pages;
u32 cps;
u32 ibs;
u32 obs;
u32 dma_buffer_size;
u32 cpc;
u8 nr_input_pins;
u8 nr_output_pins;
struct skl_module_pin_resources input[MAX_IN_QUEUE];
struct skl_module_pin_resources output[MAX_OUT_QUEUE];
};
struct skl_module {
uuid_le uuid;
u8 loadable;
u8 input_pin_type;
u8 output_pin_type;
u8 max_input_pins;
u8 max_output_pins;
u8 nr_resources;
u8 nr_interfaces;
struct skl_module_res resources[SKL_MAX_MODULE_RESOURCES];
struct skl_module_iface formats[SKL_MAX_MODULE_FORMATS];
};
struct skl_module_cfg { struct skl_module_cfg {
u8 guid[16]; u8 guid[16];
struct skl_module_inst_id id; struct skl_module_inst_id id;
struct skl_module *module;
int res_idx;
int fmt_idx;
u8 domain; u8 domain;
bool homogenous_inputs; bool homogenous_inputs;
bool homogenous_outputs; bool homogenous_outputs;
@ -329,6 +411,7 @@ struct skl_module_cfg {
enum skl_module_state m_state; enum skl_module_state m_state;
struct skl_pipe *pipe; struct skl_pipe *pipe;
struct skl_specific_cfg formats_config; struct skl_specific_cfg formats_config;
struct skl_pipe_mcfg mod_cfg[SKL_MAX_MODULES_IN_PIPE];
}; };
struct skl_algo_data { struct skl_algo_data {

Просмотреть файл

@ -415,7 +415,7 @@ static int skl_free(struct hdac_ext_bus *ebus)
snd_hdac_ext_stop_streams(ebus); snd_hdac_ext_stop_streams(ebus);
if (bus->irq >= 0) if (bus->irq >= 0)
free_irq(bus->irq, (void *)bus); free_irq(bus->irq, (void *)ebus);
snd_hdac_bus_free_stream_pages(bus); snd_hdac_bus_free_stream_pages(bus);
snd_hdac_stream_free_all(ebus); snd_hdac_stream_free_all(ebus);
snd_hdac_link_free_all(ebus); snd_hdac_link_free_all(ebus);
@ -528,7 +528,7 @@ static int probe_codec(struct hdac_ext_bus *ebus, int addr)
} }
/* Codec initialization */ /* Codec initialization */
static int skl_codec_create(struct hdac_ext_bus *ebus) static void skl_codec_create(struct hdac_ext_bus *ebus)
{ {
struct hdac_bus *bus = ebus_to_hbus(ebus); struct hdac_bus *bus = ebus_to_hbus(ebus);
int c, max_slots; int c, max_slots;
@ -559,8 +559,6 @@ static int skl_codec_create(struct hdac_ext_bus *ebus)
} }
} }
} }
return 0;
} }
static const struct hdac_bus_ops bus_core_ops = { static const struct hdac_bus_ops bus_core_ops = {
@ -612,9 +610,7 @@ static void skl_probe_work(struct work_struct *work)
dev_info(bus->dev, "no hda codecs found!\n"); dev_info(bus->dev, "no hda codecs found!\n");
/* create codec instances */ /* create codec instances */
err = skl_codec_create(ebus); skl_codec_create(ebus);
if (err < 0)
goto out_err;
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
err = snd_hdac_display_power(bus, false); err = snd_hdac_display_power(bus, false);
@ -702,6 +698,8 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
return -ENXIO; return -ENXIO;
} }
skl_init_chip(bus, true);
snd_hdac_bus_parse_capabilities(bus); snd_hdac_bus_parse_capabilities(bus);
if (skl_acquire_irq(ebus, 0) < 0) if (skl_acquire_irq(ebus, 0) < 0)
@ -982,6 +980,11 @@ static struct sst_acpi_mach sst_kbl_devdata[] = {
.quirk_data = &kbl_poppy_codecs, .quirk_data = &kbl_poppy_codecs,
.pdata = &skl_dmic_data .pdata = &skl_dmic_data
}, },
{
.id = "10EC5663",
.drv_name = "kbl_rt5663",
.fw_filename = "intel/dsp_fw_kbl.bin",
},
{} {}
}; };
@ -995,6 +998,14 @@ static struct sst_acpi_mach sst_glk_devdata[] = {
{} {}
}; };
static const struct sst_acpi_mach sst_cnl_devdata[] = {
{
.id = "INT34C2",
.drv_name = "cnl_rt274",
.fw_filename = "intel/dsp_fw_cnl.bin",
},
};
/* PCI IDs */ /* PCI IDs */
static const struct pci_device_id skl_ids[] = { static const struct pci_device_id skl_ids[] = {
/* Sunrise Point-LP */ /* Sunrise Point-LP */
@ -1009,6 +1020,9 @@ static const struct pci_device_id skl_ids[] = {
/* GLK */ /* GLK */
{ PCI_DEVICE(0x8086, 0x3198), { PCI_DEVICE(0x8086, 0x3198),
.driver_data = (unsigned long)&sst_glk_devdata}, .driver_data = (unsigned long)&sst_glk_devdata},
/* CNL */
{ PCI_DEVICE(0x8086, 0x9dc8),
.driver_data = (unsigned long)&sst_cnl_devdata},
{ 0, } { 0, }
}; };
MODULE_DEVICE_TABLE(pci, skl_ids); MODULE_DEVICE_TABLE(pci, skl_ids);

Просмотреть файл

@ -71,6 +71,8 @@ struct skl {
struct work_struct probe_work; struct work_struct probe_work;
struct skl_debug *debugfs; struct skl_debug *debugfs;
u8 nr_modules;
struct skl_module **modules;
}; };
#define skl_to_ebus(s) (&(s)->ebus) #define skl_to_ebus(s) (&(s)->ebus)
@ -90,6 +92,7 @@ struct skl_machine_pdata {
struct skl_dsp_ops { struct skl_dsp_ops {
int id; int id;
unsigned int num_cores;
struct skl_dsp_loader_ops (*loader_ops)(void); struct skl_dsp_loader_ops (*loader_ops)(void);
int (*init)(struct device *dev, void __iomem *mmio_base, int (*init)(struct device *dev, void __iomem *mmio_base,
int irq, const char *fw_name, int irq, const char *fw_name,