diff options
-rw-r--r-- | include/sound/sof/ext_manifest.h | 1 | ||||
-rw-r--r-- | sound/soc/sof/intel/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/sof/intel/apl.c | 3 | ||||
-rw-r--r-- | sound/soc/sof/intel/cnl.c | 19 | ||||
-rw-r--r-- | sound/soc/sof/intel/ext_manifest.h | 35 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda-loader.c | 100 | ||||
-rw-r--r-- | sound/soc/sof/intel/hda.h | 11 | ||||
-rw-r--r-- | sound/soc/sof/intel/icl.c | 145 | ||||
-rw-r--r-- | sound/soc/sof/intel/tgl.c | 3 | ||||
-rw-r--r-- | sound/soc/sof/loader.c | 3 | ||||
-rw-r--r-- | sound/soc/sof/ops.h | 14 | ||||
-rw-r--r-- | sound/soc/sof/sof-pci-dev.c | 2 | ||||
-rw-r--r-- | sound/soc/sof/sof-priv.h | 7 |
13 files changed, 324 insertions, 21 deletions
diff --git a/include/sound/sof/ext_manifest.h b/include/sound/sof/ext_manifest.h index e05cb21023e5..7abc4f0bd3ad 100644 --- a/include/sound/sof/ext_manifest.h +++ b/include/sound/sof/ext_manifest.h @@ -62,6 +62,7 @@ enum sof_ext_man_elem_type { SOF_EXT_MAN_ELEM_CC_VERSION = SOF_IPC_EXT_CC_INFO, SOF_EXT_MAN_ELEM_DBG_ABI = SOF_IPC_EXT_USER_ABI_INFO, SOF_EXT_MAN_ELEM_CONFIG_DATA = 5, /**< ABI3.17 */ + SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA = 6, }; /* extended manifest element header */ diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index 72d85b25df7d..2589111c2fae 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -8,7 +8,7 @@ snd-sof-intel-ipc-objs := intel-ipc.o snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ hda-dai.o hda-bus.o \ - apl.o cnl.o tgl.o + apl.o cnl.o tgl.o icl.o snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-compress.o snd-sof-intel-hda-objs := hda-codec.o diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 4eeade2e77f7..fc29b91b8932 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -92,6 +92,9 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .pre_fw_run = hda_dsp_pre_fw_run, .post_fw_run = hda_dsp_post_fw_run, + /* parse platform specific extended manifest */ + .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, + /* dsp core power up/down */ .core_power_up = hda_dsp_enable_core, .core_power_down = hda_dsp_core_reset_power_down, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index a5d3258104c0..e38db519f38d 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -294,6 +294,9 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .pre_fw_run = hda_dsp_pre_fw_run, .post_fw_run = hda_dsp_post_fw_run, + /* parse platform specific extended manifest */ + .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, + /* dsp core power up/down */ .core_power_up = hda_dsp_enable_core, .core_power_down = hda_dsp_core_reset_power_down, @@ -346,22 +349,6 @@ const struct sof_intel_dsp_desc cnl_chip_info = { }; EXPORT_SYMBOL_NS(cnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); -const struct sof_intel_dsp_desc icl_chip_info = { - /* Icelake */ - .cores_num = 4, - .init_core_mask = 1, - .host_managed_cores_mask = GENMASK(3, 0), - .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_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); - const struct sof_intel_dsp_desc ehl_chip_info = { /* Elkhartlake */ .cores_num = 4, diff --git a/sound/soc/sof/intel/ext_manifest.h b/sound/soc/sof/intel/ext_manifest.h new file mode 100644 index 000000000000..2dfae9285d3c --- /dev/null +++ b/sound/soc/sof/intel/ext_manifest.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) 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) 2020 Intel Corporation. All rights reserved. + */ + +/* + * Intel extended manifest is a extra place to store Intel cavs specific + * metadata about firmware, for example LPRO/HPRO configuration is + * Intel cavs specific. This part of output binary is not signed. + */ + +#ifndef __INTEL_CAVS_EXT_MANIFEST_H__ +#define __INTEL_CAVS_EXT_MANIFEST_H__ + +#include <sound/sof/ext_manifest.h> + +/* EXT_MAN_ELEM_PLATFORM_CONFIG_DATA elements identificators */ +enum sof_cavs_config_elem_type { + SOF_EXT_MAN_CAVS_CONFIG_EMPTY = 0, + SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO = 1, + SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE = 2, + SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE = 3, +}; + +/* EXT_MAN_ELEM_PLATFORM_CONFIG_DATA elements */ +struct sof_ext_man_cavs_config_data { + struct sof_ext_man_elem_header hdr; + + struct sof_config_elem elems[]; +} __packed; + +#endif /* __INTEL_CAVS_EXT_MANIFEST_H__ */ diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 2707a16c6a4d..02c3ff897274 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -19,6 +19,7 @@ #include <sound/hdaudio_ext.h> #include <sound/hda_register.h> #include <sound/sof.h> +#include "ext_manifest.h" #include "../ops.h" #include "hda.h" @@ -470,3 +471,102 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) /* re-enable clock gating and power gating */ return hda_dsp_ctrl_clock_power_gating(sdev, true); } + +/* + * post fw run operations for ICL, + * Core 3 will be powered up and in stall when HPRO is enabled + */ +int hda_dsp_post_fw_run_icl(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + int ret; + + if (sdev->first_boot) { + ret = hda_sdw_startup(sdev); + if (ret < 0) { + dev_err(sdev->dev, + "error: could not startup SoundWire links\n"); + return ret; + } + } + + hda_sdw_int_enable(sdev, true); + + /* + * The recommended HW programming sequence for ICL is to + * power up core 3 and keep it in stall if HPRO is enabled. + * Major difference between ICL and TGL, on ICL core 3 is managed by + * the host whereas on TGL it is handled by the firmware. + */ + if (!hda->clk_config_lpro) { + ret = snd_sof_dsp_core_power_up(sdev, BIT(3)); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core power up failed on core 3\n"); + return ret; + } + + snd_sof_dsp_stall(sdev, BIT(3)); + } + + /* re-enable clock gating and power gating */ + return hda_dsp_ctrl_clock_power_gating(sdev, true); +} + +int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, + const struct sof_ext_man_elem_header *hdr) +{ + const struct sof_ext_man_cavs_config_data *config_data = + container_of(hdr, struct sof_ext_man_cavs_config_data, hdr); + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + int i, elem_num; + + /* calculate total number of config data elements */ + elem_num = (hdr->size - sizeof(struct sof_ext_man_elem_header)) + / sizeof(struct sof_config_elem); + if (elem_num <= 0) { + dev_err(sdev->dev, "cavs config data is inconsistent: %d\n", elem_num); + return -EINVAL; + } + + for (i = 0; i < elem_num; i++) + switch (config_data->elems[i].token) { + case SOF_EXT_MAN_CAVS_CONFIG_EMPTY: + /* skip empty token */ + break; + case SOF_EXT_MAN_CAVS_CONFIG_CAVS_LPRO: + hda->clk_config_lpro = config_data->elems[i].value; + dev_dbg(sdev->dev, "FW clock config: %s\n", + hda->clk_config_lpro ? "LPRO" : "HPRO"); + break; + case SOF_EXT_MAN_CAVS_CONFIG_OUTBOX_SIZE: + case SOF_EXT_MAN_CAVS_CONFIG_INBOX_SIZE: + /* These elements are defined but not being used yet. No warn is required */ + break; + default: + dev_info(sdev->dev, "unsupported token type: %d\n", + config_data->elems[i].token); + } + + return 0; +} + +int hda_dsp_core_stall_icl(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + + /* make sure core_mask in host managed cores */ + core_mask &= chip->host_managed_cores_mask; + if (!core_mask) { + dev_err(sdev->dev, "error: core_mask is not in host managed cores\n"); + return -EINVAL; + } + + /* stall core */ + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), + HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); + + return 0; +} diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 75954e642c5e..9ec8ae0fd649 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -447,6 +447,9 @@ struct sof_intel_hda_dev { /* sdw context allocated by SoundWire driver */ struct sdw_intel_ctx *sdw; + + /* FW clock config, 0:HPRO, 1:LPRO */ + bool clk_config_lpro; }; static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s) @@ -612,11 +615,18 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); */ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev); int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev); +int hda_dsp_cl_boot_firmware_iccmax_icl(struct snd_sof_dev *sdev); int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev); /* pre and post fw run ops */ int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev); int hda_dsp_post_fw_run(struct snd_sof_dev *sdev); +int hda_dsp_post_fw_run_icl(struct snd_sof_dev *sdev); +int hda_dsp_core_stall_icl(struct snd_sof_dev *sdev, unsigned int core_mask); + +/* parse platform specific ext manifest ops */ +int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, + const struct sof_ext_man_elem_header *hdr); /* * HDA Controller Operations. @@ -733,6 +743,7 @@ 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_tgl_ops; +extern const struct snd_sof_dsp_ops sof_icl_ops; extern const struct sof_intel_dsp_desc apl_chip_info; extern const struct sof_intel_dsp_desc cnl_chip_info; diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c new file mode 100644 index 000000000000..e9d5a0a58504 --- /dev/null +++ b/sound/soc/sof/intel/icl.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright(c) 2020 Intel Corporation. All rights reserved. +// +// Author: Fred Oh <fred.oh@linux.intel.com> +// + +/* + * Hardware interface for audio DSP on IceLake. + */ + +#include <linux/kernel.h> +#include <linux/kconfig.h> +#include <linux/export.h> +#include <linux/bits.h> +#include "../ops.h" +#include "hda.h" +#include "hda-ipc.h" +#include "../sof-audio.h" + +static const struct snd_sof_debugfs_map icl_dsp_debugfs[] = { + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, +}; + +/* Icelake ops */ +const struct snd_sof_dsp_ops sof_icl_ops = { + /* probe and remove */ + .probe = hda_dsp_probe, + .remove = hda_dsp_remove, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* doorbell */ + .irq_thread = cnl_ipc_irq_thread, + + /* ipc */ + .send_msg = cnl_ipc_send_msg, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset, + .get_window_offset = hda_dsp_ipc_get_window_offset, + + .ipc_msg_data = hda_ipc_msg_data, + .ipc_pcm_params = hda_ipc_pcm_params, + + /* machine driver */ + .machine_select = hda_machine_select, + .machine_register = sof_machine_register, + .machine_unregister = sof_machine_unregister, + .set_mach_params = hda_set_mach_params, + + /* debug */ + .debug_map = icl_dsp_debugfs, + .debug_map_count = ARRAY_SIZE(icl_dsp_debugfs), + .dbg_dump = hda_dsp_dump, + .ipc_dump = cnl_ipc_dump, + + /* stream callbacks */ + .pcm_open = hda_dsp_pcm_open, + .pcm_close = hda_dsp_pcm_close, + .pcm_hw_params = hda_dsp_pcm_hw_params, + .pcm_hw_free = hda_dsp_stream_hw_free, + .pcm_trigger = hda_dsp_pcm_trigger, + .pcm_pointer = hda_dsp_pcm_pointer, + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES) + /* probe callbacks */ + .probe_assign = hda_probe_compr_assign, + .probe_free = hda_probe_compr_free, + .probe_set_params = hda_probe_compr_set_params, + .probe_trigger = hda_probe_compr_trigger, + .probe_pointer = hda_probe_compr_pointer, +#endif + + /* firmware loading */ + .load_firmware = snd_sof_load_firmware_raw, + + /* pre/post fw run */ + .pre_fw_run = hda_dsp_pre_fw_run, + .post_fw_run = hda_dsp_post_fw_run_icl, + + /* parse platform specific extended manifest */ + .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, + + /* dsp core power up/down */ + .core_power_up = hda_dsp_enable_core, + .core_power_down = hda_dsp_core_reset_power_down, + + /* firmware run */ + .run = hda_dsp_cl_boot_firmware_iccmax, + .stall = hda_dsp_core_stall_icl, + + /* trace callback */ + .trace_init = hda_dsp_trace_init, + .trace_release = hda_dsp_trace_release, + .trace_trigger = hda_dsp_trace_trigger, + + /* DAI drivers */ + .drv = skl_dai, + .num_drv = SOF_SKL_NUM_DAIS, + + /* PM */ + .suspend = hda_dsp_suspend, + .resume = hda_dsp_resume, + .runtime_suspend = hda_dsp_runtime_suspend, + .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, + + .arch_ops = &sof_xtensa_arch_ops, +}; +EXPORT_SYMBOL_NS(sof_icl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); + +const struct sof_intel_dsp_desc icl_chip_info = { + /* Icelake */ + .cores_num = 4, + .init_core_mask = 1, + .host_managed_cores_mask = GENMASK(3, 0), + .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_NS(icl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index bdcc66d0df78..2252ca38ff4b 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -84,6 +84,9 @@ const struct snd_sof_dsp_ops sof_tgl_ops = { .pre_fw_run = hda_dsp_pre_fw_run, .post_fw_run = hda_dsp_post_fw_run, + /* parse platform specific extended manifest */ + .parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data, + /* dsp core power up/down */ .core_power_up = hda_dsp_enable_core, .core_power_down = hda_dsp_core_reset_power_down, diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 2a8c9bff9963..cbce484b6469 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -330,6 +330,9 @@ static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev, case SOF_EXT_MAN_ELEM_CONFIG_DATA: ret = ext_man_get_config_data(sdev, elem_hdr); break; + case SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA: + ret = snd_sof_dsp_parse_platform_ext_manifest(sdev, elem_hdr); + break; default: dev_info(sdev->dev, "unknown sof_ext_man header type %d size 0x%X\n", elem_hdr->type, elem_hdr->size); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index b21632f5511a..95e748b36903 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -48,10 +48,10 @@ static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev) return sof_ops(sdev)->run(sdev); } -static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev) +static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev, unsigned int core_mask) { if (sof_ops(sdev)->stall) - return sof_ops(sdev)->stall(sdev); + return sof_ops(sdev)->stall(sdev, core_mask); return 0; } @@ -100,6 +100,16 @@ static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev) return 0; } +/* parse platform specific extended manifest */ +static inline int snd_sof_dsp_parse_platform_ext_manifest(struct snd_sof_dev *sdev, + const struct sof_ext_man_elem_header *hdr) +{ + if (sof_ops(sdev)->parse_platform_ext_manifest) + return sof_ops(sdev)->parse_platform_ext_manifest(sdev, hdr); + + return 0; +} + /* misc */ /** diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index f2a107481336..153d66d5c948 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -209,7 +209,7 @@ static const struct sof_dev_desc icl_desc = { .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-icl.ri", .nocodec_tplg_filename = "sof-icl-nocodec.tplg", - .ops = &sof_cnl_ops, + .ops = &sof_icl_ops, }; #endif diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index d8bc0178dc89..9ba3e3ceed01 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -18,6 +18,7 @@ #include <sound/sof/pm.h> #include <sound/sof/trace.h> #include <uapi/sound/sof/fw.h> +#include <sound/sof/ext_manifest.h> /* debug flags */ #define SOF_DBG_ENABLE_TRACE BIT(0) @@ -100,7 +101,7 @@ struct snd_sof_dsp_ops { /* DSP core boot / reset */ int (*run)(struct snd_sof_dev *sof_dev); /* mandatory */ - int (*stall)(struct snd_sof_dev *sof_dev); /* optional */ + int (*stall)(struct snd_sof_dev *sof_dev, unsigned int core_mask); /* optional */ int (*reset)(struct snd_sof_dev *sof_dev); /* optional */ int (*core_power_up)(struct snd_sof_dev *sof_dev, unsigned int core_mask); /* optional */ @@ -208,6 +209,10 @@ struct snd_sof_dsp_ops { int (*pre_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ int (*post_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ + /* parse platform specific extended manifest, optional */ + int (*parse_platform_ext_manifest)(struct snd_sof_dev *sof_dev, + const struct sof_ext_man_elem_header *hdr); + /* DSP PM */ int (*suspend)(struct snd_sof_dev *sof_dev, u32 target_state); /* optional */ |