18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license. When using or 48c2ecf20Sopenharmony_ci// redistributing this file, you may do so under either license. 58c2ecf20Sopenharmony_ci// 68c2ecf20Sopenharmony_ci// Copyright(c) 2018 Intel Corporation. All rights reserved. 78c2ecf20Sopenharmony_ci// 88c2ecf20Sopenharmony_ci// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com> 98c2ecf20Sopenharmony_ci// Ranjani Sridharan <ranjani.sridharan@linux.intel.com> 108c2ecf20Sopenharmony_ci// Rander Wang <rander.wang@intel.com> 118c2ecf20Sopenharmony_ci// Keyon Jie <yang.jie@linux.intel.com> 128c2ecf20Sopenharmony_ci// 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * Hardware interface for generic Intel audio DSP HDA IP 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <sound/hdaudio_ext.h> 208c2ecf20Sopenharmony_ci#include <sound/hda_register.h> 218c2ecf20Sopenharmony_ci#include <sound/hda_component.h> 228c2ecf20Sopenharmony_ci#include "../ops.h" 238c2ecf20Sopenharmony_ci#include "hda.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 268c2ecf20Sopenharmony_cistatic int hda_codec_mask = -1; 278c2ecf20Sopenharmony_cimodule_param_named(codec_mask, hda_codec_mask, int, 0444); 288c2ecf20Sopenharmony_ciMODULE_PARM_DESC(codec_mask, "SOF HDA codec mask for probing"); 298c2ecf20Sopenharmony_ci#endif 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * HDA Operations. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ciint hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci unsigned long timeout; 388c2ecf20Sopenharmony_ci u32 gctl = 0; 398c2ecf20Sopenharmony_ci u32 val; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* 0 to enter reset and 1 to exit reset */ 428c2ecf20Sopenharmony_ci val = reset ? 0 : SOF_HDA_GCTL_RESET; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* enter/exit HDA controller reset */ 458c2ecf20Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL, 468c2ecf20Sopenharmony_ci SOF_HDA_GCTL_RESET, val); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* wait to enter/exit reset */ 498c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT); 508c2ecf20Sopenharmony_ci while (time_before(jiffies, timeout)) { 518c2ecf20Sopenharmony_ci gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL); 528c2ecf20Sopenharmony_ci if ((gctl & SOF_HDA_GCTL_RESET) == val) 538c2ecf20Sopenharmony_ci return 0; 548c2ecf20Sopenharmony_ci usleep_range(500, 1000); 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* enter/exit reset failed */ 588c2ecf20Sopenharmony_ci dev_err(sdev->dev, "error: failed to %s HDA controller gctl 0x%x\n", 598c2ecf20Sopenharmony_ci reset ? "reset" : "ready", gctl); 608c2ecf20Sopenharmony_ci return -EIO; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ciint hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct hdac_bus *bus = sof_to_bus(sdev); 668c2ecf20Sopenharmony_ci u32 cap, offset, feature; 678c2ecf20Sopenharmony_ci int count = 0; 688c2ecf20Sopenharmony_ci int ret; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* 718c2ecf20Sopenharmony_ci * On some devices, one reset cycle is necessary before reading 728c2ecf20Sopenharmony_ci * capabilities 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci ret = hda_dsp_ctrl_link_reset(sdev, true); 758c2ecf20Sopenharmony_ci if (ret < 0) 768c2ecf20Sopenharmony_ci return ret; 778c2ecf20Sopenharmony_ci ret = hda_dsp_ctrl_link_reset(sdev, false); 788c2ecf20Sopenharmony_ci if (ret < 0) 798c2ecf20Sopenharmony_ci return ret; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci offset = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_LLCH); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci do { 848c2ecf20Sopenharmony_ci dev_dbg(sdev->dev, "checking for capabilities at offset 0x%x\n", 858c2ecf20Sopenharmony_ci offset & SOF_HDA_CAP_NEXT_MASK); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci cap = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, offset); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (cap == -1) { 908c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "Invalid capability reg read\n"); 918c2ecf20Sopenharmony_ci break; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci feature = (cap & SOF_HDA_CAP_ID_MASK) >> SOF_HDA_CAP_ID_OFF; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci switch (feature) { 978c2ecf20Sopenharmony_ci case SOF_HDA_PP_CAP_ID: 988c2ecf20Sopenharmony_ci dev_dbg(sdev->dev, "found DSP capability at 0x%x\n", 998c2ecf20Sopenharmony_ci offset); 1008c2ecf20Sopenharmony_ci bus->ppcap = bus->remap_addr + offset; 1018c2ecf20Sopenharmony_ci sdev->bar[HDA_DSP_PP_BAR] = bus->ppcap; 1028c2ecf20Sopenharmony_ci break; 1038c2ecf20Sopenharmony_ci case SOF_HDA_SPIB_CAP_ID: 1048c2ecf20Sopenharmony_ci dev_dbg(sdev->dev, "found SPIB capability at 0x%x\n", 1058c2ecf20Sopenharmony_ci offset); 1068c2ecf20Sopenharmony_ci bus->spbcap = bus->remap_addr + offset; 1078c2ecf20Sopenharmony_ci sdev->bar[HDA_DSP_SPIB_BAR] = bus->spbcap; 1088c2ecf20Sopenharmony_ci break; 1098c2ecf20Sopenharmony_ci case SOF_HDA_DRSM_CAP_ID: 1108c2ecf20Sopenharmony_ci dev_dbg(sdev->dev, "found DRSM capability at 0x%x\n", 1118c2ecf20Sopenharmony_ci offset); 1128c2ecf20Sopenharmony_ci bus->drsmcap = bus->remap_addr + offset; 1138c2ecf20Sopenharmony_ci sdev->bar[HDA_DSP_DRSM_BAR] = bus->drsmcap; 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci case SOF_HDA_GTS_CAP_ID: 1168c2ecf20Sopenharmony_ci dev_dbg(sdev->dev, "found GTS capability at 0x%x\n", 1178c2ecf20Sopenharmony_ci offset); 1188c2ecf20Sopenharmony_ci bus->gtscap = bus->remap_addr + offset; 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci case SOF_HDA_ML_CAP_ID: 1218c2ecf20Sopenharmony_ci dev_dbg(sdev->dev, "found ML capability at 0x%x\n", 1228c2ecf20Sopenharmony_ci offset); 1238c2ecf20Sopenharmony_ci bus->mlcap = bus->remap_addr + offset; 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci default: 1268c2ecf20Sopenharmony_ci dev_dbg(sdev->dev, "found capability %d at 0x%x\n", 1278c2ecf20Sopenharmony_ci feature, offset); 1288c2ecf20Sopenharmony_ci break; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci offset = cap & SOF_HDA_CAP_NEXT_MASK; 1328c2ecf20Sopenharmony_ci } while (count++ <= SOF_HDA_MAX_CAPS && offset); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return 0; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_civoid hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci u32 val = enable ? SOF_HDA_PPCTL_GPROCEN : 0; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, 1428c2ecf20Sopenharmony_ci SOF_HDA_PPCTL_GPROCEN, val); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_civoid hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci u32 val = enable ? SOF_HDA_PPCTL_PIE : 0; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, 1508c2ecf20Sopenharmony_ci SOF_HDA_PPCTL_PIE, val); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_civoid hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci u32 val = enable ? PCI_CGCTL_MISCBDCGE_MASK : 0; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_MISCBDCGE_MASK, val); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* 1618c2ecf20Sopenharmony_ci * enable/disable audio dsp clock gating and power gating bits. 1628c2ecf20Sopenharmony_ci * This allows the HW to opportunistically power and clock gate 1638c2ecf20Sopenharmony_ci * the audio dsp when it is idle 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ciint hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci u32 val; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* enable/disable audio dsp clock gating */ 1708c2ecf20Sopenharmony_ci val = enable ? PCI_CGCTL_ADSPDCGE : 0; 1718c2ecf20Sopenharmony_ci snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* enable/disable DMI Link L1 support */ 1748c2ecf20Sopenharmony_ci val = enable ? HDA_VS_INTEL_EM2_L1SEN : 0; 1758c2ecf20Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_EM2, 1768c2ecf20Sopenharmony_ci HDA_VS_INTEL_EM2_L1SEN, val); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* enable/disable audio dsp power gating */ 1798c2ecf20Sopenharmony_ci val = enable ? 0 : PCI_PGCTL_ADSPPGD; 1808c2ecf20Sopenharmony_ci snd_sof_pci_update_bits(sdev, PCI_PGCTL, PCI_PGCTL_ADSPPGD, val); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ciint hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct hdac_bus *bus = sof_to_bus(sdev); 1888c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 1898c2ecf20Sopenharmony_ci struct hdac_ext_link *hlink; 1908c2ecf20Sopenharmony_ci#endif 1918c2ecf20Sopenharmony_ci struct hdac_stream *stream; 1928c2ecf20Sopenharmony_ci int sd_offset, ret = 0; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (bus->chip_init) 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 1988c2ecf20Sopenharmony_ci snd_hdac_set_codec_wakeup(bus, true); 1998c2ecf20Sopenharmony_ci#endif 2008c2ecf20Sopenharmony_ci hda_dsp_ctrl_misc_clock_gating(sdev, false); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (full_reset) { 2038c2ecf20Sopenharmony_ci /* reset HDA controller */ 2048c2ecf20Sopenharmony_ci ret = hda_dsp_ctrl_link_reset(sdev, true); 2058c2ecf20Sopenharmony_ci if (ret < 0) { 2068c2ecf20Sopenharmony_ci dev_err(sdev->dev, "error: failed to reset HDA controller\n"); 2078c2ecf20Sopenharmony_ci goto err; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci usleep_range(500, 1000); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* exit HDA controller reset */ 2138c2ecf20Sopenharmony_ci ret = hda_dsp_ctrl_link_reset(sdev, false); 2148c2ecf20Sopenharmony_ci if (ret < 0) { 2158c2ecf20Sopenharmony_ci dev_err(sdev->dev, "error: failed to exit HDA controller reset\n"); 2168c2ecf20Sopenharmony_ci goto err; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci usleep_range(1000, 1200); 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 2238c2ecf20Sopenharmony_ci /* check to see if controller is ready */ 2248c2ecf20Sopenharmony_ci if (!snd_hdac_chip_readb(bus, GCTL)) { 2258c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "controller not ready!\n"); 2268c2ecf20Sopenharmony_ci ret = -EBUSY; 2278c2ecf20Sopenharmony_ci goto err; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* Accept unsolicited responses */ 2318c2ecf20Sopenharmony_ci snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* detect codecs */ 2348c2ecf20Sopenharmony_ci if (!bus->codec_mask) { 2358c2ecf20Sopenharmony_ci bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS); 2368c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (hda_codec_mask != -1) { 2408c2ecf20Sopenharmony_ci bus->codec_mask &= hda_codec_mask; 2418c2ecf20Sopenharmony_ci dev_dbg(bus->dev, "filtered codec_mask = 0x%lx\n", 2428c2ecf20Sopenharmony_ci bus->codec_mask); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci#endif 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* clear stream status */ 2478c2ecf20Sopenharmony_ci list_for_each_entry(stream, &bus->stream_list, list) { 2488c2ecf20Sopenharmony_ci sd_offset = SOF_STREAM_SD_OFFSET(stream); 2498c2ecf20Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, 2508c2ecf20Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, 2518c2ecf20Sopenharmony_ci SOF_HDA_CL_DMA_SD_INT_MASK); 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* clear WAKESTS */ 2558c2ecf20Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, 2568c2ecf20Sopenharmony_ci SOF_HDA_WAKESTS_INT_MASK); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 2598c2ecf20Sopenharmony_ci /* clear rirb status */ 2608c2ecf20Sopenharmony_ci snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); 2618c2ecf20Sopenharmony_ci#endif 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* clear interrupt status register */ 2648c2ecf20Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS, 2658c2ecf20Sopenharmony_ci SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 2688c2ecf20Sopenharmony_ci /* initialize the codec command I/O */ 2698c2ecf20Sopenharmony_ci snd_hdac_bus_init_cmd_io(bus); 2708c2ecf20Sopenharmony_ci#endif 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* enable CIE and GIE interrupts */ 2738c2ecf20Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, 2748c2ecf20Sopenharmony_ci SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, 2758c2ecf20Sopenharmony_ci SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* program the position buffer */ 2788c2ecf20Sopenharmony_ci if (bus->use_posbuf && bus->posbuf.addr) { 2798c2ecf20Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE, 2808c2ecf20Sopenharmony_ci (u32)bus->posbuf.addr); 2818c2ecf20Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPUBASE, 2828c2ecf20Sopenharmony_ci upper_32_bits(bus->posbuf.addr)); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 2868c2ecf20Sopenharmony_ci /* Reset stream-to-link mapping */ 2878c2ecf20Sopenharmony_ci list_for_each_entry(hlink, &bus->hlink_list, list) 2888c2ecf20Sopenharmony_ci writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); 2898c2ecf20Sopenharmony_ci#endif 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci bus->chip_init = true; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cierr: 2948c2ecf20Sopenharmony_ci hda_dsp_ctrl_misc_clock_gating(sdev, true); 2958c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 2968c2ecf20Sopenharmony_ci snd_hdac_set_codec_wakeup(bus, false); 2978c2ecf20Sopenharmony_ci#endif 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci return ret; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_civoid hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct hdac_bus *bus = sof_to_bus(sdev); 3058c2ecf20Sopenharmony_ci struct hdac_stream *stream; 3068c2ecf20Sopenharmony_ci int sd_offset; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (!bus->chip_init) 3098c2ecf20Sopenharmony_ci return; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* disable interrupts in stream descriptor */ 3128c2ecf20Sopenharmony_ci list_for_each_entry(stream, &bus->stream_list, list) { 3138c2ecf20Sopenharmony_ci sd_offset = SOF_STREAM_SD_OFFSET(stream); 3148c2ecf20Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, 3158c2ecf20Sopenharmony_ci sd_offset + 3168c2ecf20Sopenharmony_ci SOF_HDA_ADSP_REG_CL_SD_CTL, 3178c2ecf20Sopenharmony_ci SOF_HDA_CL_DMA_SD_INT_MASK, 3188c2ecf20Sopenharmony_ci 0); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* disable SIE for all streams */ 3228c2ecf20Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, 3238c2ecf20Sopenharmony_ci SOF_HDA_INT_ALL_STREAM, 0); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* disable controller CIE and GIE */ 3268c2ecf20Sopenharmony_ci snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, 3278c2ecf20Sopenharmony_ci SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, 3288c2ecf20Sopenharmony_ci 0); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* clear stream status */ 3318c2ecf20Sopenharmony_ci list_for_each_entry(stream, &bus->stream_list, list) { 3328c2ecf20Sopenharmony_ci sd_offset = SOF_STREAM_SD_OFFSET(stream); 3338c2ecf20Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, 3348c2ecf20Sopenharmony_ci sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, 3358c2ecf20Sopenharmony_ci SOF_HDA_CL_DMA_SD_INT_MASK); 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* clear WAKESTS */ 3398c2ecf20Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, 3408c2ecf20Sopenharmony_ci SOF_HDA_WAKESTS_INT_MASK); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 3438c2ecf20Sopenharmony_ci /* clear rirb status */ 3448c2ecf20Sopenharmony_ci snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); 3458c2ecf20Sopenharmony_ci#endif 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* clear interrupt status register */ 3488c2ecf20Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS, 3498c2ecf20Sopenharmony_ci SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 3528c2ecf20Sopenharmony_ci /* disable CORB/RIRB */ 3538c2ecf20Sopenharmony_ci snd_hdac_bus_stop_cmd_io(bus); 3548c2ecf20Sopenharmony_ci#endif 3558c2ecf20Sopenharmony_ci /* disable position buffer */ 3568c2ecf20Sopenharmony_ci if (bus->posbuf.addr) { 3578c2ecf20Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, 3588c2ecf20Sopenharmony_ci SOF_HDA_ADSP_DPLBASE, 0); 3598c2ecf20Sopenharmony_ci snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, 3608c2ecf20Sopenharmony_ci SOF_HDA_ADSP_DPUBASE, 0); 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci bus->chip_init = false; 3648c2ecf20Sopenharmony_ci} 365