Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: Intel: avs: Add support for FCL platform

Merge series from Cezary Rojewski <cezary.rojewski@intel.com>:

The patchset is fairly straightforward - add support for Automotive
platforms based on new DSP architecture, Frisco Lake (FCL), a
PantherLake (PTL)-based platform is an example of. The cAVS
architecture which all Intel AudioDSP followed for years ends with
RaptorLake familty. Like all the major updates, this one received new
name too - Audio Context Engine (ACE).

While the range of improvements and changes on the firmware/hardware
side is large, software survives this evolution without need of any
major refactoring. Additional hardware changes brought with LunarLake
(LNL, ACE 2.0) call for update in PCM-area. The GPDMAs previously
utilized for non-HDAudio transfer types are no longer there, everything
is running through HDAudio LINK on the Back-End side now.

In terms of code, the mtl.c file, provided with patch 05 'ASoC: Intel:
avs: PTL-based platforms support' hosts largest number of new handlers -
new IRQ and INT control and DSP-cores management. Combined with lnl.c
and ptl.c which layer the architecture changes done over ACE
generations, provide support for PTL-based platforms e.g.: FCL.
The inheritance in summary:

mtl.c <- lnl.c <- ptl.c

The functional update to HDAudio library is there to help avs-driver
read certain capabilities directly from the hardware. Once the pointer
to LINK is obtained, there is no need to call AudioDSP firmware to get
the caps.

+648 -53
+1
include/linux/pci_ids.h
··· 3070 3070 #define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 3071 3071 #define PCI_DEVICE_ID_INTEL_5100_22 0x65f6 3072 3072 #define PCI_DEVICE_ID_INTEL_IOAT_SCNB 0x65ff 3073 + #define PCI_DEVICE_ID_INTEL_HDA_FCL 0x67a8 3073 3074 #define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 3074 3075 #define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 3075 3076 #define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020
+6
include/sound/hdaudio_ext.h
··· 22 22 void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *chip, bool enable); 23 23 24 24 int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus); 25 + struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_id(struct hdac_bus *bus, u32 id); 25 26 struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_addr(struct hdac_bus *bus, int addr); 26 27 struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_name(struct hdac_bus *bus, 27 28 const char *codec_name); ··· 98 97 void __iomem *ml_addr; /* link output stream reg pointer */ 99 98 u32 lcaps; /* link capablities */ 100 99 u16 lsdiid; /* link sdi identifier */ 100 + u32 id; 101 + u8 slcount; 101 102 102 103 int ref_count; 103 104 104 105 struct list_head list; 105 106 }; 107 + 108 + #define hdac_ext_link_alt(link) ((link)->lcaps & AZX_ML_HDA_LCAP_ALT) 109 + #define hdac_ext_link_ofls(link) ((link)->lcaps & AZX_ML_HDA_LCAP_OFLS) 106 110 107 111 int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *hlink); 108 112 int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *hlink);
+19
sound/hda/ext/hdac_ext_controller.c
··· 9 9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10 10 */ 11 11 12 + #include <linux/bitfield.h> 12 13 #include <linux/delay.h> 13 14 #include <linux/slab.h> 14 15 #include <sound/hda_register.h> ··· 82 81 int idx; 83 82 u32 link_count; 84 83 struct hdac_ext_link *hlink; 84 + u32 leptr; 85 85 86 86 link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1; 87 87 ··· 98 96 (AZX_ML_INTERVAL * idx); 99 97 hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP); 100 98 hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID); 99 + hlink->slcount = FIELD_GET(AZX_ML_HDA_LCAP_SLCOUNT, hlink->lcaps) + 1; 100 + 101 + if (hdac_ext_link_alt(hlink)) { 102 + leptr = readl(hlink->ml_addr + AZX_REG_ML_LEPTR); 103 + hlink->id = FIELD_GET(AZX_REG_ML_LEPTR_ID, leptr); 104 + } 101 105 102 106 /* since link in On, update the ref */ 103 107 hlink->ref_count = 1; ··· 132 124 } 133 125 } 134 126 EXPORT_SYMBOL_GPL(snd_hdac_ext_link_free_all); 127 + 128 + struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_id(struct hdac_bus *bus, u32 id) 129 + { 130 + struct hdac_ext_link *hlink; 131 + 132 + list_for_each_entry(hlink, &bus->hlink_list, list) 133 + if (hdac_ext_link_alt(hlink) && hlink->id == id) 134 + return hlink; 135 + return NULL; 136 + } 137 + EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_hlink_by_id); 135 138 136 139 /** 137 140 * snd_hdac_ext_bus_get_hlink_by_addr - get hlink at specified address
+4
sound/hda/intel-dsp-config.c
··· 112 112 .flags = FLAG_SST, 113 113 .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M, 114 114 }, 115 + { 116 + .flags = FLAG_SST, 117 + .device = PCI_DEVICE_ID_INTEL_HDA_FCL, 118 + }, 115 119 #endif 116 120 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 117 121 {
+3 -3
sound/soc/intel/avs/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 3 3 snd-soc-avs-y := dsp.o ipc.o messages.o utils.o core.o loader.o \ 4 - topology.o path.o pcm.o board_selection.o control.o \ 5 - sysfs.o 4 + topology.o path.o pcm.o board_selection.o control.o \ 5 + sysfs.o 6 6 snd-soc-avs-y += cldma.o 7 - snd-soc-avs-y += skl.o apl.o cnl.o icl.o tgl.o 7 + snd-soc-avs-y += skl.o apl.o cnl.o icl.o tgl.o mtl.o lnl.o ptl.o 8 8 9 9 snd-soc-avs-y += trace.o 10 10 # tell define_trace.h where to find the trace header
+10 -1
sound/soc/intel/avs/avs.h
··· 69 69 extern const struct avs_dsp_ops avs_cnl_dsp_ops; 70 70 extern const struct avs_dsp_ops avs_icl_dsp_ops; 71 71 extern const struct avs_dsp_ops avs_tgl_dsp_ops; 72 + extern const struct avs_dsp_ops avs_ptl_dsp_ops; 72 73 73 74 #define AVS_PLATATTR_CLDMA BIT_ULL(0) 74 75 #define AVS_PLATATTR_IMR BIT_ULL(1) 76 + #define AVS_PLATATTR_ACE BIT_ULL(2) 77 + #define AVS_PLATATTR_ALTHDA BIT_ULL(3) 75 78 76 79 #define avs_platattr_test(adev, attr) \ 77 80 ((adev)->spec->attributes & AVS_PLATATTR_##attr) ··· 82 79 struct avs_sram_spec { 83 80 const u32 base_offset; 84 81 const u32 window_size; 85 - const u32 rom_status_offset; 86 82 }; 87 83 88 84 struct avs_hipc_spec { ··· 93 91 const u32 rsp_offset; 94 92 const u32 rsp_busy_mask; 95 93 const u32 ctl_offset; 94 + const u32 sts_offset; 96 95 }; 97 96 98 97 /* Platform specific descriptor */ ··· 268 265 int avs_dsp_disable_d0ix(struct avs_dev *adev); 269 266 int avs_dsp_enable_d0ix(struct avs_dev *adev); 270 267 268 + int avs_mtl_core_power(struct avs_dev *adev, u32 core_mask, bool power); 269 + int avs_mtl_core_reset(struct avs_dev *adev, u32 core_mask, bool power); 270 + int avs_mtl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall); 271 + int avs_lnl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall); 272 + void avs_mtl_interrupt_control(struct avs_dev *adev, bool enable); 271 273 void avs_skl_ipc_interrupt(struct avs_dev *adev); 272 274 irqreturn_t avs_cnl_dsp_interrupt(struct avs_dev *adev); 275 + irqreturn_t avs_mtl_dsp_interrupt(struct avs_dev *adev); 273 276 int avs_apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, 274 277 u32 fifo_full_period, unsigned long resource_mask, u32 *priorities); 275 278 int avs_icl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
+2 -1
sound/soc/intel/avs/board_selection.c
··· 401 401 AVS_MACH_ENTRY(HDA_ADL_P, avs_tgl_i2s_machines), 402 402 AVS_MACH_ENTRY(HDA_RPL_P_0, avs_tgl_i2s_machines), 403 403 AVS_MACH_ENTRY(HDA_RPL_M, avs_mbl_i2s_machines), 404 - {} 404 + AVS_MACH_ENTRY(HDA_FCL, avs_tgl_i2s_machines), 405 + { }, 405 406 }; 406 407 407 408 static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev)
+54 -6
sound/soc/intel/avs/core.c
··· 54 54 { 55 55 u32 value = enable ? 0 : pgctl_mask; 56 56 57 - avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL, pgctl_mask, value); 57 + if (!avs_platattr_test(adev, ACE)) 58 + avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL, pgctl_mask, value); 58 59 } 59 60 60 61 static void avs_hdac_clock_gating_enable(struct hdac_bus *bus, bool enable) 61 62 { 63 + struct avs_dev *adev = hdac_to_avs(bus); 62 64 u32 value = enable ? cgctl_mask : 0; 63 65 64 - avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, cgctl_mask, value); 66 + if (!avs_platattr_test(adev, ACE)) 67 + avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, cgctl_mask, value); 65 68 } 66 69 67 70 void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable) ··· 74 71 75 72 void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable) 76 73 { 74 + if (avs_platattr_test(adev, ACE)) 75 + return; 77 76 if (enable) { 78 77 if (atomic_inc_and_test(&adev->l1sen_counter)) 79 78 snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, ··· 104 99 105 100 static bool avs_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset) 106 101 { 102 + struct avs_dev *adev = hdac_to_avs(bus); 107 103 struct hdac_ext_link *hlink; 108 104 bool ret; 109 105 ··· 120 114 /* Set DUM bit to address incorrect position reporting for capture 121 115 * streams. In order to do so, CTRL needs to be out of reset state 122 116 */ 123 - snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM); 117 + if (!avs_platattr_test(adev, ACE)) 118 + snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM); 124 119 125 120 return ret; 126 121 } ··· 755 748 static const struct avs_sram_spec skl_sram_spec = { 756 749 .base_offset = SKL_ADSP_SRAM_BASE_OFFSET, 757 750 .window_size = SKL_ADSP_SRAM_WINDOW_SIZE, 758 - .rom_status_offset = SKL_ADSP_SRAM_BASE_OFFSET, 759 751 }; 760 752 761 753 static const struct avs_sram_spec apl_sram_spec = { 762 754 .base_offset = APL_ADSP_SRAM_BASE_OFFSET, 763 755 .window_size = APL_ADSP_SRAM_WINDOW_SIZE, 764 - .rom_status_offset = APL_ADSP_SRAM_BASE_OFFSET, 756 + }; 757 + 758 + static const struct avs_sram_spec mtl_sram_spec = { 759 + .base_offset = MTL_ADSP_SRAM_BASE_OFFSET, 760 + .window_size = MTL_ADSP_SRAM_WINDOW_SIZE, 765 761 }; 766 762 767 763 static const struct avs_hipc_spec skl_hipc_spec = { ··· 776 766 .rsp_offset = SKL_ADSP_REG_HIPCT, 777 767 .rsp_busy_mask = SKL_ADSP_HIPCT_BUSY, 778 768 .ctl_offset = SKL_ADSP_REG_HIPCCTL, 769 + .sts_offset = SKL_ADSP_SRAM_BASE_OFFSET, 770 + }; 771 + 772 + static const struct avs_hipc_spec apl_hipc_spec = { 773 + .req_offset = SKL_ADSP_REG_HIPCI, 774 + .req_ext_offset = SKL_ADSP_REG_HIPCIE, 775 + .req_busy_mask = SKL_ADSP_HIPCI_BUSY, 776 + .ack_offset = SKL_ADSP_REG_HIPCIE, 777 + .ack_done_mask = SKL_ADSP_HIPCIE_DONE, 778 + .rsp_offset = SKL_ADSP_REG_HIPCT, 779 + .rsp_busy_mask = SKL_ADSP_HIPCT_BUSY, 780 + .ctl_offset = SKL_ADSP_REG_HIPCCTL, 781 + .sts_offset = APL_ADSP_SRAM_BASE_OFFSET, 779 782 }; 780 783 781 784 static const struct avs_hipc_spec cnl_hipc_spec = { ··· 800 777 .rsp_offset = CNL_ADSP_REG_HIPCTDR, 801 778 .rsp_busy_mask = CNL_ADSP_HIPCTDR_BUSY, 802 779 .ctl_offset = CNL_ADSP_REG_HIPCCTL, 780 + .sts_offset = APL_ADSP_SRAM_BASE_OFFSET, 781 + }; 782 + 783 + static const struct avs_hipc_spec lnl_hipc_spec = { 784 + .req_offset = MTL_REG_HfIPCxIDR, 785 + .req_ext_offset = MTL_REG_HfIPCxIDD, 786 + .req_busy_mask = MTL_HfIPCxIDR_BUSY, 787 + .ack_offset = MTL_REG_HfIPCxIDA, 788 + .ack_done_mask = MTL_HfIPCxIDA_DONE, 789 + .rsp_offset = MTL_REG_HfIPCxTDR, 790 + .rsp_busy_mask = MTL_HfIPCxTDR_BUSY, 791 + .ctl_offset = MTL_REG_HfIPCxCTL, 792 + .sts_offset = LNL_REG_HfDFR(0), 803 793 }; 804 794 805 795 static const struct avs_spec skl_desc = { ··· 832 796 .core_init_mask = 3, 833 797 .attributes = AVS_PLATATTR_IMR, 834 798 .sram = &apl_sram_spec, 835 - .hipc = &skl_hipc_spec, 799 + .hipc = &apl_hipc_spec, 836 800 }; 837 801 838 802 static const struct avs_spec cnl_desc = { ··· 882 846 AVS_TGL_BASED_SPEC(adl, 35); 883 847 AVS_TGL_BASED_SPEC(adl_n, 35); 884 848 849 + static const struct avs_spec fcl_desc = { 850 + .name = "fcl", 851 + .min_fw_version = { 0 }, 852 + .dsp_ops = &avs_ptl_dsp_ops, 853 + .core_init_mask = 1, 854 + .attributes = AVS_PLATATTR_IMR | AVS_PLATATTR_ACE | AVS_PLATATTR_ALTHDA, 855 + .sram = &mtl_sram_spec, 856 + .hipc = &lnl_hipc_spec, 857 + }; 858 + 885 859 static const struct pci_device_id avs_ids[] = { 886 860 { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) }, 887 861 { PCI_DEVICE_DATA(INTEL, HDA_SKL, &skl_desc) }, ··· 927 881 { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, &adl_desc) }, 928 882 { PCI_DEVICE_DATA(INTEL, HDA_RPL_M, &adl_desc) }, 929 883 { PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, &adl_desc) }, 884 + { PCI_DEVICE_DATA(INTEL, HDA_FCL, &fcl_desc) }, 930 885 { 0 } 931 886 }; 932 887 MODULE_DEVICE_TABLE(pci, avs_ids); ··· 959 912 MODULE_FIRMWARE("intel/ehl/dsp_basefw.bin"); 960 913 MODULE_FIRMWARE("intel/adl/dsp_basefw.bin"); 961 914 MODULE_FIRMWARE("intel/adl_n/dsp_basefw.bin"); 915 + MODULE_FIRMWARE("intel/fcl/dsp_basefw.bin");
-2
sound/soc/intel/avs/dsp.c
··· 12 12 #include "registers.h" 13 13 #include "trace.h" 14 14 15 - #define AVS_ADSPCS_INTERVAL_US 500 16 - #define AVS_ADSPCS_TIMEOUT_US 50000 17 15 #define AVS_ADSPCS_DELAY_US 1000 18 16 19 17 int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
+27
sound/soc/intel/avs/lnl.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright(c) 2021-2025 Intel Corporation 4 + * 5 + * Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6 + * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7 + */ 8 + 9 + #include <sound/hdaudio_ext.h> 10 + #include "avs.h" 11 + #include "registers.h" 12 + 13 + int avs_lnl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall) 14 + { 15 + struct hdac_bus *bus = &adev->base.core; 16 + struct hdac_ext_link *hlink; 17 + int ret; 18 + 19 + ret = avs_mtl_core_stall(adev, core_mask, stall); 20 + 21 + /* On unstall, route interrupts from the links to the DSP firmware. */ 22 + if (!ret && !stall) 23 + list_for_each_entry(hlink, &bus->hlink_list, list) 24 + snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_OFLEN, 25 + AZX_ML_LCTL_OFLEN); 26 + return ret; 27 + }
+10 -1
sound/soc/intel/avs/loader.c
··· 310 310 } 311 311 312 312 /* await ROM init */ 313 - ret = snd_hdac_adsp_readl_poll(adev, spec->sram->rom_status_offset, reg, 313 + ret = snd_hdac_adsp_readl_poll(adev, spec->hipc->sts_offset, reg, 314 314 (reg & 0xF) == AVS_ROM_INIT_DONE || 315 315 (reg & 0xF) == APL_ROM_FW_ENTERED, 316 316 AVS_ROM_INIT_POLLING_US, APL_ROM_INIT_TIMEOUT_US); ··· 683 683 684 684 static int avs_dsp_alloc_resources(struct avs_dev *adev) 685 685 { 686 + struct hdac_ext_link *link; 686 687 int ret, i; 687 688 688 689 ret = avs_ipc_get_hw_config(adev, &adev->hw_cfg); ··· 693 692 ret = avs_ipc_get_fw_config(adev, &adev->fw_cfg); 694 693 if (ret) 695 694 return AVS_IPC_RET(ret); 695 + 696 + /* If hw allows, read capabilities directly from it. */ 697 + if (avs_platattr_test(adev, ALTHDA)) { 698 + link = snd_hdac_ext_bus_get_hlink_by_id(&adev->base.core, 699 + AZX_REG_ML_LEPTR_ID_INTEL_SSP); 700 + if (link) 701 + adev->hw_cfg.i2s_caps.ctrl_count = link->slcount; 702 + } 696 703 697 704 adev->core_refs = devm_kcalloc(adev->dev, adev->hw_cfg.dsp_cores, 698 705 sizeof(*adev->core_refs), GFP_KERNEL);
+29
sound/soc/intel/avs/messages.h
··· 102 102 } __packed; 103 103 static_assert(sizeof(struct avs_tlv) == 8); 104 104 105 + #define avs_tlv_size(tlv) struct_size(tlv, value, (tlv)->length / 4) 106 + 105 107 enum avs_module_msg_type { 106 108 AVS_MOD_INIT_INSTANCE = 0, 107 109 AVS_MOD_LARGE_CONFIG_GET = 3, ··· 787 785 }; 788 786 } __packed; 789 787 static_assert(sizeof(union avs_gtw_attributes) == 4); 788 + 789 + #define AVS_GTW_DMA_CONFIG_ID 0x1000 790 + #define AVS_DMA_METHOD_HDA 1 791 + 792 + struct avs_dma_device_stream_channel_map { 793 + u32 device_address; 794 + u32 channel_map; 795 + } __packed; 796 + static_assert(sizeof(struct avs_dma_device_stream_channel_map) == 8); 797 + 798 + struct avs_dma_stream_channel_map { 799 + u32 device_count; 800 + struct avs_dma_device_stream_channel_map map[16]; 801 + } __packed; 802 + static_assert(sizeof(struct avs_dma_stream_channel_map) == 132); 803 + 804 + struct avs_dma_cfg { 805 + u8 dma_method; 806 + u8 pre_allocated; 807 + u16 rsvd; 808 + u32 dma_channel_id; 809 + u32 stream_id; 810 + struct avs_dma_stream_channel_map map; 811 + u32 config_size; 812 + u8 config[] __counted_by(config_size); 813 + } __packed; 814 + static_assert(sizeof(struct avs_dma_cfg) == 148); 790 815 791 816 struct avs_copier_gtw_cfg { 792 817 union avs_connector_node_id node_id;
+200
sound/soc/intel/avs/mtl.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright(c) 2021-2025 Intel Corporation 4 + * 5 + * Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6 + * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7 + */ 8 + 9 + #include <sound/hdaudio_ext.h> 10 + #include "avs.h" 11 + #include "registers.h" 12 + #include "trace.h" 13 + 14 + #define MTL_HfDSSGBL_BASE 0x1000 15 + #define MTL_REG_HfDSSCS (MTL_HfDSSGBL_BASE + 0x0) 16 + #define MTL_HfDSSCS_SPA BIT(16) 17 + #define MTL_HfDSSCS_CPA BIT(24) 18 + 19 + #define MTL_DSPCS_BASE 0x178D00 20 + #define MTL_REG_DSPCCTL (MTL_DSPCS_BASE + 0x4) 21 + #define MTL_DSPCCTL_SPA BIT(0) 22 + #define MTL_DSPCCTL_CPA BIT(8) 23 + #define MTL_DSPCCTL_OSEL GENMASK(25, 24) 24 + #define MTL_DSPCCTL_OSEL_HOST BIT(25) 25 + 26 + #define MTL_HfINT_BASE 0x1100 27 + #define MTL_REG_HfINTIPPTR (MTL_HfINT_BASE + 0x8) 28 + #define MTL_REG_HfHIPCIE (MTL_HfINT_BASE + 0x40) 29 + #define MTL_HfINTIPPTR_PTR GENMASK(20, 0) 30 + #define MTL_HfHIPCIE_IE BIT(0) 31 + 32 + #define MTL_DWICTL_INTENL_IE BIT(0) 33 + #define MTL_DWICTL_FINALSTATUSL_IPC BIT(0) /* same as ADSPIS_IPC */ 34 + 35 + static int avs_mtl_core_power_on(struct avs_dev *adev) 36 + { 37 + u32 reg; 38 + int ret; 39 + 40 + /* Power up DSP domain. */ 41 + snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, MTL_HfDSSCS_SPA); 42 + trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "power dsp", true); 43 + 44 + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg, 45 + (reg & MTL_HfDSSCS_CPA) == MTL_HfDSSCS_CPA, 46 + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); 47 + if (ret) { 48 + dev_err(adev->dev, "power on domain dsp failed: %d\n", ret); 49 + return ret; 50 + } 51 + 52 + /* Prevent power gating of DSP domain. */ 53 + snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL, MTL_HfPWRCTL_WPDSPHPxPG, 54 + MTL_HfPWRCTL_WPDSPHPxPG); 55 + trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "prevent dsp PG", true); 56 + 57 + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfPWRSTS, reg, 58 + (reg & MTL_HfPWRSTS_DSPHPxPGS) == MTL_HfPWRSTS_DSPHPxPGS, 59 + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); 60 + 61 + /* Set ownership to HOST. */ 62 + snd_hdac_adsp_updatel(adev, MTL_REG_DSPCCTL, MTL_DSPCCTL_OSEL, MTL_DSPCCTL_OSEL_HOST); 63 + return ret; 64 + } 65 + 66 + static int avs_mtl_core_power_off(struct avs_dev *adev) 67 + { 68 + u32 reg; 69 + 70 + /* Allow power gating of DSP domain. No STS polling as HOST is only one of its users. */ 71 + snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL, MTL_HfPWRCTL_WPDSPHPxPG, 0); 72 + trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "allow dsp pg", false); 73 + 74 + /* Power down DSP domain. */ 75 + snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, 0); 76 + trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "power dsp", false); 77 + 78 + return snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg, 79 + (reg & MTL_HfDSSCS_CPA) == 0, 80 + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); 81 + } 82 + 83 + int avs_mtl_core_power(struct avs_dev *adev, u32 core_mask, bool power) 84 + { 85 + core_mask &= AVS_MAIN_CORE_MASK; 86 + if (!core_mask) 87 + return 0; 88 + 89 + if (power) 90 + return avs_mtl_core_power_on(adev); 91 + return avs_mtl_core_power_off(adev); 92 + } 93 + 94 + int avs_mtl_core_reset(struct avs_dev *adev, u32 core_mask, bool power) 95 + { 96 + /* No logical equivalent on ACE 1.x. */ 97 + return 0; 98 + } 99 + 100 + int avs_mtl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall) 101 + { 102 + u32 value, reg; 103 + int ret; 104 + 105 + core_mask &= AVS_MAIN_CORE_MASK; 106 + if (!core_mask) 107 + return 0; 108 + 109 + value = snd_hdac_adsp_readl(adev, MTL_REG_DSPCCTL); 110 + trace_avs_dsp_core_op(value, core_mask, "stall", stall); 111 + if (value == UINT_MAX) 112 + return 0; 113 + 114 + value = stall ? 0 : MTL_DSPCCTL_SPA; 115 + snd_hdac_adsp_updatel(adev, MTL_REG_DSPCCTL, MTL_DSPCCTL_SPA, value); 116 + 117 + value = stall ? 0 : MTL_DSPCCTL_CPA; 118 + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_DSPCCTL, 119 + reg, (reg & MTL_DSPCCTL_CPA) == value, 120 + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); 121 + if (ret) 122 + dev_err(adev->dev, "core_mask %d %sstall failed: %d\n", 123 + core_mask, stall ? "" : "un", ret); 124 + return ret; 125 + } 126 + 127 + static void avs_mtl_ipc_interrupt(struct avs_dev *adev) 128 + { 129 + const struct avs_spec *spec = adev->spec; 130 + u32 hipc_ack, hipc_rsp; 131 + 132 + snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, 133 + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0); 134 + 135 + hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset); 136 + hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset); 137 + 138 + /* DSP acked host's request. */ 139 + if (hipc_ack & spec->hipc->ack_done_mask) { 140 + complete(&adev->ipc->done_completion); 141 + 142 + /* Tell DSP it has our attention. */ 143 + snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask, 144 + spec->hipc->ack_done_mask); 145 + } 146 + 147 + /* DSP sent new response to process. */ 148 + if (hipc_rsp & spec->hipc->rsp_busy_mask) { 149 + union avs_reply_msg msg; 150 + 151 + msg.primary = snd_hdac_adsp_readl(adev, MTL_REG_HfIPCxTDR); 152 + msg.ext.val = snd_hdac_adsp_readl(adev, MTL_REG_HfIPCxTDD); 153 + 154 + avs_dsp_process_response(adev, msg.val); 155 + 156 + /* Tell DSP we accepted its message. */ 157 + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxTDR, 158 + MTL_HfIPCxTDR_BUSY, MTL_HfIPCxTDR_BUSY); 159 + /* Ack this response. */ 160 + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxTDA, MTL_HfIPCxTDA_BUSY, 0); 161 + } 162 + 163 + snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, 164 + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 165 + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY); 166 + } 167 + 168 + irqreturn_t avs_mtl_dsp_interrupt(struct avs_dev *adev) 169 + { 170 + u32 adspis = snd_hdac_adsp_readl(adev, MTL_DWICTL_REG_FINALSTATUSL); 171 + irqreturn_t ret = IRQ_NONE; 172 + 173 + if (adspis == UINT_MAX) 174 + return ret; 175 + 176 + if (adspis & MTL_DWICTL_FINALSTATUSL_IPC) { 177 + avs_mtl_ipc_interrupt(adev); 178 + ret = IRQ_HANDLED; 179 + } 180 + 181 + return ret; 182 + } 183 + 184 + void avs_mtl_interrupt_control(struct avs_dev *adev, bool enable) 185 + { 186 + if (enable) { 187 + snd_hdac_adsp_updatel(adev, MTL_DWICTL_REG_INTENL, MTL_DWICTL_INTENL_IE, 188 + MTL_DWICTL_INTENL_IE); 189 + snd_hdac_adsp_updatew(adev, MTL_REG_HfHIPCIE, MTL_HfHIPCIE_IE, MTL_HfHIPCIE_IE); 190 + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_DONE, 191 + AVS_ADSP_HIPCCTL_DONE); 192 + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_BUSY, 193 + AVS_ADSP_HIPCCTL_BUSY); 194 + } else { 195 + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_BUSY, 0); 196 + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_DONE, 0); 197 + snd_hdac_adsp_updatew(adev, MTL_REG_HfHIPCIE, MTL_HfHIPCIE_IE, 0); 198 + snd_hdac_adsp_updatel(adev, MTL_DWICTL_REG_INTENL, MTL_DWICTL_INTENL_IE, 0); 199 + } 200 + }
+47 -4
sound/soc/intel/avs/path.c
··· 210 210 return &fmtcfg->config; 211 211 } 212 212 213 + static int avs_append_dma_cfg(struct avs_dev *adev, struct avs_copier_gtw_cfg *gtw, 214 + struct avs_tplg_module *t, u32 dma_id, size_t *cfg_size) 215 + { 216 + u32 dma_type = t->cfg_ext->copier.dma_type; 217 + struct avs_dma_cfg *dma; 218 + struct avs_tlv *tlv; 219 + size_t tlv_size; 220 + 221 + if (!avs_platattr_test(adev, ALTHDA)) 222 + return 0; 223 + 224 + switch (dma_type) { 225 + case AVS_DMA_HDA_HOST_OUTPUT: 226 + case AVS_DMA_HDA_HOST_INPUT: 227 + case AVS_DMA_HDA_LINK_OUTPUT: 228 + case AVS_DMA_HDA_LINK_INPUT: 229 + return 0; 230 + default: 231 + break; 232 + } 233 + 234 + tlv_size = sizeof(*tlv) + sizeof(*dma); 235 + if (*cfg_size + tlv_size > AVS_MAILBOX_SIZE) 236 + return -E2BIG; 237 + 238 + /* DMA config is a TLV tailing the existing payload. */ 239 + tlv = (struct avs_tlv *)&gtw->config.blob[gtw->config_length]; 240 + tlv->type = AVS_GTW_DMA_CONFIG_ID; 241 + tlv->length = sizeof(*dma); 242 + 243 + dma = (struct avs_dma_cfg *)tlv->value; 244 + memset(dma, 0, sizeof(*dma)); 245 + dma->dma_method = AVS_DMA_METHOD_HDA; 246 + dma->pre_allocated = true; 247 + dma->dma_channel_id = dma_id; 248 + dma->stream_id = dma_id + 1; 249 + 250 + gtw->config_length += tlv_size / sizeof(u32); 251 + *cfg_size += tlv_size; 252 + 253 + return 0; 254 + } 255 + 213 256 static int avs_fill_gtw_config(struct avs_dev *adev, struct avs_copier_gtw_cfg *gtw, 214 - struct avs_tplg_module *t, size_t *cfg_size) 257 + struct avs_tplg_module *t, u32 dma_id, size_t *cfg_size) 215 258 { 216 259 struct acpi_nhlt_config *blob; 217 260 size_t gtw_size; ··· 271 228 memcpy(gtw->config.blob, blob->capabilities, blob->capabilities_size); 272 229 *cfg_size += gtw_size; 273 230 274 - return 0; 231 + return avs_append_dma_cfg(adev, gtw, t, dma_id, cfg_size); 275 232 } 276 233 277 234 static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod) ··· 288 245 dma_id = mod->owner->owner->dma_id; 289 246 cfg_size = offsetof(struct avs_copier_cfg, gtw_cfg.config); 290 247 291 - ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, &cfg_size); 248 + ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, dma_id, &cfg_size); 292 249 if (ret) 293 250 return ret; 294 251 ··· 322 279 dma_id = mod->owner->owner->dma_id; 323 280 cfg_size = offsetof(struct avs_whm_cfg, gtw_cfg.config); 324 281 325 - ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, &cfg_size); 282 + ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, dma_id, &cfg_size); 326 283 if (ret) 327 284 return ret; 328 285
+99 -34
sound/soc/intel/avs/pcm.c
··· 33 33 }; 34 34 35 35 struct work_struct period_elapsed_work; 36 + struct hdac_ext_link *link; 36 37 struct snd_pcm_substream *substream; 37 38 }; 38 39 ··· 280 279 .trigger = avs_dai_nonhda_be_trigger, 281 280 }; 282 281 283 - static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 282 + static int __avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, 283 + struct hdac_ext_link *link) 284 284 { 285 - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 286 285 struct hdac_ext_stream *link_stream; 287 286 struct avs_dma_data *data; 288 - struct hda_codec *codec; 289 287 int ret; 290 288 291 289 ret = avs_dai_startup(substream, dai); 292 290 if (ret) 293 291 return ret; 294 292 295 - codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); 296 - link_stream = snd_hdac_ext_stream_assign(&codec->bus->core, substream, 293 + data = snd_soc_dai_get_dma_data(dai, substream); 294 + link_stream = snd_hdac_ext_stream_assign(&data->adev->base.core, substream, 297 295 HDAC_EXT_STREAM_TYPE_LINK); 298 296 if (!link_stream) { 299 297 avs_dai_shutdown(substream, dai); 300 298 return -EBUSY; 301 299 } 302 300 303 - data = snd_soc_dai_get_dma_data(dai, substream); 304 301 data->link_stream = link_stream; 305 - substream->runtime->private_data = link_stream; 302 + data->link = link; 306 303 return 0; 304 + } 305 + 306 + static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 307 + { 308 + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 309 + struct hdac_ext_link *link; 310 + struct avs_dma_data *data; 311 + struct hda_codec *codec; 312 + int ret; 313 + 314 + codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); 315 + 316 + link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr); 317 + if (!link) 318 + return -EINVAL; 319 + 320 + ret = __avs_dai_hda_be_startup(substream, dai, link); 321 + if (!ret) { 322 + data = snd_soc_dai_get_dma_data(dai, substream); 323 + substream->runtime->private_data = data->link_stream; 324 + } 325 + 326 + return ret; 327 + } 328 + 329 + static int avs_dai_i2shda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 330 + { 331 + struct avs_dev *adev = to_avs_dev(dai->component->dev); 332 + struct hdac_ext_link *link; 333 + 334 + link = snd_hdac_ext_bus_get_hlink_by_id(&adev->base.core, AZX_REG_ML_LEPTR_ID_INTEL_SSP); 335 + if (!link) 336 + return -EINVAL; 337 + return __avs_dai_hda_be_startup(substream, dai, link); 338 + } 339 + 340 + static int avs_dai_dmichda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 341 + { 342 + struct avs_dev *adev = to_avs_dev(dai->component->dev); 343 + struct hdac_ext_link *link; 344 + 345 + link = snd_hdac_ext_bus_get_hlink_by_id(&adev->base.core, AZX_REG_ML_LEPTR_ID_INTEL_DMIC); 346 + if (!link) 347 + return -EINVAL; 348 + return __avs_dai_hda_be_startup(substream, dai, link); 307 349 } 308 350 309 351 static void avs_dai_hda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) ··· 355 311 356 312 snd_hdac_ext_stream_release(data->link_stream, HDAC_EXT_STREAM_TYPE_LINK); 357 313 substream->runtime->private_data = NULL; 314 + avs_dai_shutdown(substream, dai); 315 + } 316 + 317 + static void avs_dai_althda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 318 + { 319 + struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream); 320 + 321 + snd_hdac_ext_stream_release(data->link_stream, HDAC_EXT_STREAM_TYPE_LINK); 358 322 avs_dai_shutdown(substream, dai); 359 323 } 360 324 ··· 381 329 382 330 static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 383 331 { 384 - struct avs_dma_data *data; 385 - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 386 332 struct hdac_ext_stream *link_stream; 387 - struct hdac_ext_link *link; 388 - struct hda_codec *codec; 389 - 390 - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 333 + struct avs_dma_data *data; 391 334 392 335 data = snd_soc_dai_get_dma_data(dai, substream); 393 336 if (!data->path) ··· 394 347 data->path = NULL; 395 348 396 349 /* clear link <-> stream mapping */ 397 - codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); 398 - link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr); 399 - if (!link) 400 - return -EINVAL; 401 - 402 350 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 403 - snd_hdac_ext_bus_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag); 351 + snd_hdac_ext_bus_link_clear_stream_id(data->link, 352 + hdac_stream(link_stream)->stream_tag); 404 353 405 354 return 0; 406 355 } 407 356 408 357 static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 409 358 { 410 - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 411 359 struct snd_pcm_runtime *runtime = substream->runtime; 412 360 const struct snd_soc_pcm_stream *stream_info; 413 361 struct hdac_ext_stream *link_stream; 414 - struct hdac_ext_link *link; 415 362 struct avs_dma_data *data; 416 - struct hda_codec *codec; 417 - struct hdac_bus *bus; 418 363 unsigned int format_val; 419 364 unsigned int bits; 420 365 int ret; ··· 417 378 if (link_stream->link_prepared) 418 379 return 0; 419 380 420 - codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); 421 - bus = &codec->bus->core; 422 381 stream_info = snd_soc_dai_get_pcm_stream(dai, substream->stream); 423 382 bits = snd_hdac_stream_format_bits(runtime->format, runtime->subformat, 424 383 stream_info->sig_bits); 425 384 format_val = snd_hdac_stream_format(runtime->channels, bits, runtime->rate); 426 385 427 - snd_hdac_ext_stream_decouple(bus, link_stream, true); 386 + snd_hdac_ext_stream_decouple(&data->adev->base.core, link_stream, true); 428 387 snd_hdac_ext_stream_reset(link_stream); 429 388 snd_hdac_ext_stream_setup(link_stream, format_val); 430 389 431 - link = snd_hdac_ext_bus_get_hlink_by_addr(bus, codec->core.addr); 432 - if (!link) 433 - return -EINVAL; 434 - 435 390 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 436 - snd_hdac_ext_bus_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag); 391 + snd_hdac_ext_bus_link_set_stream_id(data->link, 392 + hdac_stream(link_stream)->stream_tag); 437 393 438 394 ret = avs_dai_prepare(substream, dai); 439 395 if (ret) ··· 497 463 static const struct snd_soc_dai_ops avs_dai_hda_be_ops = { 498 464 .startup = avs_dai_hda_be_startup, 499 465 .shutdown = avs_dai_hda_be_shutdown, 466 + .hw_params = avs_dai_hda_be_hw_params, 467 + .hw_free = avs_dai_hda_be_hw_free, 468 + .prepare = avs_dai_hda_be_prepare, 469 + .trigger = avs_dai_hda_be_trigger, 470 + }; 471 + 472 + static const struct snd_soc_dai_ops avs_dai_i2shda_be_ops = { 473 + .startup = avs_dai_i2shda_be_startup, 474 + .shutdown = avs_dai_althda_be_shutdown, 475 + .hw_params = avs_dai_hda_be_hw_params, 476 + .hw_free = avs_dai_hda_be_hw_free, 477 + .prepare = avs_dai_hda_be_prepare, 478 + .trigger = avs_dai_hda_be_trigger, 479 + }; 480 + 481 + static const struct snd_soc_dai_ops avs_dai_dmichda_be_ops = { 482 + .startup = avs_dai_dmichda_be_startup, 483 + .shutdown = avs_dai_althda_be_shutdown, 500 484 .hw_params = avs_dai_hda_be_hw_params, 501 485 .hw_free = avs_dai_hda_be_hw_free, 502 486 .prepare = avs_dai_hda_be_prepare, ··· 1360 1308 static struct snd_soc_dai_driver dmic_cpu_dais[] = { 1361 1309 { 1362 1310 .name = "DMIC Pin", 1363 - .ops = &avs_dai_nonhda_be_ops, 1364 1311 .capture = { 1365 1312 .stream_name = "DMIC Rx", 1366 1313 .channels_min = 1, ··· 1370 1319 }, 1371 1320 { 1372 1321 .name = "DMIC WoV Pin", 1373 - .ops = &avs_dai_nonhda_be_ops, 1374 1322 .capture = { 1375 1323 .stream_name = "DMIC WoV Rx", 1376 1324 .channels_min = 1, ··· 1382 1332 1383 1333 int avs_dmic_platform_register(struct avs_dev *adev, const char *name) 1384 1334 { 1335 + const struct snd_soc_dai_ops *ops; 1336 + 1337 + if (avs_platattr_test(adev, ALTHDA)) 1338 + ops = &avs_dai_dmichda_be_ops; 1339 + else 1340 + ops = &avs_dai_nonhda_be_ops; 1341 + 1342 + dmic_cpu_dais[0].ops = ops; 1343 + dmic_cpu_dais[1].ops = ops; 1385 1344 return avs_soc_component_register(adev->dev, name, &avs_component_driver, dmic_cpu_dais, 1386 1345 ARRAY_SIZE(dmic_cpu_dais)); 1387 1346 } 1388 1347 1389 1348 static const struct snd_soc_dai_driver i2s_dai_template = { 1390 - .ops = &avs_dai_nonhda_be_ops, 1391 1349 .playback = { 1392 1350 .channels_min = 1, 1393 1351 .channels_max = 8, ··· 1428 1370 unsigned long *tdms) 1429 1371 { 1430 1372 struct snd_soc_dai_driver *cpus, *dai; 1373 + const struct snd_soc_dai_ops *ops; 1431 1374 size_t ssp_count, cpu_count; 1432 1375 int i, j; 1433 1376 1434 1377 ssp_count = adev->hw_cfg.i2s_caps.ctrl_count; 1378 + if (avs_platattr_test(adev, ALTHDA)) 1379 + ops = &avs_dai_i2shda_be_ops; 1380 + else 1381 + ops = &avs_dai_nonhda_be_ops; 1435 1382 1436 1383 cpu_count = 0; 1437 1384 for_each_set_bit(i, &port_mask, ssp_count) ··· 1464 1401 1465 1402 if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name) 1466 1403 return -ENOMEM; 1404 + dai->ops = ops; 1467 1405 dai++; 1468 1406 } 1469 1407 } ··· 1485 1421 1486 1422 if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name) 1487 1423 return -ENOMEM; 1424 + dai->ops = ops; 1488 1425 dai++; 1489 1426 } 1490 1427 }
+98
sound/soc/intel/avs/ptl.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright(c) 2024-2025 Intel Corporation 4 + * 5 + * Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6 + * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7 + */ 8 + 9 + #include <sound/hdaudio_ext.h> 10 + #include "avs.h" 11 + #include "registers.h" 12 + #include "trace.h" 13 + 14 + #define MTL_HfDSSGBL_BASE 0x1000 15 + #define MTL_REG_HfDSSCS (MTL_HfDSSGBL_BASE + 0x0) 16 + #define MTL_HfDSSCS_SPA BIT(16) 17 + #define MTL_HfDSSCS_CPA BIT(24) 18 + 19 + #define MTL_DSPCS_BASE 0x178D00 20 + #define MTL_REG_DSPCCTL (MTL_DSPCS_BASE + 0x4) 21 + #define MTL_DSPCCTL_OSEL GENMASK(25, 24) 22 + #define MTL_DSPCCTL_OSEL_HOST BIT(25) 23 + 24 + static int avs_ptl_core_power_on(struct avs_dev *adev) 25 + { 26 + u32 reg; 27 + int ret; 28 + 29 + /* Power up DSP domain. */ 30 + snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, MTL_HfDSSCS_SPA); 31 + trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "power dsp", true); 32 + 33 + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg, 34 + (reg & MTL_HfDSSCS_CPA) == MTL_HfDSSCS_CPA, 35 + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); 36 + if (ret) { 37 + dev_err(adev->dev, "power on domain dsp failed: %d\n", ret); 38 + return ret; 39 + } 40 + 41 + /* Prevent power gating of DSP domain. */ 42 + snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL2, MTL_HfPWRCTL2_WPDSPHPxPG, 43 + MTL_HfPWRCTL2_WPDSPHPxPG); 44 + trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "prevent dsp PG", true); 45 + 46 + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfPWRSTS2, reg, 47 + (reg & MTL_HfPWRSTS2_DSPHPxPGS) == MTL_HfPWRSTS2_DSPHPxPGS, 48 + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); 49 + 50 + /* Set ownership to HOST. */ 51 + snd_hdac_adsp_updatel(adev, MTL_REG_DSPCCTL, MTL_DSPCCTL_OSEL, MTL_DSPCCTL_OSEL_HOST); 52 + return ret; 53 + } 54 + 55 + static int avs_ptl_core_power_off(struct avs_dev *adev) 56 + { 57 + u32 reg; 58 + 59 + /* Allow power gating of DSP domain. No STS polling as HOST is only one of its users. */ 60 + snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL2, MTL_HfPWRCTL2_WPDSPHPxPG, 0); 61 + trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "allow dsp pg", false); 62 + 63 + /* Power down DSP domain. */ 64 + snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, 0); 65 + trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "power dsp", false); 66 + 67 + return snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg, 68 + (reg & MTL_HfDSSCS_CPA) == 0, 69 + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); 70 + } 71 + 72 + static int avs_ptl_core_power(struct avs_dev *adev, u32 core_mask, bool power) 73 + { 74 + core_mask &= AVS_MAIN_CORE_MASK; 75 + if (!core_mask) 76 + return 0; 77 + 78 + if (power) 79 + return avs_ptl_core_power_on(adev); 80 + return avs_ptl_core_power_off(adev); 81 + } 82 + 83 + const struct avs_dsp_ops avs_ptl_dsp_ops = { 84 + .power = avs_ptl_core_power, 85 + .reset = avs_mtl_core_reset, 86 + .stall = avs_lnl_core_stall, 87 + .dsp_interrupt = avs_mtl_dsp_interrupt, 88 + .int_control = avs_mtl_interrupt_control, 89 + .load_basefw = avs_hda_load_basefw, 90 + .load_lib = avs_hda_load_library, 91 + .transfer_mods = avs_hda_transfer_modules, 92 + .log_buffer_offset = avs_icl_log_buffer_offset, 93 + .log_buffer_status = avs_apl_log_buffer_status, 94 + .coredump = avs_apl_coredump, 95 + .d0ix_toggle = avs_icl_d0ix_toggle, 96 + .set_d0ix = avs_icl_set_d0ix, 97 + AVS_SET_ENABLE_LOGS_OP(icl) 98 + };
+39 -1
sound/soc/intel/avs/registers.h
··· 35 35 #define AVS_ADSPCS_CSTALL_MASK(cm) ((cm) << 8) 36 36 #define AVS_ADSPCS_SPA_MASK(cm) ((cm) << 16) 37 37 #define AVS_ADSPCS_CPA_MASK(cm) ((cm) << 24) 38 + #define AVS_ADSPCS_INTERVAL_US 500 39 + #define AVS_ADSPCS_TIMEOUT_US 10000 38 40 #define AVS_MAIN_CORE_MASK BIT(0) 39 41 40 42 #define AVS_ADSP_HIPCCTL_BUSY BIT(0) ··· 69 67 #define CNL_ADSP_HIPCIDR_BUSY BIT(31) 70 68 #define CNL_ADSP_HIPCIDA_DONE BIT(31) 71 69 70 + /* MTL Intel HOST Inter-Processor Communication Registers */ 71 + #define MTL_HfIPC_BASE 0x73000 72 + #define MTL_REG_HfIPCxTDR (MTL_HfIPC_BASE + 0x200) 73 + #define MTL_REG_HfIPCxTDA (MTL_HfIPC_BASE + 0x204) 74 + #define MTL_REG_HfIPCxIDR (MTL_HfIPC_BASE + 0x210) 75 + #define MTL_REG_HfIPCxIDA (MTL_HfIPC_BASE + 0x214) 76 + #define MTL_REG_HfIPCxCTL (MTL_HfIPC_BASE + 0x228) 77 + #define MTL_REG_HfIPCxTDD (MTL_HfIPC_BASE + 0x300) 78 + #define MTL_REG_HfIPCxIDD (MTL_HfIPC_BASE + 0x380) 79 + 80 + #define MTL_HfIPCxTDR_BUSY BIT(31) 81 + #define MTL_HfIPCxTDA_BUSY BIT(31) 82 + #define MTL_HfIPCxIDR_BUSY BIT(31) 83 + #define MTL_HfIPCxIDA_DONE BIT(31) 84 + 85 + #define MTL_HfFLV_BASE 0x162000 86 + #define MTL_REG_HfFLGP(x, y) (MTL_HfFLV_BASE + 0x1200 + (x) * 0x20 + (y) * 0x08) 87 + #define LNL_REG_HfDFR(x) (0x160200 + (x) * 0x8) 88 + 89 + #define MTL_DWICTL_BASE 0x1800 90 + #define MTL_DWICTL_REG_INTENL (MTL_DWICTL_BASE + 0x0) 91 + #define MTL_DWICTL_REG_FINALSTATUSL (MTL_DWICTL_BASE + 0x30) 92 + 93 + #define MTL_HfPMCCU_BASE 0x1D00 94 + #define MTL_REG_HfCLKCTL (MTL_HfPMCCU_BASE + 0x10) 95 + #define MTL_REG_HfPWRCTL (MTL_HfPMCCU_BASE + 0x18) 96 + #define MTL_REG_HfPWRSTS (MTL_HfPMCCU_BASE + 0x1C) 97 + #define MTL_REG_HfPWRCTL2 (MTL_HfPMCCU_BASE + 0x20) 98 + #define MTL_REG_HfPWRSTS2 (MTL_HfPMCCU_BASE + 0x24) 99 + #define MTL_HfPWRCTL_WPDSPHPxPG BIT(0) 100 + #define MTL_HfPWRSTS_DSPHPxPGS BIT(0) 101 + #define MTL_HfPWRCTL2_WPDSPHPxPG BIT(0) 102 + #define MTL_HfPWRSTS2_DSPHPxPGS BIT(0) 103 + 72 104 /* Intel HD Audio SRAM windows base addresses */ 73 105 #define SKL_ADSP_SRAM_BASE_OFFSET 0x8000 74 106 #define SKL_ADSP_SRAM_WINDOW_SIZE 0x2000 75 107 #define APL_ADSP_SRAM_BASE_OFFSET 0x80000 76 108 #define APL_ADSP_SRAM_WINDOW_SIZE 0x20000 109 + #define MTL_ADSP_SRAM_BASE_OFFSET 0x180000 110 + #define MTL_ADSP_SRAM_WINDOW_SIZE 0x8000 77 111 78 112 /* Constants used when accessing SRAM, space shared with firmware */ 79 - #define AVS_FW_REG_BASE(adev) ((adev)->spec->sram->base_offset) 113 + #define AVS_FW_REG_BASE(adev) ((adev)->spec->hipc->sts_offset) 80 114 #define AVS_FW_REG_STATUS(adev) (AVS_FW_REG_BASE(adev) + 0x0) 81 115 #define AVS_FW_REG_ERROR(adev) (AVS_FW_REG_BASE(adev) + 0x4) 82 116