1b27f4523SCezary Rojewski // SPDX-License-Identifier: GPL-2.0-only 2b27f4523SCezary Rojewski // 3b27f4523SCezary Rojewski // Copyright(c) 2021-2022 Intel Corporation. All rights reserved. 4b27f4523SCezary Rojewski // 5b27f4523SCezary Rojewski // Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6b27f4523SCezary Rojewski // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7b27f4523SCezary Rojewski // 8b27f4523SCezary Rojewski // Special thanks to: 9b27f4523SCezary Rojewski // Krzysztof Hejmowski <krzysztof.hejmowski@intel.com> 10b27f4523SCezary Rojewski // Michal Sienkiewicz <michal.sienkiewicz@intel.com> 11b27f4523SCezary Rojewski // Filip Proborszcz 12b27f4523SCezary Rojewski // 13b27f4523SCezary Rojewski // for sharing Intel AudioDSP expertise and helping shape the very 14b27f4523SCezary Rojewski // foundation of this driver 15b27f4523SCezary Rojewski // 16b27f4523SCezary Rojewski 171affc44eSCezary Rojewski #include <linux/module.h> 18b27f4523SCezary Rojewski #include <linux/pci.h> 191affc44eSCezary Rojewski #include <sound/hda_codec.h> 201affc44eSCezary Rojewski #include <sound/hda_i915.h> 211affc44eSCezary Rojewski #include <sound/hda_register.h> 22b27f4523SCezary Rojewski #include <sound/hdaudio.h> 231affc44eSCezary Rojewski #include <sound/hdaudio_ext.h> 241affc44eSCezary Rojewski #include <sound/intel-dsp-config.h> 251affc44eSCezary Rojewski #include <sound/intel-nhlt.h> 26c50cea05SCezary Rojewski #include "../../codecs/hda.h" 27b27f4523SCezary Rojewski #include "avs.h" 281affc44eSCezary Rojewski #include "cldma.h" 29b27f4523SCezary Rojewski 30b27f4523SCezary Rojewski static void 31b27f4523SCezary Rojewski avs_hda_update_config_dword(struct hdac_bus *bus, u32 reg, u32 mask, u32 value) 32b27f4523SCezary Rojewski { 33b27f4523SCezary Rojewski struct pci_dev *pci = to_pci_dev(bus->dev); 34b27f4523SCezary Rojewski u32 data; 35b27f4523SCezary Rojewski 36b27f4523SCezary Rojewski pci_read_config_dword(pci, reg, &data); 37b27f4523SCezary Rojewski data &= ~mask; 38b27f4523SCezary Rojewski data |= (value & mask); 39b27f4523SCezary Rojewski pci_write_config_dword(pci, reg, data); 40b27f4523SCezary Rojewski } 41b27f4523SCezary Rojewski 42b27f4523SCezary Rojewski void avs_hda_power_gating_enable(struct avs_dev *adev, bool enable) 43b27f4523SCezary Rojewski { 44b27f4523SCezary Rojewski u32 value; 45b27f4523SCezary Rojewski 46b27f4523SCezary Rojewski value = enable ? 0 : AZX_PGCTL_LSRMD_MASK; 47b27f4523SCezary Rojewski avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL, 48b27f4523SCezary Rojewski AZX_PGCTL_LSRMD_MASK, value); 49b27f4523SCezary Rojewski } 50b27f4523SCezary Rojewski 51b27f4523SCezary Rojewski static void avs_hdac_clock_gating_enable(struct hdac_bus *bus, bool enable) 52b27f4523SCezary Rojewski { 53b27f4523SCezary Rojewski u32 value; 54b27f4523SCezary Rojewski 55b27f4523SCezary Rojewski value = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0; 56b27f4523SCezary Rojewski avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, value); 57b27f4523SCezary Rojewski } 58b27f4523SCezary Rojewski 59b27f4523SCezary Rojewski void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable) 60b27f4523SCezary Rojewski { 61b27f4523SCezary Rojewski avs_hdac_clock_gating_enable(&adev->base.core, enable); 62b27f4523SCezary Rojewski } 63b27f4523SCezary Rojewski 64b27f4523SCezary Rojewski void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable) 65b27f4523SCezary Rojewski { 66b27f4523SCezary Rojewski u32 value; 67b27f4523SCezary Rojewski 68b27f4523SCezary Rojewski value = enable ? AZX_VS_EM2_L1SEN : 0; 69b27f4523SCezary Rojewski snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, value); 70b27f4523SCezary Rojewski } 711affc44eSCezary Rojewski 721affc44eSCezary Rojewski static int avs_hdac_bus_init_streams(struct hdac_bus *bus) 731affc44eSCezary Rojewski { 741affc44eSCezary Rojewski unsigned int cp_streams, pb_streams; 751affc44eSCezary Rojewski unsigned int gcap; 761affc44eSCezary Rojewski 771affc44eSCezary Rojewski gcap = snd_hdac_chip_readw(bus, GCAP); 781affc44eSCezary Rojewski cp_streams = (gcap >> 8) & 0x0F; 791affc44eSCezary Rojewski pb_streams = (gcap >> 12) & 0x0F; 801affc44eSCezary Rojewski bus->num_streams = cp_streams + pb_streams; 811affc44eSCezary Rojewski 821affc44eSCezary Rojewski snd_hdac_ext_stream_init_all(bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE); 831affc44eSCezary Rojewski snd_hdac_ext_stream_init_all(bus, cp_streams, pb_streams, SNDRV_PCM_STREAM_PLAYBACK); 841affc44eSCezary Rojewski 851affc44eSCezary Rojewski return snd_hdac_bus_alloc_stream_pages(bus); 861affc44eSCezary Rojewski } 871affc44eSCezary Rojewski 881affc44eSCezary Rojewski static bool avs_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset) 891affc44eSCezary Rojewski { 901affc44eSCezary Rojewski struct hdac_ext_link *hlink; 911affc44eSCezary Rojewski bool ret; 921affc44eSCezary Rojewski 931affc44eSCezary Rojewski avs_hdac_clock_gating_enable(bus, false); 941affc44eSCezary Rojewski ret = snd_hdac_bus_init_chip(bus, full_reset); 951affc44eSCezary Rojewski 961affc44eSCezary Rojewski /* Reset stream-to-link mapping */ 971affc44eSCezary Rojewski list_for_each_entry(hlink, &bus->hlink_list, list) 981affc44eSCezary Rojewski writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); 991affc44eSCezary Rojewski 1001affc44eSCezary Rojewski avs_hdac_clock_gating_enable(bus, true); 1011affc44eSCezary Rojewski 1021affc44eSCezary Rojewski /* Set DUM bit to address incorrect position reporting for capture 1031affc44eSCezary Rojewski * streams. In order to do so, CTRL needs to be out of reset state 1041affc44eSCezary Rojewski */ 1051affc44eSCezary Rojewski snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM); 1061affc44eSCezary Rojewski 1071affc44eSCezary Rojewski return ret; 1081affc44eSCezary Rojewski } 1091affc44eSCezary Rojewski 1101affc44eSCezary Rojewski static int probe_codec(struct hdac_bus *bus, int addr) 1111affc44eSCezary Rojewski { 1121affc44eSCezary Rojewski struct hda_codec *codec; 1131affc44eSCezary Rojewski unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | 1141affc44eSCezary Rojewski (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; 1151affc44eSCezary Rojewski unsigned int res = -1; 1161affc44eSCezary Rojewski int ret; 1171affc44eSCezary Rojewski 1181affc44eSCezary Rojewski mutex_lock(&bus->cmd_mutex); 1191affc44eSCezary Rojewski snd_hdac_bus_send_cmd(bus, cmd); 1201affc44eSCezary Rojewski snd_hdac_bus_get_response(bus, addr, &res); 1211affc44eSCezary Rojewski mutex_unlock(&bus->cmd_mutex); 1221affc44eSCezary Rojewski if (res == -1) 1231affc44eSCezary Rojewski return -EIO; 1241affc44eSCezary Rojewski 1251affc44eSCezary Rojewski dev_dbg(bus->dev, "codec #%d probed OK: 0x%x\n", addr, res); 1261affc44eSCezary Rojewski 1271affc44eSCezary Rojewski codec = snd_hda_codec_device_init(to_hda_bus(bus), addr, "hdaudioB%dD%d", bus->idx, addr); 1281affc44eSCezary Rojewski if (IS_ERR(codec)) { 1291affc44eSCezary Rojewski dev_err(bus->dev, "init codec failed: %ld\n", PTR_ERR(codec)); 1301affc44eSCezary Rojewski return PTR_ERR(codec); 1311affc44eSCezary Rojewski } 1321affc44eSCezary Rojewski /* 1331affc44eSCezary Rojewski * Allow avs_core suspend by forcing suspended state on all 1341affc44eSCezary Rojewski * of its codec child devices. Component interested in 1351affc44eSCezary Rojewski * dealing with hda codecs directly takes pm responsibilities 1361affc44eSCezary Rojewski */ 1371affc44eSCezary Rojewski pm_runtime_set_suspended(hda_codec_dev(codec)); 1381affc44eSCezary Rojewski 1391affc44eSCezary Rojewski /* configure effectively creates new ASoC component */ 1401affc44eSCezary Rojewski ret = snd_hda_codec_configure(codec); 1411affc44eSCezary Rojewski if (ret < 0) { 1421affc44eSCezary Rojewski dev_err(bus->dev, "failed to config codec %d\n", ret); 1431affc44eSCezary Rojewski return ret; 1441affc44eSCezary Rojewski } 1451affc44eSCezary Rojewski 1461affc44eSCezary Rojewski return 0; 1471affc44eSCezary Rojewski } 1481affc44eSCezary Rojewski 1491affc44eSCezary Rojewski static void avs_hdac_bus_probe_codecs(struct hdac_bus *bus) 1501affc44eSCezary Rojewski { 1511affc44eSCezary Rojewski int c; 1521affc44eSCezary Rojewski 1531affc44eSCezary Rojewski /* First try to probe all given codec slots */ 1541affc44eSCezary Rojewski for (c = 0; c < HDA_MAX_CODECS; c++) { 1551affc44eSCezary Rojewski if (!(bus->codec_mask & BIT(c))) 1561affc44eSCezary Rojewski continue; 1571affc44eSCezary Rojewski 1581affc44eSCezary Rojewski if (!probe_codec(bus, c)) 1591affc44eSCezary Rojewski /* success, continue probing */ 1601affc44eSCezary Rojewski continue; 1611affc44eSCezary Rojewski 1621affc44eSCezary Rojewski /* 1631affc44eSCezary Rojewski * Some BIOSen give you wrong codec addresses 1641affc44eSCezary Rojewski * that don't exist 1651affc44eSCezary Rojewski */ 1661affc44eSCezary Rojewski dev_warn(bus->dev, "Codec #%d probe error; disabling it...\n", c); 1671affc44eSCezary Rojewski bus->codec_mask &= ~BIT(c); 1681affc44eSCezary Rojewski /* 1691affc44eSCezary Rojewski * More badly, accessing to a non-existing 1701affc44eSCezary Rojewski * codec often screws up the controller bus, 1711affc44eSCezary Rojewski * and disturbs the further communications. 1721affc44eSCezary Rojewski * Thus if an error occurs during probing, 1731affc44eSCezary Rojewski * better to reset the controller bus to get 1741affc44eSCezary Rojewski * back to the sanity state. 1751affc44eSCezary Rojewski */ 1761affc44eSCezary Rojewski snd_hdac_bus_stop_chip(bus); 1771affc44eSCezary Rojewski avs_hdac_bus_init_chip(bus, true); 1781affc44eSCezary Rojewski } 1791affc44eSCezary Rojewski } 1801affc44eSCezary Rojewski 1811affc44eSCezary Rojewski static void avs_hda_probe_work(struct work_struct *work) 1821affc44eSCezary Rojewski { 1831affc44eSCezary Rojewski struct avs_dev *adev = container_of(work, struct avs_dev, probe_work); 1841affc44eSCezary Rojewski struct hdac_bus *bus = &adev->base.core; 1851affc44eSCezary Rojewski struct hdac_ext_link *hlink; 1861affc44eSCezary Rojewski int ret; 1871affc44eSCezary Rojewski 1881affc44eSCezary Rojewski pm_runtime_set_active(bus->dev); /* clear runtime_error flag */ 1891affc44eSCezary Rojewski 1901affc44eSCezary Rojewski ret = snd_hdac_i915_init(bus); 1911affc44eSCezary Rojewski if (ret < 0) 1921affc44eSCezary Rojewski dev_info(bus->dev, "i915 init unsuccessful: %d\n", ret); 1931affc44eSCezary Rojewski 1941affc44eSCezary Rojewski snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); 1951affc44eSCezary Rojewski avs_hdac_bus_init_chip(bus, true); 1961affc44eSCezary Rojewski avs_hdac_bus_probe_codecs(bus); 1971affc44eSCezary Rojewski snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); 1981affc44eSCezary Rojewski 1991affc44eSCezary Rojewski /* with all codecs probed, links can be powered down */ 2001affc44eSCezary Rojewski list_for_each_entry(hlink, &bus->hlink_list, list) 2011affc44eSCezary Rojewski snd_hdac_ext_bus_link_put(bus, hlink); 2021affc44eSCezary Rojewski 2031affc44eSCezary Rojewski snd_hdac_ext_bus_ppcap_enable(bus, true); 2041affc44eSCezary Rojewski snd_hdac_ext_bus_ppcap_int_enable(bus, true); 2051affc44eSCezary Rojewski 2061affc44eSCezary Rojewski ret = avs_dsp_first_boot_firmware(adev); 2071affc44eSCezary Rojewski if (ret < 0) 2081affc44eSCezary Rojewski return; 2091affc44eSCezary Rojewski 2101affc44eSCezary Rojewski adev->nhlt = intel_nhlt_init(adev->dev); 2111affc44eSCezary Rojewski if (!adev->nhlt) 2121affc44eSCezary Rojewski dev_info(bus->dev, "platform has no NHLT\n"); 2131affc44eSCezary Rojewski 2141affc44eSCezary Rojewski avs_register_all_boards(adev); 2151affc44eSCezary Rojewski 2161affc44eSCezary Rojewski /* configure PM */ 2171affc44eSCezary Rojewski pm_runtime_set_autosuspend_delay(bus->dev, 2000); 2181affc44eSCezary Rojewski pm_runtime_use_autosuspend(bus->dev); 2191affc44eSCezary Rojewski pm_runtime_mark_last_busy(bus->dev); 2201affc44eSCezary Rojewski pm_runtime_put_autosuspend(bus->dev); 2211affc44eSCezary Rojewski pm_runtime_allow(bus->dev); 2221affc44eSCezary Rojewski } 2231affc44eSCezary Rojewski 2241affc44eSCezary Rojewski static void hdac_stream_update_pos(struct hdac_stream *stream, u64 buffer_size) 2251affc44eSCezary Rojewski { 2261affc44eSCezary Rojewski u64 prev_pos, pos, num_bytes; 2271affc44eSCezary Rojewski 2281affc44eSCezary Rojewski div64_u64_rem(stream->curr_pos, buffer_size, &prev_pos); 2291affc44eSCezary Rojewski pos = snd_hdac_stream_get_pos_posbuf(stream); 2301affc44eSCezary Rojewski 2311affc44eSCezary Rojewski if (pos < prev_pos) 2321affc44eSCezary Rojewski num_bytes = (buffer_size - prev_pos) + pos; 2331affc44eSCezary Rojewski else 2341affc44eSCezary Rojewski num_bytes = pos - prev_pos; 2351affc44eSCezary Rojewski 2361affc44eSCezary Rojewski stream->curr_pos += num_bytes; 2371affc44eSCezary Rojewski } 2381affc44eSCezary Rojewski 2391affc44eSCezary Rojewski /* called from IRQ */ 2401affc44eSCezary Rojewski static void hdac_update_stream(struct hdac_bus *bus, struct hdac_stream *stream) 2411affc44eSCezary Rojewski { 2421affc44eSCezary Rojewski if (stream->substream) { 2431affc44eSCezary Rojewski snd_pcm_period_elapsed(stream->substream); 2441affc44eSCezary Rojewski } else if (stream->cstream) { 2451affc44eSCezary Rojewski u64 buffer_size = stream->cstream->runtime->buffer_size; 2461affc44eSCezary Rojewski 2471affc44eSCezary Rojewski hdac_stream_update_pos(stream, buffer_size); 2481affc44eSCezary Rojewski snd_compr_fragment_elapsed(stream->cstream); 2491affc44eSCezary Rojewski } 2501affc44eSCezary Rojewski } 2511affc44eSCezary Rojewski 2521affc44eSCezary Rojewski static irqreturn_t hdac_bus_irq_handler(int irq, void *context) 2531affc44eSCezary Rojewski { 2541affc44eSCezary Rojewski struct hdac_bus *bus = context; 2551affc44eSCezary Rojewski u32 mask, int_enable; 2561affc44eSCezary Rojewski u32 status; 2571affc44eSCezary Rojewski int ret = IRQ_NONE; 2581affc44eSCezary Rojewski 2591affc44eSCezary Rojewski if (!pm_runtime_active(bus->dev)) 2601affc44eSCezary Rojewski return ret; 2611affc44eSCezary Rojewski 2621affc44eSCezary Rojewski spin_lock(&bus->reg_lock); 2631affc44eSCezary Rojewski 2641affc44eSCezary Rojewski status = snd_hdac_chip_readl(bus, INTSTS); 2651affc44eSCezary Rojewski if (status == 0 || status == UINT_MAX) { 2661affc44eSCezary Rojewski spin_unlock(&bus->reg_lock); 2671affc44eSCezary Rojewski return ret; 2681affc44eSCezary Rojewski } 2691affc44eSCezary Rojewski 2701affc44eSCezary Rojewski /* clear rirb int */ 2711affc44eSCezary Rojewski status = snd_hdac_chip_readb(bus, RIRBSTS); 2721affc44eSCezary Rojewski if (status & RIRB_INT_MASK) { 2731affc44eSCezary Rojewski if (status & RIRB_INT_RESPONSE) 2741affc44eSCezary Rojewski snd_hdac_bus_update_rirb(bus); 2751affc44eSCezary Rojewski snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); 2761affc44eSCezary Rojewski } 2771affc44eSCezary Rojewski 2781affc44eSCezary Rojewski mask = (0x1 << bus->num_streams) - 1; 2791affc44eSCezary Rojewski 2801affc44eSCezary Rojewski status = snd_hdac_chip_readl(bus, INTSTS); 2811affc44eSCezary Rojewski status &= mask; 2821affc44eSCezary Rojewski if (status) { 2831affc44eSCezary Rojewski /* Disable stream interrupts; Re-enable in bottom half */ 2841affc44eSCezary Rojewski int_enable = snd_hdac_chip_readl(bus, INTCTL); 2851affc44eSCezary Rojewski snd_hdac_chip_writel(bus, INTCTL, (int_enable & (~mask))); 2861affc44eSCezary Rojewski ret = IRQ_WAKE_THREAD; 2871affc44eSCezary Rojewski } else { 2881affc44eSCezary Rojewski ret = IRQ_HANDLED; 2891affc44eSCezary Rojewski } 2901affc44eSCezary Rojewski 2911affc44eSCezary Rojewski spin_unlock(&bus->reg_lock); 2921affc44eSCezary Rojewski return ret; 2931affc44eSCezary Rojewski } 2941affc44eSCezary Rojewski 2951affc44eSCezary Rojewski static irqreturn_t hdac_bus_irq_thread(int irq, void *context) 2961affc44eSCezary Rojewski { 2971affc44eSCezary Rojewski struct hdac_bus *bus = context; 2981affc44eSCezary Rojewski u32 status; 2991affc44eSCezary Rojewski u32 int_enable; 3001affc44eSCezary Rojewski u32 mask; 3011affc44eSCezary Rojewski unsigned long flags; 3021affc44eSCezary Rojewski 3031affc44eSCezary Rojewski status = snd_hdac_chip_readl(bus, INTSTS); 3041affc44eSCezary Rojewski 3051affc44eSCezary Rojewski snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream); 3061affc44eSCezary Rojewski 3071affc44eSCezary Rojewski /* Re-enable stream interrupts */ 3081affc44eSCezary Rojewski mask = (0x1 << bus->num_streams) - 1; 3091affc44eSCezary Rojewski spin_lock_irqsave(&bus->reg_lock, flags); 3101affc44eSCezary Rojewski int_enable = snd_hdac_chip_readl(bus, INTCTL); 3111affc44eSCezary Rojewski snd_hdac_chip_writel(bus, INTCTL, (int_enable | mask)); 3121affc44eSCezary Rojewski spin_unlock_irqrestore(&bus->reg_lock, flags); 3131affc44eSCezary Rojewski 3141affc44eSCezary Rojewski return IRQ_HANDLED; 3151affc44eSCezary Rojewski } 3161affc44eSCezary Rojewski 3171affc44eSCezary Rojewski static int avs_hdac_acquire_irq(struct avs_dev *adev) 3181affc44eSCezary Rojewski { 3191affc44eSCezary Rojewski struct hdac_bus *bus = &adev->base.core; 3201affc44eSCezary Rojewski struct pci_dev *pci = to_pci_dev(bus->dev); 3211affc44eSCezary Rojewski int ret; 3221affc44eSCezary Rojewski 3231affc44eSCezary Rojewski /* request one and check that we only got one interrupt */ 3241affc44eSCezary Rojewski ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_LEGACY); 3251affc44eSCezary Rojewski if (ret != 1) { 3261affc44eSCezary Rojewski dev_err(adev->dev, "Failed to allocate IRQ vector: %d\n", ret); 3271affc44eSCezary Rojewski return ret; 3281affc44eSCezary Rojewski } 3291affc44eSCezary Rojewski 3301affc44eSCezary Rojewski ret = pci_request_irq(pci, 0, hdac_bus_irq_handler, hdac_bus_irq_thread, bus, 3311affc44eSCezary Rojewski KBUILD_MODNAME); 3321affc44eSCezary Rojewski if (ret < 0) { 3331affc44eSCezary Rojewski dev_err(adev->dev, "Failed to request stream IRQ handler: %d\n", ret); 3341affc44eSCezary Rojewski goto free_vector; 3351affc44eSCezary Rojewski } 3361affc44eSCezary Rojewski 3371affc44eSCezary Rojewski ret = pci_request_irq(pci, 0, avs_dsp_irq_handler, avs_dsp_irq_thread, adev, 3381affc44eSCezary Rojewski KBUILD_MODNAME); 3391affc44eSCezary Rojewski if (ret < 0) { 3401affc44eSCezary Rojewski dev_err(adev->dev, "Failed to request IPC IRQ handler: %d\n", ret); 3411affc44eSCezary Rojewski goto free_stream_irq; 3421affc44eSCezary Rojewski } 3431affc44eSCezary Rojewski 3441affc44eSCezary Rojewski return 0; 3451affc44eSCezary Rojewski 3461affc44eSCezary Rojewski free_stream_irq: 3471affc44eSCezary Rojewski pci_free_irq(pci, 0, bus); 3481affc44eSCezary Rojewski free_vector: 3491affc44eSCezary Rojewski pci_free_irq_vectors(pci); 3501affc44eSCezary Rojewski return ret; 3511affc44eSCezary Rojewski } 3521affc44eSCezary Rojewski 3531affc44eSCezary Rojewski static int avs_bus_init(struct avs_dev *adev, struct pci_dev *pci, const struct pci_device_id *id) 3541affc44eSCezary Rojewski { 3551affc44eSCezary Rojewski struct hda_bus *bus = &adev->base; 3561affc44eSCezary Rojewski struct avs_ipc *ipc; 3571affc44eSCezary Rojewski struct device *dev = &pci->dev; 3581affc44eSCezary Rojewski int ret; 3591affc44eSCezary Rojewski 360c50cea05SCezary Rojewski ret = snd_hdac_ext_bus_init(&bus->core, dev, NULL, &soc_hda_ext_bus_ops); 3611affc44eSCezary Rojewski if (ret < 0) 3621affc44eSCezary Rojewski return ret; 3631affc44eSCezary Rojewski 3641affc44eSCezary Rojewski bus->core.use_posbuf = 1; 3651affc44eSCezary Rojewski bus->core.bdl_pos_adj = 0; 3661affc44eSCezary Rojewski bus->core.sync_write = 1; 3671affc44eSCezary Rojewski bus->pci = pci; 3681affc44eSCezary Rojewski bus->mixer_assigned = -1; 3691affc44eSCezary Rojewski mutex_init(&bus->prepare_mutex); 3701affc44eSCezary Rojewski 3711affc44eSCezary Rojewski ipc = devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL); 3721affc44eSCezary Rojewski if (!ipc) 3731affc44eSCezary Rojewski return -ENOMEM; 3741affc44eSCezary Rojewski ret = avs_ipc_init(ipc, dev); 3751affc44eSCezary Rojewski if (ret < 0) 3761affc44eSCezary Rojewski return ret; 3771affc44eSCezary Rojewski 3781affc44eSCezary Rojewski adev->dev = dev; 3791affc44eSCezary Rojewski adev->spec = (const struct avs_spec *)id->driver_data; 3801affc44eSCezary Rojewski adev->ipc = ipc; 3811affc44eSCezary Rojewski adev->hw_cfg.dsp_cores = hweight_long(AVS_MAIN_CORE_MASK); 3821affc44eSCezary Rojewski INIT_WORK(&adev->probe_work, avs_hda_probe_work); 3831affc44eSCezary Rojewski INIT_LIST_HEAD(&adev->comp_list); 3841affc44eSCezary Rojewski INIT_LIST_HEAD(&adev->path_list); 3851affc44eSCezary Rojewski INIT_LIST_HEAD(&adev->fw_list); 3861affc44eSCezary Rojewski init_completion(&adev->fw_ready); 3871affc44eSCezary Rojewski spin_lock_init(&adev->path_list_lock); 3881affc44eSCezary Rojewski mutex_init(&adev->modres_mutex); 3891affc44eSCezary Rojewski mutex_init(&adev->comp_list_mutex); 3901affc44eSCezary Rojewski mutex_init(&adev->path_mutex); 3911affc44eSCezary Rojewski 3921affc44eSCezary Rojewski return 0; 3931affc44eSCezary Rojewski } 3941affc44eSCezary Rojewski 3951affc44eSCezary Rojewski static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) 3961affc44eSCezary Rojewski { 3971affc44eSCezary Rojewski struct hdac_bus *bus; 3981affc44eSCezary Rojewski struct avs_dev *adev; 3991affc44eSCezary Rojewski struct device *dev = &pci->dev; 4001affc44eSCezary Rojewski int ret; 4011affc44eSCezary Rojewski 4021affc44eSCezary Rojewski ret = snd_intel_dsp_driver_probe(pci); 4031affc44eSCezary Rojewski if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_AVS) 4041affc44eSCezary Rojewski return -ENODEV; 4051affc44eSCezary Rojewski 4061affc44eSCezary Rojewski ret = pcim_enable_device(pci); 4071affc44eSCezary Rojewski if (ret < 0) 4081affc44eSCezary Rojewski return ret; 4091affc44eSCezary Rojewski 4101affc44eSCezary Rojewski adev = devm_kzalloc(dev, sizeof(*adev), GFP_KERNEL); 4111affc44eSCezary Rojewski if (!adev) 4121affc44eSCezary Rojewski return -ENOMEM; 4131affc44eSCezary Rojewski ret = avs_bus_init(adev, pci, id); 4141affc44eSCezary Rojewski if (ret < 0) { 4151affc44eSCezary Rojewski dev_err(dev, "failed to init avs bus: %d\n", ret); 4161affc44eSCezary Rojewski return ret; 4171affc44eSCezary Rojewski } 4181affc44eSCezary Rojewski 4191affc44eSCezary Rojewski ret = pci_request_regions(pci, "AVS HDAudio"); 4201affc44eSCezary Rojewski if (ret < 0) 4211affc44eSCezary Rojewski return ret; 4221affc44eSCezary Rojewski 4231affc44eSCezary Rojewski bus = &adev->base.core; 4241affc44eSCezary Rojewski bus->addr = pci_resource_start(pci, 0); 4251affc44eSCezary Rojewski bus->remap_addr = pci_ioremap_bar(pci, 0); 4261affc44eSCezary Rojewski if (!bus->remap_addr) { 4271affc44eSCezary Rojewski dev_err(bus->dev, "ioremap error\n"); 4281affc44eSCezary Rojewski ret = -ENXIO; 4291affc44eSCezary Rojewski goto err_remap_bar0; 4301affc44eSCezary Rojewski } 4311affc44eSCezary Rojewski 4321affc44eSCezary Rojewski adev->dsp_ba = pci_ioremap_bar(pci, 4); 4331affc44eSCezary Rojewski if (!adev->dsp_ba) { 4341affc44eSCezary Rojewski dev_err(bus->dev, "ioremap error\n"); 4351affc44eSCezary Rojewski ret = -ENXIO; 4361affc44eSCezary Rojewski goto err_remap_bar4; 4371affc44eSCezary Rojewski } 4381affc44eSCezary Rojewski 4391affc44eSCezary Rojewski snd_hdac_bus_parse_capabilities(bus); 4401affc44eSCezary Rojewski if (bus->mlcap) 4411affc44eSCezary Rojewski snd_hdac_ext_bus_get_ml_capabilities(bus); 4421affc44eSCezary Rojewski 4431affc44eSCezary Rojewski if (!dma_set_mask(dev, DMA_BIT_MASK(64))) { 4441affc44eSCezary Rojewski dma_set_coherent_mask(dev, DMA_BIT_MASK(64)); 4451affc44eSCezary Rojewski } else { 4461affc44eSCezary Rojewski dma_set_mask(dev, DMA_BIT_MASK(32)); 4471affc44eSCezary Rojewski dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); 4481affc44eSCezary Rojewski } 4491affc44eSCezary Rojewski 4501affc44eSCezary Rojewski ret = avs_hdac_bus_init_streams(bus); 4511affc44eSCezary Rojewski if (ret < 0) { 4521affc44eSCezary Rojewski dev_err(dev, "failed to init streams: %d\n", ret); 4531affc44eSCezary Rojewski goto err_init_streams; 4541affc44eSCezary Rojewski } 4551affc44eSCezary Rojewski 4561affc44eSCezary Rojewski ret = avs_hdac_acquire_irq(adev); 4571affc44eSCezary Rojewski if (ret < 0) { 4581affc44eSCezary Rojewski dev_err(bus->dev, "failed to acquire irq: %d\n", ret); 4591affc44eSCezary Rojewski goto err_acquire_irq; 4601affc44eSCezary Rojewski } 4611affc44eSCezary Rojewski 4621affc44eSCezary Rojewski pci_set_master(pci); 4631affc44eSCezary Rojewski pci_set_drvdata(pci, bus); 4641affc44eSCezary Rojewski device_disable_async_suspend(dev); 4651affc44eSCezary Rojewski 4661affc44eSCezary Rojewski schedule_work(&adev->probe_work); 4671affc44eSCezary Rojewski 4681affc44eSCezary Rojewski return 0; 4691affc44eSCezary Rojewski 4701affc44eSCezary Rojewski err_acquire_irq: 4711affc44eSCezary Rojewski snd_hdac_bus_free_stream_pages(bus); 4721affc44eSCezary Rojewski snd_hdac_stream_free_all(bus); 4731affc44eSCezary Rojewski err_init_streams: 4741affc44eSCezary Rojewski iounmap(adev->dsp_ba); 4751affc44eSCezary Rojewski err_remap_bar4: 4761affc44eSCezary Rojewski iounmap(bus->remap_addr); 4771affc44eSCezary Rojewski err_remap_bar0: 4781affc44eSCezary Rojewski pci_release_regions(pci); 4791affc44eSCezary Rojewski return ret; 4801affc44eSCezary Rojewski } 4811affc44eSCezary Rojewski 4821affc44eSCezary Rojewski static void avs_pci_remove(struct pci_dev *pci) 4831affc44eSCezary Rojewski { 4841affc44eSCezary Rojewski struct hdac_device *hdev, *save; 4851affc44eSCezary Rojewski struct hdac_bus *bus = pci_get_drvdata(pci); 4861affc44eSCezary Rojewski struct avs_dev *adev = hdac_to_avs(bus); 4871affc44eSCezary Rojewski 4881affc44eSCezary Rojewski cancel_work_sync(&adev->probe_work); 4891affc44eSCezary Rojewski avs_ipc_block(adev->ipc); 4901affc44eSCezary Rojewski 4911affc44eSCezary Rojewski avs_unregister_all_boards(adev); 4921affc44eSCezary Rojewski 4931affc44eSCezary Rojewski if (adev->nhlt) 4941affc44eSCezary Rojewski intel_nhlt_free(adev->nhlt); 4951affc44eSCezary Rojewski 4961affc44eSCezary Rojewski if (avs_platattr_test(adev, CLDMA)) 4971affc44eSCezary Rojewski hda_cldma_free(&code_loader); 4981affc44eSCezary Rojewski 4991affc44eSCezary Rojewski snd_hdac_stop_streams_and_chip(bus); 5001affc44eSCezary Rojewski avs_dsp_op(adev, int_control, false); 5011affc44eSCezary Rojewski snd_hdac_ext_bus_ppcap_int_enable(bus, false); 5021affc44eSCezary Rojewski 5031affc44eSCezary Rojewski /* it is safe to remove all codecs from the system now */ 5041affc44eSCezary Rojewski list_for_each_entry_safe(hdev, save, &bus->codec_list, list) 5051affc44eSCezary Rojewski snd_hda_codec_unregister(hdac_to_hda_codec(hdev)); 5061affc44eSCezary Rojewski 5071affc44eSCezary Rojewski snd_hdac_bus_free_stream_pages(bus); 5081affc44eSCezary Rojewski snd_hdac_stream_free_all(bus); 5091affc44eSCezary Rojewski /* reverse ml_capabilities */ 5101affc44eSCezary Rojewski snd_hdac_link_free_all(bus); 5111affc44eSCezary Rojewski snd_hdac_ext_bus_exit(bus); 5121affc44eSCezary Rojewski 5131affc44eSCezary Rojewski avs_dsp_core_disable(adev, GENMASK(adev->hw_cfg.dsp_cores - 1, 0)); 5141affc44eSCezary Rojewski snd_hdac_ext_bus_ppcap_enable(bus, false); 5151affc44eSCezary Rojewski 5161affc44eSCezary Rojewski /* snd_hdac_stop_streams_and_chip does that already? */ 5171affc44eSCezary Rojewski snd_hdac_bus_stop_chip(bus); 5181affc44eSCezary Rojewski snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); 5191affc44eSCezary Rojewski if (bus->audio_component) 5201affc44eSCezary Rojewski snd_hdac_i915_exit(bus); 5211affc44eSCezary Rojewski 5221affc44eSCezary Rojewski avs_module_info_free(adev); 5231affc44eSCezary Rojewski pci_free_irq(pci, 0, adev); 5241affc44eSCezary Rojewski pci_free_irq(pci, 0, bus); 5251affc44eSCezary Rojewski pci_free_irq_vectors(pci); 5261affc44eSCezary Rojewski iounmap(bus->remap_addr); 5271affc44eSCezary Rojewski iounmap(adev->dsp_ba); 5281affc44eSCezary Rojewski pci_release_regions(pci); 5291affc44eSCezary Rojewski 5301affc44eSCezary Rojewski /* Firmware is not needed anymore */ 5311affc44eSCezary Rojewski avs_release_firmwares(adev); 5321affc44eSCezary Rojewski 5331affc44eSCezary Rojewski /* pm_runtime_forbid() can rpm_resume() which we do not want */ 5341affc44eSCezary Rojewski pm_runtime_disable(&pci->dev); 5351affc44eSCezary Rojewski pm_runtime_forbid(&pci->dev); 5361affc44eSCezary Rojewski pm_runtime_enable(&pci->dev); 5371affc44eSCezary Rojewski pm_runtime_get_noresume(&pci->dev); 5381affc44eSCezary Rojewski } 5391affc44eSCezary Rojewski 540cfbc100eSCezary Rojewski static int __maybe_unused avs_suspend_common(struct avs_dev *adev) 541cfbc100eSCezary Rojewski { 542cfbc100eSCezary Rojewski struct hdac_bus *bus = &adev->base.core; 543cfbc100eSCezary Rojewski int ret; 544cfbc100eSCezary Rojewski 545cfbc100eSCezary Rojewski flush_work(&adev->probe_work); 546cfbc100eSCezary Rojewski 547cfbc100eSCezary Rojewski snd_hdac_ext_bus_link_power_down_all(bus); 548cfbc100eSCezary Rojewski 549cfbc100eSCezary Rojewski ret = avs_ipc_set_dx(adev, AVS_MAIN_CORE_MASK, false); 550cfbc100eSCezary Rojewski /* 551cfbc100eSCezary Rojewski * pm_runtime is blocked on DSP failure but system-wide suspend is not. 552cfbc100eSCezary Rojewski * Do not block entire system from suspending if that's the case. 553cfbc100eSCezary Rojewski */ 554cfbc100eSCezary Rojewski if (ret && ret != -EPERM) { 555cfbc100eSCezary Rojewski dev_err(adev->dev, "set dx failed: %d\n", ret); 556cfbc100eSCezary Rojewski return AVS_IPC_RET(ret); 557cfbc100eSCezary Rojewski } 558cfbc100eSCezary Rojewski 559*daa36bbcSCezary Rojewski avs_ipc_block(adev->ipc); 560cfbc100eSCezary Rojewski avs_dsp_op(adev, int_control, false); 561cfbc100eSCezary Rojewski snd_hdac_ext_bus_ppcap_int_enable(bus, false); 562cfbc100eSCezary Rojewski 563cfbc100eSCezary Rojewski ret = avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); 564cfbc100eSCezary Rojewski if (ret < 0) { 565cfbc100eSCezary Rojewski dev_err(adev->dev, "core_mask %ld disable failed: %d\n", AVS_MAIN_CORE_MASK, ret); 566cfbc100eSCezary Rojewski return ret; 567cfbc100eSCezary Rojewski } 568cfbc100eSCezary Rojewski 569cfbc100eSCezary Rojewski snd_hdac_ext_bus_ppcap_enable(bus, false); 570cfbc100eSCezary Rojewski /* disable LP SRAM retention */ 571cfbc100eSCezary Rojewski avs_hda_power_gating_enable(adev, false); 572cfbc100eSCezary Rojewski snd_hdac_bus_stop_chip(bus); 573cfbc100eSCezary Rojewski /* disable CG when putting controller to reset */ 574cfbc100eSCezary Rojewski avs_hdac_clock_gating_enable(bus, false); 575cfbc100eSCezary Rojewski snd_hdac_bus_enter_link_reset(bus); 576cfbc100eSCezary Rojewski avs_hdac_clock_gating_enable(bus, true); 577cfbc100eSCezary Rojewski 578cfbc100eSCezary Rojewski snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); 579cfbc100eSCezary Rojewski 580cfbc100eSCezary Rojewski return 0; 581cfbc100eSCezary Rojewski } 582cfbc100eSCezary Rojewski 583cfbc100eSCezary Rojewski static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool purge) 584cfbc100eSCezary Rojewski { 585cfbc100eSCezary Rojewski struct hdac_bus *bus = &adev->base.core; 586cfbc100eSCezary Rojewski struct hdac_ext_link *hlink; 587cfbc100eSCezary Rojewski int ret; 588cfbc100eSCezary Rojewski 589cfbc100eSCezary Rojewski snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); 590cfbc100eSCezary Rojewski avs_hdac_bus_init_chip(bus, true); 591cfbc100eSCezary Rojewski 592cfbc100eSCezary Rojewski snd_hdac_ext_bus_ppcap_enable(bus, true); 593cfbc100eSCezary Rojewski snd_hdac_ext_bus_ppcap_int_enable(bus, true); 594cfbc100eSCezary Rojewski 595cfbc100eSCezary Rojewski ret = avs_dsp_boot_firmware(adev, purge); 596cfbc100eSCezary Rojewski if (ret < 0) { 597cfbc100eSCezary Rojewski dev_err(adev->dev, "firmware boot failed: %d\n", ret); 598cfbc100eSCezary Rojewski return ret; 599cfbc100eSCezary Rojewski } 600cfbc100eSCezary Rojewski 601cfbc100eSCezary Rojewski /* turn off the links that were off before suspend */ 602cfbc100eSCezary Rojewski list_for_each_entry(hlink, &bus->hlink_list, list) { 603cfbc100eSCezary Rojewski if (!hlink->ref_count) 604cfbc100eSCezary Rojewski snd_hdac_ext_bus_link_power_down(hlink); 605cfbc100eSCezary Rojewski } 606cfbc100eSCezary Rojewski 607cfbc100eSCezary Rojewski /* check dma status and clean up CORB/RIRB buffers */ 608cfbc100eSCezary Rojewski if (!bus->cmd_dma_state) 609cfbc100eSCezary Rojewski snd_hdac_bus_stop_cmd_io(bus); 610cfbc100eSCezary Rojewski 611cfbc100eSCezary Rojewski return 0; 612cfbc100eSCezary Rojewski } 613cfbc100eSCezary Rojewski 614cfbc100eSCezary Rojewski static int __maybe_unused avs_suspend(struct device *dev) 615cfbc100eSCezary Rojewski { 616cfbc100eSCezary Rojewski return avs_suspend_common(to_avs_dev(dev)); 617cfbc100eSCezary Rojewski } 618cfbc100eSCezary Rojewski 619cfbc100eSCezary Rojewski static int __maybe_unused avs_resume(struct device *dev) 620cfbc100eSCezary Rojewski { 621cfbc100eSCezary Rojewski return avs_resume_common(to_avs_dev(dev), true); 622cfbc100eSCezary Rojewski } 623cfbc100eSCezary Rojewski 624cfbc100eSCezary Rojewski static int __maybe_unused avs_runtime_suspend(struct device *dev) 625cfbc100eSCezary Rojewski { 626cfbc100eSCezary Rojewski return avs_suspend_common(to_avs_dev(dev)); 627cfbc100eSCezary Rojewski } 628cfbc100eSCezary Rojewski 629cfbc100eSCezary Rojewski static int __maybe_unused avs_runtime_resume(struct device *dev) 630cfbc100eSCezary Rojewski { 631cfbc100eSCezary Rojewski return avs_resume_common(to_avs_dev(dev), true); 632cfbc100eSCezary Rojewski } 633cfbc100eSCezary Rojewski 634cfbc100eSCezary Rojewski static const struct dev_pm_ops avs_dev_pm = { 635cfbc100eSCezary Rojewski SET_SYSTEM_SLEEP_PM_OPS(avs_suspend, avs_resume) 636cfbc100eSCezary Rojewski SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL) 637cfbc100eSCezary Rojewski }; 638cfbc100eSCezary Rojewski 639b3e29075SCezary Rojewski static const struct avs_spec skl_desc = { 640b3e29075SCezary Rojewski .name = "skl", 641b3e29075SCezary Rojewski .min_fw_version = { 642b3e29075SCezary Rojewski .major = 9, 643b3e29075SCezary Rojewski .minor = 21, 644b3e29075SCezary Rojewski .hotfix = 0, 645b3e29075SCezary Rojewski .build = 4732, 646b3e29075SCezary Rojewski }, 647b3e29075SCezary Rojewski .dsp_ops = &skl_dsp_ops, 648b3e29075SCezary Rojewski .core_init_mask = 1, 649b3e29075SCezary Rojewski .attributes = AVS_PLATATTR_CLDMA, 650b3e29075SCezary Rojewski .sram_base_offset = SKL_ADSP_SRAM_BASE_OFFSET, 651b3e29075SCezary Rojewski .sram_window_size = SKL_ADSP_SRAM_WINDOW_SIZE, 652b3e29075SCezary Rojewski .rom_status = SKL_ADSP_SRAM_BASE_OFFSET, 653b3e29075SCezary Rojewski }; 654b3e29075SCezary Rojewski 655c8c960c1SCezary Rojewski static const struct avs_spec apl_desc = { 656c8c960c1SCezary Rojewski .name = "apl", 657c8c960c1SCezary Rojewski .min_fw_version = { 658c8c960c1SCezary Rojewski .major = 9, 659c8c960c1SCezary Rojewski .minor = 22, 660c8c960c1SCezary Rojewski .hotfix = 1, 661c8c960c1SCezary Rojewski .build = 4323, 662c8c960c1SCezary Rojewski }, 663c8c960c1SCezary Rojewski .dsp_ops = &apl_dsp_ops, 664c8c960c1SCezary Rojewski .core_init_mask = 3, 665c8c960c1SCezary Rojewski .attributes = AVS_PLATATTR_IMR, 666c8c960c1SCezary Rojewski .sram_base_offset = APL_ADSP_SRAM_BASE_OFFSET, 667c8c960c1SCezary Rojewski .sram_window_size = APL_ADSP_SRAM_WINDOW_SIZE, 668c8c960c1SCezary Rojewski .rom_status = APL_ADSP_SRAM_BASE_OFFSET, 669c8c960c1SCezary Rojewski }; 670c8c960c1SCezary Rojewski 6711affc44eSCezary Rojewski static const struct pci_device_id avs_ids[] = { 672b3e29075SCezary Rojewski { PCI_VDEVICE(INTEL, 0x9d70), (unsigned long)&skl_desc }, /* SKL */ 673b3e29075SCezary Rojewski { PCI_VDEVICE(INTEL, 0x9d71), (unsigned long)&skl_desc }, /* KBL */ 674c8c960c1SCezary Rojewski { PCI_VDEVICE(INTEL, 0x5a98), (unsigned long)&apl_desc }, /* APL */ 675c8c960c1SCezary Rojewski { PCI_VDEVICE(INTEL, 0x3198), (unsigned long)&apl_desc }, /* GML */ 6761affc44eSCezary Rojewski { 0 } 6771affc44eSCezary Rojewski }; 6781affc44eSCezary Rojewski MODULE_DEVICE_TABLE(pci, avs_ids); 6791affc44eSCezary Rojewski 6801affc44eSCezary Rojewski static struct pci_driver avs_pci_driver = { 6811affc44eSCezary Rojewski .name = KBUILD_MODNAME, 6821affc44eSCezary Rojewski .id_table = avs_ids, 6831affc44eSCezary Rojewski .probe = avs_pci_probe, 6841affc44eSCezary Rojewski .remove = avs_pci_remove, 685cfbc100eSCezary Rojewski .driver = { 686cfbc100eSCezary Rojewski .pm = &avs_dev_pm, 687cfbc100eSCezary Rojewski }, 6881affc44eSCezary Rojewski }; 6891affc44eSCezary Rojewski module_pci_driver(avs_pci_driver); 6901affc44eSCezary Rojewski 6911affc44eSCezary Rojewski MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); 6921affc44eSCezary Rojewski MODULE_AUTHOR("Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>"); 6931affc44eSCezary Rojewski MODULE_DESCRIPTION("Intel cAVS sound driver"); 6941affc44eSCezary Rojewski MODULE_LICENSE("GPL"); 695