1*8a300c8fSLiam Girdwood // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2*8a300c8fSLiam Girdwood // 3*8a300c8fSLiam Girdwood // This file is provided under a dual BSD/GPLv2 license. When using or 4*8a300c8fSLiam Girdwood // redistributing this file, you may do so under either license. 5*8a300c8fSLiam Girdwood // 6*8a300c8fSLiam Girdwood // Copyright(c) 2018 Intel Corporation. All rights reserved. 7*8a300c8fSLiam Girdwood // 8*8a300c8fSLiam Girdwood // Authors: Liam Girdwood <[email protected]> 9*8a300c8fSLiam Girdwood // Ranjani Sridharan <[email protected]> 10*8a300c8fSLiam Girdwood // Rander Wang <[email protected]> 11*8a300c8fSLiam Girdwood // Keyon Jie <[email protected]> 12*8a300c8fSLiam Girdwood // 13*8a300c8fSLiam Girdwood 14*8a300c8fSLiam Girdwood /* 15*8a300c8fSLiam Girdwood * Hardware interface for generic Intel audio DSP HDA IP 16*8a300c8fSLiam Girdwood */ 17*8a300c8fSLiam Girdwood 18*8a300c8fSLiam Girdwood #include <sound/hdaudio_ext.h> 19*8a300c8fSLiam Girdwood #include <sound/hda_register.h> 20*8a300c8fSLiam Girdwood #include "../ops.h" 21*8a300c8fSLiam Girdwood #include "hda.h" 22*8a300c8fSLiam Girdwood 23*8a300c8fSLiam Girdwood /* 24*8a300c8fSLiam Girdwood * HDA Operations. 25*8a300c8fSLiam Girdwood */ 26*8a300c8fSLiam Girdwood 27*8a300c8fSLiam Girdwood int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset) 28*8a300c8fSLiam Girdwood { 29*8a300c8fSLiam Girdwood unsigned long timeout; 30*8a300c8fSLiam Girdwood u32 gctl = 0; 31*8a300c8fSLiam Girdwood u32 val; 32*8a300c8fSLiam Girdwood 33*8a300c8fSLiam Girdwood /* 0 to enter reset and 1 to exit reset */ 34*8a300c8fSLiam Girdwood val = reset ? 0 : SOF_HDA_GCTL_RESET; 35*8a300c8fSLiam Girdwood 36*8a300c8fSLiam Girdwood /* enter/exit HDA controller reset */ 37*8a300c8fSLiam Girdwood snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL, 38*8a300c8fSLiam Girdwood SOF_HDA_GCTL_RESET, val); 39*8a300c8fSLiam Girdwood 40*8a300c8fSLiam Girdwood /* wait to enter/exit reset */ 41*8a300c8fSLiam Girdwood timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT); 42*8a300c8fSLiam Girdwood while (time_before(jiffies, timeout)) { 43*8a300c8fSLiam Girdwood gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL); 44*8a300c8fSLiam Girdwood if ((gctl & SOF_HDA_GCTL_RESET) == val) 45*8a300c8fSLiam Girdwood return 0; 46*8a300c8fSLiam Girdwood usleep_range(500, 1000); 47*8a300c8fSLiam Girdwood } 48*8a300c8fSLiam Girdwood 49*8a300c8fSLiam Girdwood /* enter/exit reset failed */ 50*8a300c8fSLiam Girdwood dev_err(sdev->dev, "error: failed to %s HDA controller gctl 0x%x\n", 51*8a300c8fSLiam Girdwood reset ? "reset" : "ready", gctl); 52*8a300c8fSLiam Girdwood return -EIO; 53*8a300c8fSLiam Girdwood } 54*8a300c8fSLiam Girdwood 55*8a300c8fSLiam Girdwood int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev) 56*8a300c8fSLiam Girdwood { 57*8a300c8fSLiam Girdwood struct hdac_bus *bus = sof_to_bus(sdev); 58*8a300c8fSLiam Girdwood u32 cap, offset, feature; 59*8a300c8fSLiam Girdwood int count = 0; 60*8a300c8fSLiam Girdwood 61*8a300c8fSLiam Girdwood offset = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_LLCH); 62*8a300c8fSLiam Girdwood 63*8a300c8fSLiam Girdwood do { 64*8a300c8fSLiam Girdwood cap = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, offset); 65*8a300c8fSLiam Girdwood 66*8a300c8fSLiam Girdwood dev_dbg(sdev->dev, "checking for capabilities at offset 0x%x\n", 67*8a300c8fSLiam Girdwood offset & SOF_HDA_CAP_NEXT_MASK); 68*8a300c8fSLiam Girdwood 69*8a300c8fSLiam Girdwood feature = (cap & SOF_HDA_CAP_ID_MASK) >> SOF_HDA_CAP_ID_OFF; 70*8a300c8fSLiam Girdwood 71*8a300c8fSLiam Girdwood switch (feature) { 72*8a300c8fSLiam Girdwood case SOF_HDA_PP_CAP_ID: 73*8a300c8fSLiam Girdwood dev_dbg(sdev->dev, "found DSP capability at 0x%x\n", 74*8a300c8fSLiam Girdwood offset); 75*8a300c8fSLiam Girdwood bus->ppcap = bus->remap_addr + offset; 76*8a300c8fSLiam Girdwood sdev->bar[HDA_DSP_PP_BAR] = bus->ppcap; 77*8a300c8fSLiam Girdwood break; 78*8a300c8fSLiam Girdwood case SOF_HDA_SPIB_CAP_ID: 79*8a300c8fSLiam Girdwood dev_dbg(sdev->dev, "found SPIB capability at 0x%x\n", 80*8a300c8fSLiam Girdwood offset); 81*8a300c8fSLiam Girdwood bus->spbcap = bus->remap_addr + offset; 82*8a300c8fSLiam Girdwood sdev->bar[HDA_DSP_SPIB_BAR] = bus->spbcap; 83*8a300c8fSLiam Girdwood break; 84*8a300c8fSLiam Girdwood case SOF_HDA_DRSM_CAP_ID: 85*8a300c8fSLiam Girdwood dev_dbg(sdev->dev, "found DRSM capability at 0x%x\n", 86*8a300c8fSLiam Girdwood offset); 87*8a300c8fSLiam Girdwood bus->drsmcap = bus->remap_addr + offset; 88*8a300c8fSLiam Girdwood sdev->bar[HDA_DSP_DRSM_BAR] = bus->drsmcap; 89*8a300c8fSLiam Girdwood break; 90*8a300c8fSLiam Girdwood case SOF_HDA_GTS_CAP_ID: 91*8a300c8fSLiam Girdwood dev_dbg(sdev->dev, "found GTS capability at 0x%x\n", 92*8a300c8fSLiam Girdwood offset); 93*8a300c8fSLiam Girdwood bus->gtscap = bus->remap_addr + offset; 94*8a300c8fSLiam Girdwood break; 95*8a300c8fSLiam Girdwood case SOF_HDA_ML_CAP_ID: 96*8a300c8fSLiam Girdwood dev_dbg(sdev->dev, "found ML capability at 0x%x\n", 97*8a300c8fSLiam Girdwood offset); 98*8a300c8fSLiam Girdwood bus->mlcap = bus->remap_addr + offset; 99*8a300c8fSLiam Girdwood break; 100*8a300c8fSLiam Girdwood default: 101*8a300c8fSLiam Girdwood dev_vdbg(sdev->dev, "found capability %d at 0x%x\n", 102*8a300c8fSLiam Girdwood feature, offset); 103*8a300c8fSLiam Girdwood break; 104*8a300c8fSLiam Girdwood } 105*8a300c8fSLiam Girdwood 106*8a300c8fSLiam Girdwood offset = cap & SOF_HDA_CAP_NEXT_MASK; 107*8a300c8fSLiam Girdwood } while (count++ <= SOF_HDA_MAX_CAPS && offset); 108*8a300c8fSLiam Girdwood 109*8a300c8fSLiam Girdwood return 0; 110*8a300c8fSLiam Girdwood } 111*8a300c8fSLiam Girdwood 112*8a300c8fSLiam Girdwood void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable) 113*8a300c8fSLiam Girdwood { 114*8a300c8fSLiam Girdwood u32 val = enable ? SOF_HDA_PPCTL_GPROCEN : 0; 115*8a300c8fSLiam Girdwood 116*8a300c8fSLiam Girdwood snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, 117*8a300c8fSLiam Girdwood SOF_HDA_PPCTL_GPROCEN, val); 118*8a300c8fSLiam Girdwood } 119*8a300c8fSLiam Girdwood 120*8a300c8fSLiam Girdwood void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable) 121*8a300c8fSLiam Girdwood { 122*8a300c8fSLiam Girdwood u32 val = enable ? SOF_HDA_PPCTL_PIE : 0; 123*8a300c8fSLiam Girdwood 124*8a300c8fSLiam Girdwood snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, 125*8a300c8fSLiam Girdwood SOF_HDA_PPCTL_PIE, val); 126*8a300c8fSLiam Girdwood } 127*8a300c8fSLiam Girdwood 128*8a300c8fSLiam Girdwood void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable) 129*8a300c8fSLiam Girdwood { 130*8a300c8fSLiam Girdwood u32 val = enable ? PCI_CGCTL_MISCBDCGE_MASK : 0; 131*8a300c8fSLiam Girdwood 132*8a300c8fSLiam Girdwood snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_MISCBDCGE_MASK, val); 133*8a300c8fSLiam Girdwood } 134*8a300c8fSLiam Girdwood 135*8a300c8fSLiam Girdwood /* 136*8a300c8fSLiam Girdwood * enable/disable audio dsp clock gating and power gating bits. 137*8a300c8fSLiam Girdwood * This allows the HW to opportunistically power and clock gate 138*8a300c8fSLiam Girdwood * the audio dsp when it is idle 139*8a300c8fSLiam Girdwood */ 140*8a300c8fSLiam Girdwood int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) 141*8a300c8fSLiam Girdwood { 142*8a300c8fSLiam Girdwood #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 143*8a300c8fSLiam Girdwood struct hdac_bus *bus = sof_to_bus(sdev); 144*8a300c8fSLiam Girdwood #endif 145*8a300c8fSLiam Girdwood u32 val; 146*8a300c8fSLiam Girdwood 147*8a300c8fSLiam Girdwood /* enable/disable audio dsp clock gating */ 148*8a300c8fSLiam Girdwood val = enable ? PCI_CGCTL_ADSPDCGE : 0; 149*8a300c8fSLiam Girdwood snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val); 150*8a300c8fSLiam Girdwood 151*8a300c8fSLiam Girdwood #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 152*8a300c8fSLiam Girdwood /* enable/disable L1 support */ 153*8a300c8fSLiam Girdwood val = enable ? SOF_HDA_VS_EM2_L1SEN : 0; 154*8a300c8fSLiam Girdwood snd_hdac_chip_updatel(bus, VS_EM2, SOF_HDA_VS_EM2_L1SEN, val); 155*8a300c8fSLiam Girdwood #endif 156*8a300c8fSLiam Girdwood 157*8a300c8fSLiam Girdwood /* enable/disable audio dsp power gating */ 158*8a300c8fSLiam Girdwood val = enable ? 0 : PCI_PGCTL_ADSPPGD; 159*8a300c8fSLiam Girdwood snd_sof_pci_update_bits(sdev, PCI_PGCTL, PCI_PGCTL_ADSPPGD, val); 160*8a300c8fSLiam Girdwood 161*8a300c8fSLiam Girdwood return 0; 162*8a300c8fSLiam Girdwood } 163*8a300c8fSLiam Girdwood 164*8a300c8fSLiam Girdwood #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) 165*8a300c8fSLiam Girdwood /* 166*8a300c8fSLiam Girdwood * While performing reset, controller may not come back properly and causing 167*8a300c8fSLiam Girdwood * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset 168*8a300c8fSLiam Girdwood * (init chip) and then again set CGCTL.MISCBDCGE to 1 169*8a300c8fSLiam Girdwood */ 170*8a300c8fSLiam Girdwood int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) 171*8a300c8fSLiam Girdwood { 172*8a300c8fSLiam Girdwood struct hdac_bus *bus = sof_to_bus(sdev); 173*8a300c8fSLiam Girdwood int ret; 174*8a300c8fSLiam Girdwood 175*8a300c8fSLiam Girdwood hda_dsp_ctrl_misc_clock_gating(sdev, false); 176*8a300c8fSLiam Girdwood ret = snd_hdac_bus_init_chip(bus, full_reset); 177*8a300c8fSLiam Girdwood hda_dsp_ctrl_misc_clock_gating(sdev, true); 178*8a300c8fSLiam Girdwood 179*8a300c8fSLiam Girdwood return ret; 180*8a300c8fSLiam Girdwood } 181*8a300c8fSLiam Girdwood #endif 182