diff options
author | Takashi Iwai <tiwai@suse.de> | 2024-03-11 16:18:47 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2024-03-11 16:18:47 +0100 |
commit | f5d9ddf1214bf878ca69c905c2f410c5b51de99c (patch) | |
tree | 3ea7bf6f519a490f72cf5f9023b5c0a6dff0fea0 /sound/soc/intel/avs | |
parent | 6719cd5e45111449f4021e08f2e488f17a9b292b (diff) | |
parent | 6c023ad32b192dea51a4f842cc6ecf89bb6238c9 (diff) | |
download | linux-f5d9ddf1214bf878ca69c905c2f410c5b51de99c.tar.gz linux-f5d9ddf1214bf878ca69c905c2f410c5b51de99c.tar.bz2 linux-f5d9ddf1214bf878ca69c905c2f410c5b51de99c.zip |
Merge tag 'asoc-v6.9' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Updates for v6.9
This has been quite a small release, there's a lot of driver specific
cleanups and minor enhancements but hardly anything on the core and only
one new driver. Highlights include:
- SoundWire support for AMD ACP 6.3 systems.
- Support for reporting version information for AVS firmware.
- Support DSPless mode for Intel Soundwire systems.
- Support for configuring CS35L56 amplifiers using EFI calibration
data.
- Log which component is being operated on as part of power management
trace events.
- Support for Microchip SAM9x7, NXP i.MX95 and Qualcomm WCD939x
Diffstat (limited to 'sound/soc/intel/avs')
-rw-r--r-- | sound/soc/intel/avs/Makefile | 5 | ||||
-rw-r--r-- | sound/soc/intel/avs/apl.c | 58 | ||||
-rw-r--r-- | sound/soc/intel/avs/avs.h | 70 | ||||
-rw-r--r-- | sound/soc/intel/avs/board_selection.c | 85 | ||||
-rw-r--r-- | sound/soc/intel/avs/cnl.c | 61 | ||||
-rw-r--r-- | sound/soc/intel/avs/core.c | 161 | ||||
-rw-r--r-- | sound/soc/intel/avs/icl.c | 197 | ||||
-rw-r--r-- | sound/soc/intel/avs/ipc.c | 66 | ||||
-rw-r--r-- | sound/soc/intel/avs/loader.c | 2 | ||||
-rw-r--r-- | sound/soc/intel/avs/messages.c | 1 | ||||
-rw-r--r-- | sound/soc/intel/avs/messages.h | 38 | ||||
-rw-r--r-- | sound/soc/intel/avs/path.c | 33 | ||||
-rw-r--r-- | sound/soc/intel/avs/pcm.c | 77 | ||||
-rw-r--r-- | sound/soc/intel/avs/registers.h | 21 | ||||
-rw-r--r-- | sound/soc/intel/avs/skl.c | 59 | ||||
-rw-r--r-- | sound/soc/intel/avs/sysfs.c | 35 | ||||
-rw-r--r-- | sound/soc/intel/avs/tgl.c | 54 | ||||
-rw-r--r-- | sound/soc/intel/avs/topology.c | 164 | ||||
-rw-r--r-- | sound/soc/intel/avs/topology.h | 13 |
19 files changed, 1055 insertions, 145 deletions
diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile index 460ee6599daf..5480500337f8 100644 --- a/sound/soc/intel/avs/Makefile +++ b/sound/soc/intel/avs/Makefile @@ -1,9 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \ - topology.o path.o pcm.o board_selection.o control.o + topology.o path.o pcm.o board_selection.o control.o \ + sysfs.o snd-soc-avs-objs += cldma.o -snd-soc-avs-objs += skl.o apl.o +snd-soc-avs-objs += skl.o apl.o cnl.o icl.o tgl.o snd-soc-avs-objs += trace.o # tell define_trace.h where to find the trace header diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c index 1860099c782a..c21ecaef9eba 100644 --- a/sound/soc/intel/avs/apl.c +++ b/sound/soc/intel/avs/apl.c @@ -13,11 +13,11 @@ #include "path.h" #include "topology.h" -static int __maybe_unused -apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, - u32 fifo_full_period, unsigned long resource_mask, u32 *priorities) +#ifdef CONFIG_DEBUG_FS +int avs_apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, + u32 fifo_full_period, unsigned long resource_mask, u32 *priorities) { - struct apl_log_state_info *info; + struct avs_apl_log_state_info *info; u32 size, num_cores = adev->hw_cfg.dsp_cores; int ret, i; @@ -47,10 +47,11 @@ apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_peri return 0; } +#endif -static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg) +int avs_apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg) { - struct apl_log_buffer_layout layout; + struct avs_apl_log_buffer_layout layout; void __iomem *addr, *buf; addr = avs_log_buffer_addr(adev, msg->log.core); @@ -63,11 +64,11 @@ static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg /* consume the logs regardless of consumer presence */ goto update_read_ptr; - buf = apl_log_payload_addr(addr); + buf = avs_apl_log_payload_addr(addr); if (layout.read_ptr > layout.write_ptr) { avs_dump_fw_log(adev, buf + layout.read_ptr, - apl_log_payload_size(adev) - layout.read_ptr); + avs_apl_log_payload_size(adev) - layout.read_ptr); layout.read_ptr = 0; } avs_dump_fw_log_wakeup(adev, buf + layout.read_ptr, layout.write_ptr - layout.read_ptr); @@ -77,7 +78,8 @@ update_read_ptr: return 0; } -static int apl_wait_log_entry(struct avs_dev *adev, u32 core, struct apl_log_buffer_layout *layout) +static int avs_apl_wait_log_entry(struct avs_dev *adev, u32 core, + struct avs_apl_log_buffer_layout *layout) { unsigned long timeout; void __iomem *addr; @@ -99,11 +101,11 @@ static int apl_wait_log_entry(struct avs_dev *adev, u32 core, struct apl_log_buf } /* reads log header and tests its type */ -#define apl_is_entry_stackdump(addr) ((readl(addr) >> 30) & 0x1) +#define avs_apl_is_entry_stackdump(addr) ((readl(addr) >> 30) & 0x1) -static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg) +int avs_apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg) { - struct apl_log_buffer_layout layout; + struct avs_apl_log_buffer_layout layout; void __iomem *addr, *buf; size_t dump_size; u16 offset = 0; @@ -124,9 +126,9 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg) if (!addr) goto exit; - buf = apl_log_payload_addr(addr); + buf = avs_apl_log_payload_addr(addr); memcpy_fromio(&layout, addr, sizeof(layout)); - if (!apl_is_entry_stackdump(buf + layout.read_ptr)) { + if (!avs_apl_is_entry_stackdump(buf + layout.read_ptr)) { union avs_notify_msg lbs_msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS); /* @@ -142,11 +144,11 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg) do { u32 count; - if (apl_wait_log_entry(adev, msg->ext.coredump.core_id, &layout)) + if (avs_apl_wait_log_entry(adev, msg->ext.coredump.core_id, &layout)) break; if (layout.read_ptr > layout.write_ptr) { - count = apl_log_payload_size(adev) - layout.read_ptr; + count = avs_apl_log_payload_size(adev) - layout.read_ptr; memcpy_fromio(pos + offset, buf + layout.read_ptr, count); layout.read_ptr = 0; offset += count; @@ -165,7 +167,7 @@ exit: return 0; } -static bool apl_lp_streaming(struct avs_dev *adev) +static bool avs_apl_lp_streaming(struct avs_dev *adev) { struct avs_path *path; @@ -201,7 +203,7 @@ static bool apl_lp_streaming(struct avs_dev *adev) return true; } -static bool apl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake) +bool avs_apl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake) { /* wake in all cases */ if (wake) @@ -215,10 +217,10 @@ static bool apl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool w * Note: for cAVS 1.5+ and 1.8, D0IX is LP-firmware transition, * not the power-gating mechanism known from cAVS 2.0. */ - return apl_lp_streaming(adev); + return avs_apl_lp_streaming(adev); } -static int apl_set_d0ix(struct avs_dev *adev, bool enable) +int avs_apl_set_d0ix(struct avs_dev *adev, bool enable) { bool streaming = false; int ret; @@ -231,20 +233,20 @@ static int apl_set_d0ix(struct avs_dev *adev, bool enable) return AVS_IPC_RET(ret); } -const struct avs_dsp_ops apl_dsp_ops = { +const struct avs_dsp_ops avs_apl_dsp_ops = { .power = avs_dsp_core_power, .reset = avs_dsp_core_reset, .stall = avs_dsp_core_stall, - .irq_handler = avs_dsp_irq_handler, - .irq_thread = avs_dsp_irq_thread, + .irq_handler = avs_irq_handler, + .irq_thread = avs_skl_irq_thread, .int_control = avs_dsp_interrupt_control, .load_basefw = avs_hda_load_basefw, .load_lib = avs_hda_load_library, .transfer_mods = avs_hda_transfer_modules, - .log_buffer_offset = skl_log_buffer_offset, - .log_buffer_status = apl_log_buffer_status, - .coredump = apl_coredump, - .d0ix_toggle = apl_d0ix_toggle, - .set_d0ix = apl_set_d0ix, + .log_buffer_offset = avs_skl_log_buffer_offset, + .log_buffer_status = avs_apl_log_buffer_status, + .coredump = avs_apl_coredump, + .d0ix_toggle = avs_apl_d0ix_toggle, + .set_d0ix = avs_apl_set_d0ix, AVS_SET_ENABLE_LOGS_OP(apl) }; diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h index d694e08e44e1..f80f79415344 100644 --- a/sound/soc/intel/avs/avs.h +++ b/sound/soc/intel/avs/avs.h @@ -46,8 +46,8 @@ struct avs_dsp_ops { int (* const power)(struct avs_dev *, u32, bool); int (* const reset)(struct avs_dev *, u32, bool); int (* const stall)(struct avs_dev *, u32, bool); - irqreturn_t (* const irq_handler)(int, void *); - irqreturn_t (* const irq_thread)(int, void *); + irqreturn_t (* const irq_handler)(struct avs_dev *); + irqreturn_t (* const irq_thread)(struct avs_dev *); void (* const int_control)(struct avs_dev *, bool); int (* const load_basefw)(struct avs_dev *, struct firmware *); int (* const load_lib)(struct avs_dev *, struct firmware *, u32); @@ -64,8 +64,11 @@ struct avs_dsp_ops { #define avs_dsp_op(adev, op, ...) \ ((adev)->spec->dsp_ops->op(adev, ## __VA_ARGS__)) -extern const struct avs_dsp_ops skl_dsp_ops; -extern const struct avs_dsp_ops apl_dsp_ops; +extern const struct avs_dsp_ops avs_skl_dsp_ops; +extern const struct avs_dsp_ops avs_apl_dsp_ops; +extern const struct avs_dsp_ops avs_cnl_dsp_ops; +extern const struct avs_dsp_ops avs_icl_dsp_ops; +extern const struct avs_dsp_ops avs_tgl_dsp_ops; #define AVS_PLATATTR_CLDMA BIT_ULL(0) #define AVS_PLATATTR_IMR BIT_ULL(1) @@ -73,6 +76,23 @@ extern const struct avs_dsp_ops apl_dsp_ops; #define avs_platattr_test(adev, attr) \ ((adev)->spec->attributes & AVS_PLATATTR_##attr) +struct avs_sram_spec { + const u32 base_offset; + const u32 window_size; + const u32 rom_status_offset; +}; + +struct avs_hipc_spec { + const u32 req_offset; + const u32 req_ext_offset; + const u32 req_busy_mask; + const u32 ack_offset; + const u32 ack_done_mask; + const u32 rsp_offset; + const u32 rsp_busy_mask; + const u32 ctl_offset; +}; + /* Platform specific descriptor */ struct avs_spec { const char *name; @@ -82,9 +102,8 @@ struct avs_spec { const u32 core_init_mask; /* used during DSP boot */ const u64 attributes; /* bitmask of AVS_PLATATTR_* */ - const u32 sram_base_offset; - const u32 sram_window_size; - const u32 rom_status; + const struct avs_sram_spec *sram; + const struct avs_hipc_spec *hipc; }; struct avs_fw_entry { @@ -127,6 +146,7 @@ struct avs_dev { int *core_refs; /* reference count per core */ char **lib_names; int num_lp_paths; + atomic_t l1sen_counter; /* controls whether L1SEN should be disabled */ struct completion fw_ready; struct work_struct probe_work; @@ -225,8 +245,7 @@ struct avs_ipc { #define AVS_IPC_RET(ret) \ (((ret) <= 0) ? (ret) : -AVS_EIPC) -irqreturn_t avs_dsp_irq_handler(int irq, void *dev_id); -irqreturn_t avs_dsp_irq_thread(int irq, void *dev_id); +irqreturn_t avs_irq_handler(struct avs_dev *adev); void avs_dsp_process_response(struct avs_dev *adev, u64 header); int avs_dsp_send_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request, struct avs_ipc_msg *reply, int timeout, const char *name); @@ -248,7 +267,20 @@ void avs_ipc_block(struct avs_ipc *ipc); int avs_dsp_disable_d0ix(struct avs_dev *adev); int avs_dsp_enable_d0ix(struct avs_dev *adev); -int skl_log_buffer_offset(struct avs_dev *adev, u32 core); +irqreturn_t avs_skl_irq_thread(struct avs_dev *adev); +irqreturn_t avs_cnl_irq_thread(struct avs_dev *adev); +int avs_apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, + u32 fifo_full_period, unsigned long resource_mask, u32 *priorities); +int avs_icl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, + u32 fifo_full_period, unsigned long resource_mask, u32 *priorities); +int avs_skl_log_buffer_offset(struct avs_dev *adev, u32 core); +int avs_icl_log_buffer_offset(struct avs_dev *adev, u32 core); +int avs_apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg); +int avs_apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg); +bool avs_apl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake); +bool avs_icl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake); +int avs_apl_set_d0ix(struct avs_dev *adev, bool enable); +int avs_icl_set_d0ix(struct avs_dev *adev, bool enable); /* Firmware resources management */ @@ -293,6 +325,8 @@ int avs_hda_load_library(struct avs_dev *adev, struct firmware *lib, u32 id); int avs_hda_transfer_modules(struct avs_dev *adev, bool load, struct avs_module_entry *mods, u32 num_mods); +int avs_icl_load_basefw(struct avs_dev *adev, struct firmware *fw); + /* Soc component members */ struct avs_soc_component { @@ -342,21 +376,21 @@ static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_n return ret; } -struct apl_log_buffer_layout { +struct avs_apl_log_buffer_layout { u32 read_ptr; u32 write_ptr; u8 buffer[]; } __packed; -#define apl_log_payload_size(adev) \ - (avs_log_buffer_size(adev) - sizeof(struct apl_log_buffer_layout)) +#define avs_apl_log_payload_size(adev) \ + (avs_log_buffer_size(adev) - sizeof(struct avs_apl_log_buffer_layout)) -#define apl_log_payload_addr(addr) \ - (addr + sizeof(struct apl_log_buffer_layout)) +#define avs_apl_log_payload_addr(addr) \ + (addr + sizeof(struct avs_apl_log_buffer_layout)) #ifdef CONFIG_DEBUG_FS #define AVS_SET_ENABLE_LOGS_OP(name) \ - .enable_logs = name##_enable_logs + .enable_logs = avs_##name##_enable_logs bool avs_logging_fw(struct avs_dev *adev); void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len); @@ -392,4 +426,8 @@ static inline void avs_debugfs_init(struct avs_dev *adev) { } static inline void avs_debugfs_exit(struct avs_dev *adev) { } #endif +/* Filesystems integration */ + +extern const struct attribute_group *avs_attr_groups[]; + #endif /* __SOUND_SOC_INTEL_AVS_H */ diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 8e91eece992d..8360ce557401 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -236,6 +236,82 @@ static struct snd_soc_acpi_mach avs_gml_i2s_machines[] = { {}, }; +static struct snd_soc_acpi_mach avs_cnl_i2s_machines[] = { + { + .id = "INT34C2", + .drv_name = "avs_rt274", + .mach_params = { + .i2s_link_mask = AVS_SSP(0), + }, + .tplg_filename = "rt274-tplg.bin", + }, + { + .id = "10EC5682", + .drv_name = "avs_rt5682", + .mach_params = { + .i2s_link_mask = AVS_SSP(1), + }, + .tplg_filename = "rt5682-tplg.bin", + }, + {}, +}; + +static struct snd_soc_acpi_mach avs_icl_i2s_machines[] = { + { + .id = "INT343A", + .drv_name = "avs_rt298", + .mach_params = { + .i2s_link_mask = AVS_SSP(0), + }, + .tplg_filename = "rt298-tplg.bin", + }, + { + .id = "INT34C2", + .drv_name = "avs_rt274", + .mach_params = { + .i2s_link_mask = AVS_SSP(0), + }, + .tplg_filename = "rt274-tplg.bin", + }, + {}, +}; + +static struct snd_soc_acpi_mach avs_tgl_i2s_machines[] = { + { + .id = "INT34C2", + .drv_name = "avs_rt274", + .mach_params = { + .i2s_link_mask = AVS_SSP(0), + }, + .tplg_filename = "rt274-tplg.bin", + }, + { + .id = "10EC0298", + .drv_name = "avs_rt298", + .mach_params = { + .i2s_link_mask = AVS_SSP(0), + }, + .tplg_filename = "rt298-tplg.bin", + }, + { + .id = "10EC1308", + .drv_name = "avs_rt1308", + .mach_params = { + .i2s_link_mask = AVS_SSP(1), + }, + .tplg_filename = "rt1308-tplg.bin", + }, + { + .id = "ESSX8336", + .drv_name = "avs_es8336", + .mach_params = { + .i2s_link_mask = AVS_SSP(0), + }, + .tplg_filename = "es8336-tplg.bin", + }, + {}, +}; + static struct snd_soc_acpi_mach avs_test_i2s_machines[] = { { .drv_name = "avs_i2s_test", @@ -296,6 +372,15 @@ static const struct avs_acpi_boards i2s_boards[] = { AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines), AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines), AVS_MACH_ENTRY(HDA_GML, avs_gml_i2s_machines), + AVS_MACH_ENTRY(HDA_CNL_LP, avs_cnl_i2s_machines), + AVS_MACH_ENTRY(HDA_CNL_H, avs_cnl_i2s_machines), + AVS_MACH_ENTRY(HDA_CML_LP, avs_cnl_i2s_machines), + AVS_MACH_ENTRY(HDA_ICL_LP, avs_icl_i2s_machines), + AVS_MACH_ENTRY(HDA_TGL_LP, avs_tgl_i2s_machines), + AVS_MACH_ENTRY(HDA_EHL_0, avs_tgl_i2s_machines), + AVS_MACH_ENTRY(HDA_ADL_P, avs_tgl_i2s_machines), + AVS_MACH_ENTRY(HDA_RPL_P_0, avs_tgl_i2s_machines), + AVS_MACH_ENTRY(HDA_RPL_M, avs_tgl_i2s_machines), {}, }; diff --git a/sound/soc/intel/avs/cnl.c b/sound/soc/intel/avs/cnl.c new file mode 100644 index 000000000000..5423c29ecc4e --- /dev/null +++ b/sound/soc/intel/avs/cnl.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2024 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <sound/hdaudio_ext.h> +#include "avs.h" +#include "messages.h" + +irqreturn_t avs_cnl_irq_thread(struct avs_dev *adev) +{ + union avs_reply_msg msg; + u32 hipctdr, hipctdd, hipctda; + + hipctdr = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDR); + hipctdd = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDD); + + /* Ensure DSP sent new response to process. */ + if (!(hipctdr & CNL_ADSP_HIPCTDR_BUSY)) + return IRQ_NONE; + + msg.primary = hipctdr; + msg.ext.val = hipctdd; + avs_dsp_process_response(adev, msg.val); + + /* Tell DSP we accepted its message. */ + snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCTDR, + CNL_ADSP_HIPCTDR_BUSY, CNL_ADSP_HIPCTDR_BUSY); + /* Ack this response. */ + snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCTDA, + CNL_ADSP_HIPCTDA_DONE, CNL_ADSP_HIPCTDA_DONE); + /* HW might have been clock gated, give some time for change to propagate. */ + snd_hdac_adsp_readl_poll(adev, CNL_ADSP_REG_HIPCTDA, hipctda, + !(hipctda & CNL_ADSP_HIPCTDA_DONE), 10, 1000); + /* Unmask busy interrupt. */ + snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCCTL, + AVS_ADSP_HIPCCTL_BUSY, AVS_ADSP_HIPCCTL_BUSY); + + return IRQ_HANDLED; +} + +const struct avs_dsp_ops avs_cnl_dsp_ops = { + .power = avs_dsp_core_power, + .reset = avs_dsp_core_reset, + .stall = avs_dsp_core_stall, + .irq_handler = avs_irq_handler, + .irq_thread = avs_cnl_irq_thread, + .int_control = avs_dsp_interrupt_control, + .load_basefw = avs_hda_load_basefw, + .load_lib = avs_hda_load_library, + .transfer_mods = avs_hda_transfer_modules, + .log_buffer_offset = avs_skl_log_buffer_offset, + .log_buffer_status = avs_apl_log_buffer_status, + .coredump = avs_apl_coredump, + .d0ix_toggle = avs_apl_d0ix_toggle, + .set_d0ix = avs_apl_set_d0ix, + AVS_SET_ENABLE_LOGS_OP(apl) +}; diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index 565878eb42cd..d7f8940099ce 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -69,9 +69,14 @@ void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable) void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable) { - u32 value = enable ? AZX_VS_EM2_L1SEN : 0; - - snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, value); + if (enable) { + if (atomic_inc_and_test(&adev->l1sen_counter)) + snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, + AZX_VS_EM2_L1SEN); + } else { + if (atomic_dec_return(&adev->l1sen_counter) == -1) + snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, 0); + } } static int avs_hdac_bus_init_streams(struct hdac_bus *bus) @@ -317,6 +322,20 @@ static irqreturn_t hdac_bus_irq_thread(int irq, void *context) return IRQ_HANDLED; } +static irqreturn_t avs_dsp_irq_handler(int irq, void *dev_id) +{ + struct avs_dev *adev = dev_id; + + return avs_dsp_op(adev, irq_handler); +} + +static irqreturn_t avs_dsp_irq_thread(int irq, void *dev_id) +{ + struct avs_dev *adev = dev_id; + + return avs_dsp_op(adev, irq_thread); +} + static int avs_hdac_acquire_irq(struct avs_dev *adev) { struct hdac_bus *bus = &adev->base.core; @@ -726,38 +745,107 @@ static const struct dev_pm_ops avs_dev_pm = { SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL) }; +static const struct avs_sram_spec skl_sram_spec = { + .base_offset = SKL_ADSP_SRAM_BASE_OFFSET, + .window_size = SKL_ADSP_SRAM_WINDOW_SIZE, + .rom_status_offset = SKL_ADSP_SRAM_BASE_OFFSET, +}; + +static const struct avs_sram_spec apl_sram_spec = { + .base_offset = APL_ADSP_SRAM_BASE_OFFSET, + .window_size = APL_ADSP_SRAM_WINDOW_SIZE, + .rom_status_offset = APL_ADSP_SRAM_BASE_OFFSET, +}; + +static const struct avs_hipc_spec skl_hipc_spec = { + .req_offset = SKL_ADSP_REG_HIPCI, + .req_ext_offset = SKL_ADSP_REG_HIPCIE, + .req_busy_mask = SKL_ADSP_HIPCI_BUSY, + .ack_offset = SKL_ADSP_REG_HIPCIE, + .ack_done_mask = SKL_ADSP_HIPCIE_DONE, + .rsp_offset = SKL_ADSP_REG_HIPCT, + .rsp_busy_mask = SKL_ADSP_HIPCT_BUSY, + .ctl_offset = SKL_ADSP_REG_HIPCCTL, +}; + +static const struct avs_hipc_spec cnl_hipc_spec = { + .req_offset = CNL_ADSP_REG_HIPCIDR, + .req_ext_offset = CNL_ADSP_REG_HIPCIDD, + .req_busy_mask = CNL_ADSP_HIPCIDR_BUSY, + .ack_offset = CNL_ADSP_REG_HIPCIDA, + .ack_done_mask = CNL_ADSP_HIPCIDA_DONE, + .rsp_offset = CNL_ADSP_REG_HIPCTDR, + .rsp_busy_mask = CNL_ADSP_HIPCTDR_BUSY, + .ctl_offset = CNL_ADSP_REG_HIPCCTL, +}; + static const struct avs_spec skl_desc = { .name = "skl", - .min_fw_version = { - .major = 9, - .minor = 21, - .hotfix = 0, - .build = 4732, - }, - .dsp_ops = &skl_dsp_ops, + .min_fw_version = { 9, 21, 0, 4732 }, + .dsp_ops = &avs_skl_dsp_ops, .core_init_mask = 1, .attributes = AVS_PLATATTR_CLDMA, - .sram_base_offset = SKL_ADSP_SRAM_BASE_OFFSET, - .sram_window_size = SKL_ADSP_SRAM_WINDOW_SIZE, - .rom_status = SKL_ADSP_SRAM_BASE_OFFSET, + .sram = &skl_sram_spec, + .hipc = &skl_hipc_spec, }; static const struct avs_spec apl_desc = { .name = "apl", - .min_fw_version = { - .major = 9, - .minor = 22, - .hotfix = 1, - .build = 4323, - }, - .dsp_ops = &apl_dsp_ops, + .min_fw_version = { 9, 22, 1, 4323 }, + .dsp_ops = &avs_apl_dsp_ops, .core_init_mask = 3, .attributes = AVS_PLATATTR_IMR, - .sram_base_offset = APL_ADSP_SRAM_BASE_OFFSET, - .sram_window_size = APL_ADSP_SRAM_WINDOW_SIZE, - .rom_status = APL_ADSP_SRAM_BASE_OFFSET, + .sram = &apl_sram_spec, + .hipc = &skl_hipc_spec, +}; + +static const struct avs_spec cnl_desc = { + .name = "cnl", + .min_fw_version = { 10, 23, 0, 5314 }, + .dsp_ops = &avs_cnl_dsp_ops, + .core_init_mask = 1, + .attributes = AVS_PLATATTR_IMR, + .sram = &apl_sram_spec, + .hipc = &cnl_hipc_spec, +}; + +static const struct avs_spec icl_desc = { + .name = "icl", + .min_fw_version = { 10, 23, 0, 5040 }, + .dsp_ops = &avs_icl_dsp_ops, + .core_init_mask = 1, + .attributes = AVS_PLATATTR_IMR, + .sram = &apl_sram_spec, + .hipc = &cnl_hipc_spec, }; +static const struct avs_spec jsl_desc = { + .name = "jsl", + .min_fw_version = { 10, 26, 0, 5872 }, + .dsp_ops = &avs_icl_dsp_ops, + .core_init_mask = 1, + .attributes = AVS_PLATATTR_IMR, + .sram = &apl_sram_spec, + .hipc = &cnl_hipc_spec, +}; + +#define AVS_TGL_BASED_SPEC(sname) \ +static const struct avs_spec sname##_desc = { \ + .name = #sname, \ + .min_fw_version = { 10, 29, 0, 5646 }, \ + .dsp_ops = &avs_tgl_dsp_ops, \ + .core_init_mask = 1, \ + .attributes = AVS_PLATATTR_IMR, \ + .sram = &apl_sram_spec, \ + .hipc = &cnl_hipc_spec, \ +} + +AVS_TGL_BASED_SPEC(lkf); +AVS_TGL_BASED_SPEC(tgl); +AVS_TGL_BASED_SPEC(ehl); +AVS_TGL_BASED_SPEC(adl); +AVS_TGL_BASED_SPEC(adl_n); + static const struct pci_device_id avs_ids[] = { { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) }, { PCI_DEVICE_DATA(INTEL, HDA_SKL, &skl_desc) }, @@ -767,6 +855,32 @@ static const struct pci_device_id avs_ids[] = { { PCI_DEVICE_DATA(INTEL, HDA_CML_S, &skl_desc) }, { PCI_DEVICE_DATA(INTEL, HDA_APL, &apl_desc) }, { PCI_DEVICE_DATA(INTEL, HDA_GML, &apl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, &cnl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, &cnl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, &cnl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CML_H, &cnl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RKL_S, &cnl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_LP, &icl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_N, &icl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ICL_H, &icl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_JSL_N, &jsl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_LKF, &lkf_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_TGL_LP, &tgl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_TGL_H, &tgl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_CML_R, &tgl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_EHL_0, &ehl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_EHL_3, &ehl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_S, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_P, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_PS, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_M, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_PX, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_ADL_N, &adl_n_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_S, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_0, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_M, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, &adl_desc) }, { 0 } }; MODULE_DEVICE_TABLE(pci, avs_ids); @@ -777,6 +891,7 @@ static struct pci_driver avs_pci_driver = { .probe = avs_pci_probe, .remove = avs_pci_remove, .shutdown = avs_pci_shutdown, + .dev_groups = avs_attr_groups, .driver = { .pm = &avs_dev_pm, }, diff --git a/sound/soc/intel/avs/icl.c b/sound/soc/intel/avs/icl.c new file mode 100644 index 000000000000..9d9921e1cd4d --- /dev/null +++ b/sound/soc/intel/avs/icl.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2021-2024 Intel Corporation. All rights reserved. +// +// Authors: Cezary Rojewski <cezary.rojewski@intel.com> +// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> +// + +#include <linux/slab.h> +#include <sound/hdaudio.h> +#include <sound/hdaudio_ext.h> +#include "avs.h" +#include "messages.h" + +#define ICL_VS_LTRP_GB_ICCMAX 95 + +#ifdef CONFIG_DEBUG_FS +int avs_icl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, + u32 fifo_full_period, unsigned long resource_mask, u32 *priorities) +{ + struct avs_icl_log_state_info *info; + u32 size, num_libs = adev->fw_cfg.max_libs_count; + int i, ret; + + if (fls_long(resource_mask) > num_libs) + return -EINVAL; + size = struct_size(info, logs_priorities_mask, num_libs); + info = kzalloc(size, GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->aging_timer_period = aging_period; + info->fifo_full_timer_period = fifo_full_period; + info->enable = enable; + if (enable) + for_each_set_bit(i, &resource_mask, num_libs) + info->logs_priorities_mask[i] = *priorities++; + + ret = avs_ipc_set_enable_logs(adev, (u8 *)info, size); + kfree(info); + if (ret) + return AVS_IPC_RET(ret); + + return 0; +} +#endif + +union avs_icl_memwnd2_slot_type { + u32 val; + struct { + u32 resource_id:8; + u32 type:24; + }; +} __packed; + +struct avs_icl_memwnd2_desc { + u32 resource_id; + union avs_icl_memwnd2_slot_type slot_id; + u32 vma; +} __packed; + +#define AVS_ICL_MEMWND2_SLOTS_COUNT 15 + +struct avs_icl_memwnd2 { + union { + struct avs_icl_memwnd2_desc slot_desc[AVS_ICL_MEMWND2_SLOTS_COUNT]; + u8 rsvd[PAGE_SIZE]; + }; + u8 slot_array[AVS_ICL_MEMWND2_SLOTS_COUNT][PAGE_SIZE]; +} __packed; + +#define AVS_ICL_SLOT_UNUSED \ + ((union avs_icl_memwnd2_slot_type) { 0x00000000U }) +#define AVS_ICL_SLOT_CRITICAL_LOG \ + ((union avs_icl_memwnd2_slot_type) { 0x54524300U }) +#define AVS_ICL_SLOT_DEBUG_LOG \ + ((union avs_icl_memwnd2_slot_type) { 0x474f4c00U }) +#define AVS_ICL_SLOT_GDB_STUB \ + ((union avs_icl_memwnd2_slot_type) { 0x42444700U }) +#define AVS_ICL_SLOT_BROKEN \ + ((union avs_icl_memwnd2_slot_type) { 0x44414544U }) + +static int avs_icl_slot_offset(struct avs_dev *adev, union avs_icl_memwnd2_slot_type slot_type) +{ + struct avs_icl_memwnd2_desc desc[AVS_ICL_MEMWND2_SLOTS_COUNT]; + int i; + + memcpy_fromio(&desc, avs_sram_addr(adev, AVS_DEBUG_WINDOW), sizeof(desc)); + + for (i = 0; i < AVS_ICL_MEMWND2_SLOTS_COUNT; i++) + if (desc[i].slot_id.val == slot_type.val) + return offsetof(struct avs_icl_memwnd2, slot_array) + + avs_skl_log_buffer_offset(adev, i); + return -ENXIO; +} + +int avs_icl_log_buffer_offset(struct avs_dev *adev, u32 core) +{ + union avs_icl_memwnd2_slot_type slot_type = AVS_ICL_SLOT_DEBUG_LOG; + int ret; + + slot_type.resource_id = core; + ret = avs_icl_slot_offset(adev, slot_type); + if (ret < 0) + dev_dbg(adev->dev, "No slot offset found for: %x\n", + slot_type.val); + + return ret; +} + +bool avs_icl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake) +{ + /* Payload-less IPCs do not take part in d0ix toggling. */ + return tx->size; +} + +int avs_icl_set_d0ix(struct avs_dev *adev, bool enable) +{ + int ret; + + ret = avs_ipc_set_d0ix(adev, enable, false); + return AVS_IPC_RET(ret); +} + +int avs_icl_load_basefw(struct avs_dev *adev, struct firmware *fw) +{ + struct hdac_bus *bus = &adev->base.core; + struct hdac_ext_stream *host_stream; + struct snd_pcm_substream substream; + struct snd_dma_buffer dmab; + unsigned int sd_fmt; + u8 ltrp_gb; + int ret; + + /* + * ICCMAX: + * + * For ICL+ platforms, as per HW recommendation LTRP_GB is set to 95us + * during FW load. Its original value shall be restored once load completes. + * + * To avoid DMI/OPIO L1 entry during the load procedure, additional CAPTURE + * stream is allocated and set to run. + */ + + memset(&substream, 0, sizeof(substream)); + substream.stream = SNDRV_PCM_STREAM_CAPTURE; + + host_stream = snd_hdac_ext_stream_assign(bus, &substream, HDAC_EXT_STREAM_TYPE_HOST); + if (!host_stream) + return -EBUSY; + + ltrp_gb = snd_hdac_chip_readb(bus, VS_LTRP) & AZX_REG_VS_LTRP_GB_MASK; + /* Carries no real data, use default format. */ + sd_fmt = snd_hdac_stream_format(1, 32, 48000); + + ret = snd_hdac_dsp_prepare(hdac_stream(host_stream), sd_fmt, fw->size, &dmab); + if (ret < 0) + goto release_stream; + + s |