xref: /linux-6.15/sound/soc/sof/intel/hda-ctrl.c (revision 8a300c8f)
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