diff options
Diffstat (limited to 'sound/soc/sof/intel')
-rw-r--r-- | sound/soc/sof/intel/Kconfig | 84 | ||||
-rw-r--r-- | sound/soc/sof/intel/apl.c | 8 | ||||
-rw-r--r-- | sound/soc/sof/intel/bdw.c | 38 | ||||
-rw-r--r-- | sound/soc/sof/intel/byt.c | 50 | ||||
-rw-r--r-- | sound/soc/sof/intel/cnl.c | 67 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-codec.c | 22 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-ctrl.c | 12 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-dsp.c | 137 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-ipc.c | 6 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-ipc.h | 51 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-loader.c | 26 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-pcm.c | 15 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-stream.c | 69 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda.c | 30 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda.h | 28 |
15 files changed, 573 insertions, 70 deletions
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 479ba249e219..cc09bb606f7d 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -10,7 +10,7 @@ config SND_SOC_SOF_INTEL_TOPLEVEL if SND_SOC_SOF_INTEL_TOPLEVEL config SND_SOC_SOF_INTEL_ACPI - tristate + def_tristate SND_SOC_SOF_ACPI select SND_SOC_SOF_BAYTRAIL if SND_SOC_SOF_BAYTRAIL_SUPPORT select SND_SOC_SOF_BROADWELL if SND_SOC_SOF_BROADWELL_SUPPORT help @@ -18,7 +18,7 @@ config SND_SOC_SOF_INTEL_ACPI 'select' statements at a higher level config SND_SOC_SOF_INTEL_PCI - tristate + def_tristate SND_SOC_SOF_PCI select SND_SOC_SOF_MERRIFIELD if SND_SOC_SOF_MERRIFIELD_SUPPORT select SND_SOC_SOF_APOLLOLAKE if SND_SOC_SOF_APOLLOLAKE_SUPPORT select SND_SOC_SOF_GEMINILAKE if SND_SOC_SOF_GEMINILAKE_SUPPORT @@ -29,6 +29,7 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_COMETLAKE_H if SND_SOC_SOF_COMETLAKE_H_SUPPORT select SND_SOC_SOF_TIGERLAKE if SND_SOC_SOF_TIGERLAKE_SUPPORT select SND_SOC_SOF_ELKHARTLAKE if SND_SOC_SOF_ELKHARTLAKE_SUPPORT + select SND_SOC_SOF_JASPERLAKE if SND_SOC_SOF_JASPERLAKE_SUPPORT help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -36,7 +37,7 @@ config SND_SOC_SOF_INTEL_PCI config SND_SOC_SOF_INTEL_HIFI_EP_IPC tristate help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_INTEL_ATOM_HIFI_EP @@ -61,10 +62,18 @@ if SND_SOC_SOF_INTEL_ACPI config SND_SOC_SOF_BAYTRAIL_SUPPORT bool "SOF support for Baytrail, Braswell and Cherrytrail" + depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI=n help This adds support for Sound Open Firmware for Intel(R) platforms using the Baytrail, Braswell or Cherrytrail processors. - Say Y if you have such a device. + This option is mutually exclusive with the Atom/SST and Baytrail + legacy drivers. If you want to enable SOF on Baytrail/Cherrytrail, + you need to deselect those options first. + SOF does not support Baytrail-CR for now, so this option is not + recommended for distros. At some point all legacy drivers will be + deprecated but not before all userspace firmware/topology/UCM files + are made available to downstream distros. + Say Y if you want to enable SOF on Baytrail/Cherrytrail If unsure select "N". config SND_SOC_SOF_BAYTRAIL @@ -76,10 +85,18 @@ config SND_SOC_SOF_BAYTRAIL config SND_SOC_SOF_BROADWELL_SUPPORT bool "SOF support for Broadwell" + depends on SND_SOC_INTEL_HASWELL=n help This adds support for Sound Open Firmware for Intel(R) platforms using the Broadwell processors. - Say Y if you have such a device. + This option is mutually exclusive with the Haswell/Broadwell legacy + driver. If you want to enable SOF on Broadwell you need to deselect + the legacy driver first. + SOF does fully support Broadwell yet, so this option is not + recommended for distros. At some point all legacy drivers will be + deprecated but not before all userspace firmware/topology/UCM files + are made available to downstream distros. + Say Y if you want to enable SOF on Broadwell If unsure select "N". config SND_SOC_SOF_BROADWELL @@ -217,31 +234,46 @@ config SND_SOC_SOF_COMETLAKE_H_SUPPORT config SND_SOC_SOF_TIGERLAKE_SUPPORT bool "SOF support for Tigerlake" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Tigerlake processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the Tigerlake processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_TIGERLAKE tristate select SND_SOC_SOF_HDA_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_ELKHARTLAKE_SUPPORT bool "SOF support for ElkhartLake" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the ElkhartLake processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the ElkhartLake processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_ELKHARTLAKE tristate select SND_SOC_SOF_HDA_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_JASPERLAKE_SUPPORT + bool "SOF support for JasperLake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the JasperLake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_JASPERLAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_HDA_COMMON @@ -273,6 +305,26 @@ config SND_SOC_SOF_HDA_AUDIO_CODEC Say Y if you want to enable HDAudio codecs with SOF. If unsure select "N". +config SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1 + bool "SOF enable DMI Link L1" + help + This option enables DMI L1 for both playback and capture + and disables known workarounds for specific HDaudio platforms. + Only use to look into power optimizations on platforms not + affected by DMI L1 issues. This option is not recommended. + Say Y if you want to enable DMI Link L1 + If unsure, select "N". + +config SND_SOC_SOF_HDA_COMMON_HDMI_CODEC + bool "SOF common HDA HDMI codec driver" + depends on SND_SOC_SOF_HDA_LINK + depends on SND_HDA_CODEC_HDMI + help + This adds support for HDMI audio by using the common HDA + HDMI/DisplayPort codec driver. + Say Y if you want to use the common codec driver with SOF. + If unsure select "Y". + endif ## SND_SOC_SOF_HDA_COMMON config SND_SOC_SOF_HDA_LINK_BASELINE @@ -286,7 +338,7 @@ config SND_SOC_SOF_HDA tristate select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC - select SND_INTEL_NHLT if ACPI + select SND_INTEL_DSP_CONFIG help This option is not user-selectable but automagically handled by 'select' statements at a higher level diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 8dc7a5558da4..7daa8eb456c8 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -97,6 +97,14 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .runtime_resume = hda_dsp_runtime_resume, .runtime_idle = hda_dsp_runtime_idle, .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, + .set_power_state = hda_dsp_set_power_state, + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_apl_ops); diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index e282179263e8..141dad554764 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -37,6 +37,7 @@ #define MBOX_SIZE 0x1000 #define MBOX_DUMP_SIZE 0x30 #define EXCEPT_OFFSET 0x800 +#define EXCEPT_MAX_HDR_SIZE 0x400 /* DSP peripherals */ #define DMAC0_OFFSET 0xFE000 @@ -228,6 +229,11 @@ static void bdw_get_registers(struct snd_sof_dev *sdev, /* note: variable AR register array is not read */ /* then get panic info */ + if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) { + dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n", + xoops->arch_hdr.totalsize); + return; + } offset += xoops->arch_hdr.totalsize; sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info)); @@ -241,7 +247,7 @@ static void bdw_dump(struct snd_sof_dev *sdev, u32 flags) struct sof_ipc_dsp_oops_xtensa xoops; struct sof_ipc_panic_info panic_info; u32 stack[BDW_STACK_DUMP_SIZE]; - u32 status, panic; + u32 status, panic, imrx, imrd; /* now try generic SOF status messages */ status = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); @@ -250,6 +256,26 @@ static void bdw_dump(struct snd_sof_dev *sdev, u32 flags) BDW_STACK_DUMP_SIZE); snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, BDW_STACK_DUMP_SIZE); + + /* provide some context for firmware debug */ + imrx = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IMRX); + imrd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IMRD); + dev_err(sdev->dev, + "error: ipc host -> DSP: pending %s complete %s raw 0x%8.8x\n", + (panic & SHIM_IPCX_BUSY) ? "yes" : "no", + (panic & SHIM_IPCX_DONE) ? "yes" : "no", panic); + dev_err(sdev->dev, + "error: mask host: pending %s complete %s raw 0x%8.8x\n", + (imrx & SHIM_IMRX_BUSY) ? "yes" : "no", + (imrx & SHIM_IMRX_DONE) ? "yes" : "no", imrx); + dev_err(sdev->dev, + "error: ipc DSP -> host: pending %s complete %s raw 0x%8.8x\n", + (status & SHIM_IPCD_BUSY) ? "yes" : "no", + (status & SHIM_IPCD_DONE) ? "yes" : "no", status); + dev_err(sdev->dev, + "error: mask DSP: pending %s complete %s raw 0x%8.8x\n", + (imrd & SHIM_IMRD_BUSY) ? "yes" : "no", + (imrd & SHIM_IMRD_DONE) ? "yes" : "no", imrd); } /* @@ -451,6 +477,7 @@ static int bdw_probe(struct snd_sof_dev *sdev) /* TODO: add offsets */ sdev->mmio_bar = BDW_DSP_BAR; sdev->mailbox_bar = BDW_DSP_BAR; + sdev->dsp_oops_offset = MBOX_OFFSET; /* PCI base */ mmio = platform_get_resource(pdev, IORESOURCE_MEM, @@ -564,7 +591,14 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { /* DAI drivers */ .drv = bdw_dai, - .num_drv = ARRAY_SIZE(bdw_dai) + .num_drv = ARRAY_SIZE(bdw_dai), + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_BATCH, }; EXPORT_SYMBOL(sof_bdw_ops); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 5e7a6aaa627a..2abf80b3eb52 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -28,6 +28,7 @@ #define MBOX_OFFSET 0x144000 #define MBOX_SIZE 0x1000 #define EXCEPT_OFFSET 0x800 +#define EXCEPT_MAX_HDR_SIZE 0x400 /* DSP peripherals */ #define DMAC0_OFFSET 0x098000 @@ -126,6 +127,11 @@ static void byt_get_registers(struct snd_sof_dev *sdev, /* note: variable AR register array is not read */ /* then get panic info */ + if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) { + dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n", + xoops->arch_hdr.totalsize); + return; + } offset += xoops->arch_hdr.totalsize; sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info)); @@ -139,7 +145,7 @@ static void byt_dump(struct snd_sof_dev *sdev, u32 flags) struct sof_ipc_dsp_oops_xtensa xoops; struct sof_ipc_panic_info panic_info; u32 stack[BYT_STACK_DUMP_SIZE]; - u32 status, panic; + u32 status, panic, imrd, imrx; /* now try generic SOF status messages */ status = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IPCD); @@ -148,6 +154,27 @@ static void byt_dump(struct snd_sof_dev *sdev, u32 flags) BYT_STACK_DUMP_SIZE); snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, BYT_STACK_DUMP_SIZE); + + /* provide some context for firmware debug */ + imrx = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IMRX); + imrd = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IMRD); + dev_err(sdev->dev, + "error: ipc host -> DSP: pending %s complete %s raw 0x%8.8x\n", + (panic & SHIM_IPCX_BUSY) ? "yes" : "no", + (panic & SHIM_IPCX_DONE) ? "yes" : "no", panic); + dev_err(sdev->dev, + "error: mask host: pending %s complete %s raw 0x%8.8x\n", + (imrx & SHIM_IMRX_BUSY) ? "yes" : "no", + (imrx & SHIM_IMRX_DONE) ? "yes" : "no", imrx); + dev_err(sdev->dev, + "error: ipc DSP -> host: pending %s complete %s raw 0x%8.8x\n", + (status & SHIM_IPCD_BUSY) ? "yes" : "no", + (status & SHIM_IPCD_DONE) ? "yes" : "no", status); + dev_err(sdev->dev, + "error: mask DSP: pending %s complete %s raw 0x%8.8x\n", + (imrd & SHIM_IMRD_BUSY) ? "yes" : "no", + (imrd & SHIM_IMRD_DONE) ? "yes" : "no", imrd); + } /* @@ -505,6 +532,13 @@ const struct snd_sof_dsp_ops sof_tng_ops = { /* DAI drivers */ .drv = byt_dai, .num_drv = 3, /* we have only 3 SSPs on byt*/ + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_BATCH, }; EXPORT_SYMBOL(sof_tng_ops); @@ -666,6 +700,13 @@ const struct snd_sof_dsp_ops sof_byt_ops = { /* DAI drivers */ .drv = byt_dai, .num_drv = 3, /* we have only 3 SSPs on byt*/ + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_BATCH, }; EXPORT_SYMBOL(sof_byt_ops); @@ -726,6 +767,13 @@ const struct snd_sof_dsp_ops sof_cht_ops = { .drv = byt_dai, /* all 6 SSPs may be available for cherrytrail */ .num_drv = ARRAY_SIZE(byt_dai), + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_BATCH, }; EXPORT_SYMBOL(sof_cht_ops); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 4ddd73762d81..0e1e265f3f3b 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -17,6 +17,7 @@ #include "../ops.h" #include "hda.h" +#include "hda-ipc.h" static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = { {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, @@ -150,14 +151,45 @@ static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev) CNL_DSP_REG_HIPCCTL_DONE); } +static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg, + u32 *dr, u32 *dd) +{ + struct sof_ipc_pm_gate *pm_gate; + + if (msg->header == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE)) { + pm_gate = msg->msg_data; + + /* send the compact message via the primary register */ + *dr = HDA_IPC_MSG_COMPACT | HDA_IPC_PM_GATE; + + /* send payload via the extended data register */ + *dd = pm_gate->flags; + + return true; + } + + return false; +} + static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { - /* send the message */ - sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, - msg->msg_size); - snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, - CNL_DSP_REG_HIPCIDR_BUSY); + u32 dr = 0; + u32 dd = 0; + + if (cnl_compact_ipc_compress(msg, &dr, &dd)) { + /* send the message via IPC registers */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDD, + dd); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, + CNL_DSP_REG_HIPCIDR_BUSY | dr); + } else { + /* send the message via mailbox */ + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, + CNL_DSP_REG_HIPCIDR_BUSY); + } return 0; } @@ -255,6 +287,14 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .runtime_resume = hda_dsp_runtime_resume, .runtime_idle = hda_dsp_runtime_idle, .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, + .set_power_state = hda_dsp_set_power_state, + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_cnl_ops); @@ -327,3 +367,20 @@ const struct sof_intel_dsp_desc ehl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, }; EXPORT_SYMBOL(ehl_chip_info); + +const struct sof_intel_dsp_desc jsl_chip_info = { + /* Jasperlake */ + .cores_num = 2, + .init_core_mask = 1, + .cores_mask = HDA_DSP_CORE_MASK(0) | + HDA_DSP_CORE_MASK(1), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL(jsl_chip_info); diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 3ca6795a89ba..827f84a0722e 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -84,6 +84,8 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) { #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) struct hdac_hda_priv *hda_priv; + struct snd_soc_acpi_mach_params *mach_params = NULL; + struct snd_sof_pdata *pdata = sdev->pdata; #endif struct hda_bus *hbus = sof_to_hbus(sdev); struct hdac_device *hdev; @@ -113,8 +115,19 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) if (ret < 0) return ret; - /* use legacy bus only for HDA codecs, idisp uses ext bus */ - if ((resp & 0xFFFF0000) != IDISP_VID_INTEL) { + if (pdata->machine) + mach_params = (struct snd_soc_acpi_mach_params *) + &pdata->machine->mach_params; + + if ((resp & 0xFFFF0000) == IDISP_VID_INTEL) + hda_priv->need_display_power = true; + + /* + * if common HDMI codec driver is not used, codec load + * is skipped here and hdac_hdmi is used instead + */ + if ((mach_params && mach_params->common_hdmi_codec_drv) || + (resp & 0xFFFF0000) != IDISP_VID_INTEL) { hdev->type = HDA_DEV_LEGACY; hda_codec_load_module(&hda_priv->codec); } @@ -155,7 +168,8 @@ int hda_codec_probe_bus(struct snd_sof_dev *sdev) } EXPORT_SYMBOL(hda_codec_probe_bus); -#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || \ + IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) void hda_codec_i915_get(struct snd_sof_dev *sdev) { @@ -204,6 +218,6 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev) } EXPORT_SYMBOL(hda_codec_i915_exit); -#endif /* CONFIG_SND_SOC_HDAC_HDMI */ +#endif MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index bc41028a7a01..df1909e1d950 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -139,20 +139,16 @@ void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable) */ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - struct hdac_bus *bus = sof_to_bus(sdev); -#endif u32 val; /* enable/disable audio dsp clock gating */ val = enable ? PCI_CGCTL_ADSPDCGE : 0; snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* enable/disable L1 support */ - val = enable ? SOF_HDA_VS_EM2_L1SEN : 0; - snd_hdac_chip_updatel(bus, VS_EM2, SOF_HDA_VS_EM2_L1SEN, val); -#endif + /* enable/disable DMI Link L1 support */ + val = enable ? HDA_VS_INTEL_EM2_L1SEN : 0; + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_EM2, + HDA_VS_INTEL_EM2_L1SEN, val); /* enable/disable audio dsp power gating */ val = enable ? 0 : PCI_PGCTL_ADSPPGD; diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index fb55a3c5afd0..4a4d318f97ff 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -19,6 +19,7 @@ #include <sound/hda_register.h> #include "../ops.h" #include "hda.h" +#include "hda-ipc.h" /* * DSP Core control. @@ -42,6 +43,12 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) ((adspcs & reset) == reset), HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", + __func__); + return ret; + } /* has core entered reset ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -77,6 +84,13 @@ int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", + __func__); + return ret; + } + /* has core left reset ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS); @@ -151,8 +165,12 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) (adspcs & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); - if (ret < 0) - dev_err(sdev->dev, "error: timeout on core powerup\n"); + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", + __func__); + return ret; + } /* did core power up ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -171,17 +189,24 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) { u32 adspcs; + int ret; /* update bits */ snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, HDA_DSP_ADSPCS_SPA_MASK(core_mask), 0); - return snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, adspcs, !(adspcs & HDA_DSP_ADSPCS_SPA_MASK(core_mask)), HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC); + if (ret < 0) + dev_err(sdev->dev, + "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", + __func__); + + return ret; } bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, @@ -282,6 +307,80 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0); } +static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int retry = HDA_DSP_REG_POLL_RETRY_COUNT; + + while (snd_hdac_chip_readb(bus, VS_D0I3C) & SOF_HDA_VS_D0I3C_CIP) { + if (!retry--) + return -ETIMEDOUT; + usleep_range(10, 15); + } + + return 0; +} + +static int hda_dsp_send_pm_gate_ipc(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_pm_gate pm_gate; + struct sof_ipc_reply reply; + + memset(&pm_gate, 0, sizeof(pm_gate)); + + /* configure pm_gate ipc message */ + pm_gate.hdr.size = sizeof(pm_gate); + pm_gate.hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE; + pm_gate.flags = flags; + + /* send pm_gate ipc to dsp */ + return sof_ipc_tx_message(sdev->ipc, pm_gate.hdr.cmd, &pm_gate, + sizeof(pm_gate), &reply, sizeof(reply)); +} + +int hda_dsp_set_power_state(struct snd_sof_dev *sdev, + enum sof_d0_substate d0_substate) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + u32 flags; + int ret; + u8 value; + + /* Write to D0I3C after Command-In-Progress bit is cleared */ + ret = hda_dsp_wait_d0i3c_done(sdev); + if (ret < 0) { + dev_err(bus->dev, "CIP timeout before D0I3C update!\n"); + return ret; + } + + /* Update D0I3C register */ + value = d0_substate == SOF_DSP_D0I3 ? SOF_HDA_VS_D0I3C_I3 : 0; + snd_hdac_chip_updateb(bus, VS_D0I3C, SOF_HDA_VS_D0I3C_I3, value); + + /* Wait for cmd in progress to be cleared before exiting the function */ + ret = hda_dsp_wait_d0i3c_done(sdev); + if (ret < 0) { + dev_err(bus->dev, "CIP timeout after D0I3C update!\n"); + return ret; + } + + dev_vdbg(bus->dev, "D0I3C updated, register = 0x%x\n", + snd_hdac_chip_readb(bus, VS_D0I3C)); + + if (d0_substate == SOF_DSP_D0I0) + flags = HDA_PM_PPG;/* prevent power gating in D0 */ + else + flags = HDA_PM_NO_DMA_TRACE;/* disable DMA trace in D0I3*/ + + /* sending pm_gate IPC */ + ret = hda_dsp_send_pm_gate_ipc(sdev, flags); + if (ret < 0) + dev_err(sdev->dev, + "error: PM_GATE ipc error %d\n", ret); + + return ret; +} + static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; @@ -379,6 +478,22 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) int hda_dsp_resume(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + struct pci_dev *pci = to_pci_dev(sdev->dev); + + if (sdev->s0_suspend) { + /* restore L1SEN bit */ + if (hda->l1_support_changed) + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + HDA_VS_INTEL_EM2, + HDA_VS_INTEL_EM2_L1SEN, 0); + + /* restore and disable the system wakeup */ + pci_restore_state(pci); + disable_irq_wake(pci->irq); + return 0; + } + /* init hda controller. DSP cores will be powered up during fw boot */ return hda_resume(sdev, false); } @@ -410,9 +525,25 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev) int hda_dsp_suspend(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct hdac_bus *bus = sof_to_bus(sdev); + struct pci_dev *pci = to_pci_dev(sdev->dev); int ret; + if (sdev->s0_suspend) { + /* enable L1SEN to make sure the system can enter S0Ix */ + hda->l1_support_changed = + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + HDA_VS_INTEL_EM2, + HDA_VS_INTEL_EM2_L1SEN, + HDA_VS_INTEL_EM2_L1SEN); + + /* enable the system waking up via IPC IRQ */ + enable_irq_wake(pci->irq); + pci_save_state(pci); + return 0; + } + /* stop hda controller and power dsp off */ ret = hda_suspend(sdev, false); if (ret < 0) { diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 6aae6f18b3dc..0fd2153c1769 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -83,10 +83,12 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) } hdr = msg->msg_data; - if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) { + if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE) || + hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE)) { /* * memory windows are powered off before sending IPC reply, - * so we can't read the mailbox for CTX_SAVE reply. + * so we can't read the mailbox for CTX_SAVE and PM_GATE + * replies. */ reply.error = 0; reply.hdr.cmd = SOF_IPC_GLB_REPLY; diff --git a/sound/soc/sof/intel/hda-ipc.h b/sound/soc/sof/intel/hda-ipc.h new file mode 100644 index 000000000000..aef0ceac9803 --- /dev/null +++ b/sound/soc/sof/intel/hda-ipc.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2019 Intel Corporation. All rights reserved. + * + * Author: Keyon Jie <yang.jie@linux.intel.com> + */ + +#ifndef __SOF_INTEL_HDA_IPC_H +#define __SOF_INTEL_HDA_IPC_H + +/* + * Primary register, mapped to + * - DIPCTDR (HIPCIDR) in sideband IPC (cAVS 1.8+) + * - DIPCT in cAVS 1.5 IPC + * + * Secondary register, mapped to: + * - DIPCTDD (HIPCIDD) in sideband IPC (cAVS 1.8+) + * - DIPCTE in cAVS 1.5 IPC + */ + +/* Common bits in primary register */ + +/* Reserved for doorbell */ +#define HDA_IPC_RSVD_31 BIT(31) +/* Target, 0 - normal message, 1 - compact message(cAVS compatible) */ +#define HDA_IPC_MSG_COMPACT BIT(30) +/* Direction, 0 - request, 1 - response */ +#define HDA_IPC_RSP BIT(29) + +#define HDA_IPC_TYPE_SHIFT 24 +#define HDA_IPC_TYPE_MASK GENMASK(28, 24) +#define HDA_IPC_TYPE(x) ((x) << HDA_IPC_TYPE_SHIFT) + +#define HDA_IPC_PM_GATE HDA_IPC_TYPE(0x8U) + +/* Command specific payload bits in secondary register */ + +/* Disable DMA tracing (0 - keep tracing, 1 - to disable DMA trace) */ +#define HDA_PM_NO_DMA_TRACE BIT(4) +/* Prevent clock gating (0 - cg allowed, 1 - DSP clock always on) */ +#define HDA_PM_PCG BIT(3) +/* Prevent power gating (0 - deep power state transitions allowed) */ +#define HDA_PM_PPG BIT(2) +/* Indicates whether streaming is active */ +#define HDA_PM_PG_STREAMING BIT(1) +#define HDA_PM_PG_RSVD BIT(0) + +#endif diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 6427f0b3a2f1..b1783360fe10 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -44,6 +44,7 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, return -ENODEV; } hstream = &dsp_stream->hstream; + hstream->substream = NULL; /* allocate DMA buffer */ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab); @@ -125,7 +126,8 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, HDA_DSP_INIT_TIMEOUT_US); if (ret < 0) { - dev_err(sdev->dev, "error: waiting for HIPCIE done\n"); + dev_err(sdev->dev, "error: %s: timeout for HIPCIE done\n", + __func__); goto err; } @@ -151,6 +153,10 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, if (!ret) return 0; + dev_err(sdev->dev, + "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", + __func__); + err: hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); hda_dsp_core_reset_power_down(sdev, chip->cores_mask); @@ -252,10 +258,22 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_BASEFW_TIMEOUT_US); + /* + * even in case of errors we still need to stop the DMAs, + * but we return the initial error should the DMA stop also fail + */ + + if (status < 0) { + dev_err(sdev->dev, + "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", + __func__); + } + ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP); if (ret < 0) { dev_err(sdev->dev, "error: DMA trigger stop failed\n"); - return ret; + if (!status) + status = ret; } return status; @@ -340,13 +358,15 @@ cleanup: /* * Perform codeloader stream cleanup. * This should be done even if firmware loading fails. + * If the cleanup also fails, we return the initial error */ ret1 = cl_cleanup(sdev, &sdev->dmab, stream); if (ret1 < 0) { dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); /* set return value to indicate cleanup failure */ - ret = ret1; + if (!ret) + ret = ret1; } /* diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 9b730f183529..575f5f5877d8 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -89,6 +89,7 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct snd_dma_buffer *dmab; + struct sof_ipc_fw_version *v = &sdev->fw_ready.version; int ret; u32 size, rate, bits; @@ -116,9 +117,17 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, /* disable SPIB, to enable buffer wrap for stream */ hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); - /* set host_period_bytes to 0 if no IPC position */ - if (hda && hda->no_ipc_position) - ipc_params->host_period_bytes = 0; + /* update no_stream_position flag for ipc params */ + if (hda && hda->no_ipc_position) { + /* For older ABIs set host_period_bytes to zero to inform + * FW we don't want position updates. Newer versions use + * no_stream_position for this purpose. + */ + if (v->abi_version < SOF_ABI_VER(3, 10, 0)) + ipc_params->host_period_bytes = 0; + else + ipc_params->no_stream_position = 1; + } ipc_params->stream_tag = hstream->stream_tag; diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index ad8d41f22e92..29ab43281670 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -185,6 +185,17 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction) direction == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); + /* + * Disable DMI Link L1 entry when capture stream is opened. + * Workaround to address a known issue with host DMA that results + * in xruns during pause/release in capture scenarios. + */ + if (!IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1)) + if (stream && direction == SNDRV_PCM_STREAM_CAPTURE) + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + HDA_VS_INTEL_EM2, + HDA_VS_INTEL_EM2_L1SEN, 0); + return stream; } @@ -193,23 +204,43 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag) { struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_stream *s; + bool active_capture_stream = false; + bool found = false; spin_lock_irq(&bus->reg_lock); - /* find used stream */ + /* + * close stream matching the stream tag + * and check if there are any open capture streams. + */ list_for_each_entry(s, &bus->stream_list, list) { - if (s->direction == direction && - s->opened && s->stream_tag == stream_tag) { + if (!s->opened) + continue; + + if (s->direction == direction && s->stream_tag == stream_tag) { s->opened = false; - spin_unlock_irq(&bus->reg_lock); - return 0; + found = true; + } else if (s->direction == SNDRV_PCM_STREAM_CAPTURE) { + active_capture_stream = true; } } spin_unlock_irq(&bus->reg_lock); - dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag); - return -ENODEV; + /* Enable DMI L1 entry if there are no capture streams open */ + if (!IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1)) + if (!active_capture_stream) + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + HDA_VS_INTEL_EM2, + HDA_VS_INTEL_EM2_L1SEN, + HDA_VS_INTEL_EM2_L1SEN); + + if (!found) { + dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag); + return -ENODEV; + } + + return 0; } int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, @@ -244,8 +275,12 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_STREAM_RUN_TIMEOUT); - if (ret) + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: cmd %d: timeout on STREAM_SD_OFFSET read\n", + __func__, cmd); return ret; + } hstream->running = true; break; @@ -263,8 +298,12 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_STREAM_RUN_TIMEOUT); - if (ret) + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: cmd %d: timeout on STREAM_SD_OFFSET read\n", + __func__, cmd); return ret; + } snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, @@ -325,8 +364,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_STREAM_RUN_TIMEOUT); - if (ret) + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on STREAM_SD_OFFSET read1\n", + __func__); return ret; + } snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, @@ -387,8 +430,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_STREAM_RUN_TIMEOUT); - if (ret) + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on STREAM_SD_OFFSET read2\n", + __func__); return ret; + } snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index c72e9a09eee1..91bd88fddac7 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -32,8 +32,7 @@ /* platform specific devices */ #include "shim.h" -#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348) -#define IS_CNL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9dc8) +#define EXCEPT_MAX_HDR_SIZE 0x400 /* * Debug @@ -54,6 +53,11 @@ MODULE_PARM_DESC(use_msi, "SOF HDA use PCI MSI mode"); static int hda_dmic_num = -1; module_param_named(dmic_num, hda_dmic_num, int, 0444); MODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number"); + +static bool hda_codec_use_common_hdmi = + IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_COMMON_HDMI_CODEC); +module_param_named(use_common_hdmi, hda_codec_use_common_hdmi, bool, 0444); +MODULE_PARM_DESC(use_common_hdmi, "SOF HDA use common HDMI codec driver"); #endif static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = { @@ -131,6 +135,11 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev, /* note: variable AR register array is not read */ /* then get panic info */ + if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) { + dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n", + xoops->arch_hdr.totalsize); + return; + } offset += xoops->arch_hdr.totalsize; sof_block_read(sdev, sdev->mmio_bar, offset, panic_info, sizeof(*panic_info)); @@ -255,12 +264,9 @@ static int hda_init(struct snd_sof_dev *sdev) /* HDA bus init */ sof_hda_bus_init(bus, &pci->dev); - /* Workaround for a communication error on CFL (bko#199007) and CNL */ - if (IS_CFL(pci) || IS_CNL(pci)) - bus->polling_mode = 1; - bus->use_posbuf = 1; bus->bdl_pos_adj = 0; + bus->sync_write = 1; mutex_init(&hbus->prepare_mutex); hbus->pci = pci; @@ -409,9 +415,16 @@ static int hda_init_caps(struct snd_sof_dev *sdev) pdata->tplg_filename = hda_mach->sof_tplg_filename; - /* firmware: pick the first in machine list */ + /* + * firmware: pick the first in machine list, + * or use nocodec firmware name if list is empty + */ mach = pdata->desc->machines; - pdata->fw_filename = mach->sof_fw_filename; + if (mach->id[0]) + pdata->fw_filename = mach->sof_fw_filename; + else + pdata->fw_filename = + pdata->desc->nocodec_fw_filename; dev_info(bus->dev, "using HDA machine driver %s now\n", hda_mach->drv_name); @@ -458,6 +471,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) &pdata->machine->mach_params; mach_params->codec_mask = bus->codec_mask; mach_params->platform = dev_name(sdev->dev); + mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi; } /* create codec instances */ diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 5591841a1b6f..18d7e72bf9b7 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -39,7 +39,6 @@ #define SOF_HDA_WAKESTS 0x0E #define SOF_HDA_WAKESTS_INT_MASK ((1 << 8) - 1) #define SOF_HDA_RIRBSTS 0x5d -#define SOF_HDA_VS_EM2_L1SEN BIT(13) /* SOF_HDA_GCTL register bist */ #define SOF_HDA_GCTL_RESET BIT(0) @@ -65,6 +64,13 @@ #define SOF_HDA_PPCTL_PIE BIT(31) #define SOF_HDA_PPCTL_GPROCEN BIT(30) +/*Vendor Specific Registers*/ +#define SOF_HDA_VS_D0I3C 0x104A + +/* D0I3C Register fields */ +#define SOF_HDA_VS_D0I3C_CIP BIT(0) /* Command-In-Progress */ +#define SOF_HDA_VS_D0I3C_I3 BIT(2) /* D0i3 enable bit */ + /* DPIB entry size: 8 Bytes = 2 DWords */ #define SOF_HDA_DPIB_ENTRY_SIZE 0x8 @@ -208,6 +214,7 @@ #define HDA_DSP_CTRL_RESET_TIMEOUT 100 #define HDA_DSP_WAIT_TIMEOUT 500 /* 500 msec */ #define HDA_DSP_REG_POLL_INTERVAL_US 500 /* 0.5 msec */ +#define HDA_DSP_REG_POLL_RETRY_COUNT 50 #define HDA_DSP_ADSPIC_IPC 1 #define HDA_DSP_ADSPIS_IPC 1 @@ -228,6 +235,10 @@ #define HDA_DSP_REG_HIPCIE (HDA_DSP_IPC_BASE + 0x0C) #define HDA_DSP_REG_HIPCCTL (HDA_DSP_IPC_BASE + 0x10) +/* Intel Vendor Specific Registers */ +#define HDA_VS_INTEL_EM2 0x1030 +#define HDA_VS_INTEL_EM2_L1SEN BIT(13) + /* HIPCI */ #define HDA_DSP_REG_HIPCI_BUSY BIT(31) #define HDA_DSP_REG_HIPCI_MSG_MASK 0x7FFFFFFF @@ -301,6 +312,7 @@ #define CNL_DSP_REG_HIPCTDD (CNL_DSP_IPC_BASE + 0x08) #define CNL_DSP_REG_HIPCIDR (CNL_DSP_IPC_BASE + 0x10) #define CNL_DSP_REG_HIPCIDA (CNL_DSP_IPC_BASE + 0x14) +#define CNL_DSP_REG_HIPCIDD (CNL_DSP_IPC_BASE + 0x18) #define CNL_DSP_REG_HIPCCTL (CNL_DSP_IPC_BASE + 0x28) /* HIPCI */ @@ -396,6 +408,9 @@ struct sof_intel_hda_dev { int irq; + /* PM related */ + bool l1_support_changed;/* during suspend, is L1SEN changed or not */ + /* DMIC device */ struct platform_device *dmic_dev; }; @@ -452,6 +467,9 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev); void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev); +int hda_dsp_set_power_state(struct snd_sof_dev *sdev, + enum sof_d0_substate d0_substate); + int hda_dsp_suspend(struct snd_sof_dev *sdev); int hda_dsp_resume(struct snd_sof_dev *sdev); int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev); @@ -562,7 +580,9 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev); #endif /* CONFIG_SND_SOC_SOF_HDA */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) && IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) && \ + (IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || \ + IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) void hda_codec_i915_get(struct snd_sof_dev *sdev); void hda_codec_i915_put(struct snd_sof_dev *sdev); @@ -576,7 +596,7 @@ static inline void hda_codec_i915_put(struct snd_sof_dev *sdev) { } static inline int hda_codec_i915_init(struct snd_sof_dev *sdev) { return 0; } static inline int hda_codec_i915_exit(struct snd_sof_dev *sdev) { return 0; } -#endif /* CONFIG_SND_SOC_SOF_HDA && CONFIG_SND_SOC_HDAC_HDMI */ +#endif /* * Trace Control. @@ -593,7 +613,6 @@ extern struct snd_soc_dai_driver skl_dai[]; */ extern const struct snd_sof_dsp_ops sof_apl_ops; extern const struct snd_sof_dsp_ops sof_cnl_ops; -extern const struct snd_sof_dsp_ops sof_skl_ops; extern const struct sof_intel_dsp_desc apl_chip_info; extern const struct sof_intel_dsp_desc cnl_chip_info; @@ -601,5 +620,6 @@ extern const struct sof_intel_dsp_desc skl_chip_info; extern const struct sof_intel_dsp_desc icl_chip_info; extern const struct sof_intel_dsp_desc tgl_chip_info; extern const struct sof_intel_dsp_desc ehl_chip_info; +extern const struct sof_intel_dsp_desc jsl_chip_info; #endif |