ASoC: SOF: Intel: hda: add multi-link helper for LOSVID
[linux-block.git] / sound / soc / sof / intel / hda-ctrl.c
CommitLineData
e149ca29 1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
8a300c8f
LG
2//
3// This file is provided under a dual BSD/GPLv2 license. When using or
4// redistributing this file, you may do so under either license.
5//
6// Copyright(c) 2018 Intel Corporation. All rights reserved.
7//
8// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
10// Rander Wang <rander.wang@intel.com>
11// Keyon Jie <yang.jie@linux.intel.com>
12//
13
14/*
15 * Hardware interface for generic Intel audio DSP HDA IP
16 */
17
4f6250b8 18#include <linux/module.h>
8a300c8f
LG
19#include <sound/hdaudio_ext.h>
20#include <sound/hda_register.h>
7e26df0c 21#include <sound/hda_component.h>
8a300c8f
LG
22#include "../ops.h"
23#include "hda.h"
24
4f6250b8
KV
25#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
26static int hda_codec_mask = -1;
27module_param_named(codec_mask, hda_codec_mask, int, 0444);
28MODULE_PARM_DESC(codec_mask, "SOF HDA codec mask for probing");
29#endif
30
8a300c8f
LG
31/*
32 * HDA Operations.
33 */
34
35int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset)
36{
37 unsigned long timeout;
38 u32 gctl = 0;
39 u32 val;
40
41 /* 0 to enter reset and 1 to exit reset */
42 val = reset ? 0 : SOF_HDA_GCTL_RESET;
43
44 /* enter/exit HDA controller reset */
45 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL,
46 SOF_HDA_GCTL_RESET, val);
47
48 /* wait to enter/exit reset */
49 timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT);
50 while (time_before(jiffies, timeout)) {
51 gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL);
52 if ((gctl & SOF_HDA_GCTL_RESET) == val)
53 return 0;
54 usleep_range(500, 1000);
55 }
56
57 /* enter/exit reset failed */
58 dev_err(sdev->dev, "error: failed to %s HDA controller gctl 0x%x\n",
59 reset ? "reset" : "ready", gctl);
60 return -EIO;
61}
62
63int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev)
64{
65 struct hdac_bus *bus = sof_to_bus(sdev);
66 u32 cap, offset, feature;
67 int count = 0;
f09e9c7f
PLB
68 int ret;
69
70 /*
71 * On some devices, one reset cycle is necessary before reading
72 * capabilities
73 */
74 ret = hda_dsp_ctrl_link_reset(sdev, true);
75 if (ret < 0)
76 return ret;
77 ret = hda_dsp_ctrl_link_reset(sdev, false);
78 if (ret < 0)
79 return ret;
8a300c8f
LG
80
81 offset = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_LLCH);
82
83 do {
8a300c8f
LG
84 dev_dbg(sdev->dev, "checking for capabilities at offset 0x%x\n",
85 offset & SOF_HDA_CAP_NEXT_MASK);
86
f09e9c7f
PLB
87 cap = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, offset);
88
89 if (cap == -1) {
90 dev_dbg(bus->dev, "Invalid capability reg read\n");
91 break;
92 }
93
8a300c8f
LG
94 feature = (cap & SOF_HDA_CAP_ID_MASK) >> SOF_HDA_CAP_ID_OFF;
95
96 switch (feature) {
97 case SOF_HDA_PP_CAP_ID:
98 dev_dbg(sdev->dev, "found DSP capability at 0x%x\n",
99 offset);
100 bus->ppcap = bus->remap_addr + offset;
101 sdev->bar[HDA_DSP_PP_BAR] = bus->ppcap;
102 break;
103 case SOF_HDA_SPIB_CAP_ID:
104 dev_dbg(sdev->dev, "found SPIB capability at 0x%x\n",
105 offset);
106 bus->spbcap = bus->remap_addr + offset;
107 sdev->bar[HDA_DSP_SPIB_BAR] = bus->spbcap;
108 break;
109 case SOF_HDA_DRSM_CAP_ID:
110 dev_dbg(sdev->dev, "found DRSM capability at 0x%x\n",
111 offset);
112 bus->drsmcap = bus->remap_addr + offset;
113 sdev->bar[HDA_DSP_DRSM_BAR] = bus->drsmcap;
114 break;
115 case SOF_HDA_GTS_CAP_ID:
116 dev_dbg(sdev->dev, "found GTS capability at 0x%x\n",
117 offset);
118 bus->gtscap = bus->remap_addr + offset;
119 break;
120 case SOF_HDA_ML_CAP_ID:
121 dev_dbg(sdev->dev, "found ML capability at 0x%x\n",
122 offset);
123 bus->mlcap = bus->remap_addr + offset;
124 break;
125 default:
f09e9c7f
PLB
126 dev_dbg(sdev->dev, "found capability %d at 0x%x\n",
127 feature, offset);
8a300c8f
LG
128 break;
129 }
130
131 offset = cap & SOF_HDA_CAP_NEXT_MASK;
132 } while (count++ <= SOF_HDA_MAX_CAPS && offset);
133
134 return 0;
135}
136
137void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable)
138{
139 u32 val = enable ? SOF_HDA_PPCTL_GPROCEN : 0;
140
141 snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
142 SOF_HDA_PPCTL_GPROCEN, val);
143}
144
145void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable)
146{
147 u32 val = enable ? SOF_HDA_PPCTL_PIE : 0;
148
149 snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
150 SOF_HDA_PPCTL_PIE, val);
151}
152
153void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable)
154{
155 u32 val = enable ? PCI_CGCTL_MISCBDCGE_MASK : 0;
156
157 snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_MISCBDCGE_MASK, val);
158}
159
160/*
161 * enable/disable audio dsp clock gating and power gating bits.
162 * This allows the HW to opportunistically power and clock gate
163 * the audio dsp when it is idle
164 */
165int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
166{
8a300c8f
LG
167 u32 val;
168
169 /* enable/disable audio dsp clock gating */
170 val = enable ? PCI_CGCTL_ADSPDCGE : 0;
171 snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val);
172
43b2ab90
RS
173 /* enable/disable DMI Link L1 support */
174 val = enable ? HDA_VS_INTEL_EM2_L1SEN : 0;
175 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_EM2,
176 HDA_VS_INTEL_EM2_L1SEN, val);
8a300c8f
LG
177
178 /* enable/disable audio dsp power gating */
179 val = enable ? 0 : PCI_PGCTL_ADSPPGD;
180 snd_sof_pci_update_bits(sdev, PCI_PGCTL, PCI_PGCTL_ADSPPGD, val);
181
182 return 0;
183}
184
b48b77d8 185int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev)
8a300c8f
LG
186{
187 struct hdac_bus *bus = sof_to_bus(sdev);
be1b577d
ZY
188 struct hdac_stream *stream;
189 int sd_offset, ret = 0;
190
191 if (bus->chip_init)
192 return 0;
8a300c8f 193
7e26df0c
KV
194#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
195 snd_hdac_set_codec_wakeup(bus, true);
196#endif
8a300c8f 197 hda_dsp_ctrl_misc_clock_gating(sdev, false);
be1b577d 198
b48b77d8
PLB
199 /* reset HDA controller */
200 ret = hda_dsp_ctrl_link_reset(sdev, true);
201 if (ret < 0) {
202 dev_err(sdev->dev, "error: failed to reset HDA controller\n");
203 goto err;
204 }
be1b577d 205
b48b77d8
PLB
206 /* exit HDA controller reset */
207 ret = hda_dsp_ctrl_link_reset(sdev, false);
208 if (ret < 0) {
209 dev_err(sdev->dev, "error: failed to exit HDA controller reset\n");
210 goto err;
be1b577d
ZY
211 }
212
213#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
be1b577d
ZY
214 /* Accept unsolicited responses */
215 snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
216
217 /* detect codecs */
218 if (!bus->codec_mask) {
219 bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
220 dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
221 }
4f6250b8
KV
222
223 if (hda_codec_mask != -1) {
224 bus->codec_mask &= hda_codec_mask;
225 dev_dbg(bus->dev, "filtered codec_mask = 0x%lx\n",
226 bus->codec_mask);
227 }
be1b577d
ZY
228#endif
229
230 /* clear stream status */
231 list_for_each_entry(stream, &bus->stream_list, list) {
232 sd_offset = SOF_STREAM_SD_OFFSET(stream);
3a39e0ea 233 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
38bf0780 234 sd_offset + SOF_HDA_ADSP_REG_SD_STS,
3a39e0ea 235 SOF_HDA_CL_DMA_SD_INT_MASK);
be1b577d
ZY
236 }
237
238 /* clear WAKESTS */
3a39e0ea
RS
239 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
240 SOF_HDA_WAKESTS_INT_MASK);
be1b577d
ZY
241
242#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
243 /* clear rirb status */
244 snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
245#endif
246
247 /* clear interrupt status register */
248 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
249 SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
250
251#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
252 /* initialize the codec command I/O */
253 snd_hdac_bus_init_cmd_io(bus);
254#endif
255
256 /* enable CIE and GIE interrupts */
257 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
258 SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
259 SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN);
260
be1b577d
ZY
261 /* program the position buffer */
262 if (bus->use_posbuf && bus->posbuf.addr) {
061edb23
ZY
263 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE,
264 (u32)bus->posbuf.addr);
265 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPUBASE,
266 upper_32_bits(bus->posbuf.addr));
be1b577d 267 }
be1b577d 268
1a7d06ae 269 hda_bus_ml_reset_losidv(bus);
d0697351 270
be1b577d
ZY
271 bus->chip_init = true;
272
aae5a6e9 273err:
8a300c8f 274 hda_dsp_ctrl_misc_clock_gating(sdev, true);
7e26df0c
KV
275#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
276 snd_hdac_set_codec_wakeup(bus, false);
277#endif
8a300c8f
LG
278
279 return ret;
280}
13063a2c
ZY
281
282void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
283{
284 struct hdac_bus *bus = sof_to_bus(sdev);
285 struct hdac_stream *stream;
286 int sd_offset;
287
288 if (!bus->chip_init)
289 return;
290
291 /* disable interrupts in stream descriptor */
292 list_for_each_entry(stream, &bus->stream_list, list) {
293 sd_offset = SOF_STREAM_SD_OFFSET(stream);
294 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
295 sd_offset +
38bf0780 296 SOF_HDA_ADSP_REG_SD_CTL,
13063a2c
ZY
297 SOF_HDA_CL_DMA_SD_INT_MASK,
298 0);
299 }
300
301 /* disable SIE for all streams */
302 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
303 SOF_HDA_INT_ALL_STREAM, 0);
304
305 /* disable controller CIE and GIE */
306 snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
307 SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
308 0);
309
310 /* clear stream status */
311 list_for_each_entry(stream, &bus->stream_list, list) {
312 sd_offset = SOF_STREAM_SD_OFFSET(stream);
3a39e0ea 313 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
38bf0780 314 sd_offset + SOF_HDA_ADSP_REG_SD_STS,
3a39e0ea 315 SOF_HDA_CL_DMA_SD_INT_MASK);
13063a2c
ZY
316 }
317
318 /* clear WAKESTS */
3a39e0ea
RS
319 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
320 SOF_HDA_WAKESTS_INT_MASK);
13063a2c
ZY
321
322#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
323 /* clear rirb status */
324 snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
325#endif
326
327 /* clear interrupt status register */
328 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
329 SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
330
331#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
332 /* disable CORB/RIRB */
333 snd_hdac_bus_stop_cmd_io(bus);
334#endif
335 /* disable position buffer */
12ce2138 336 if (bus->use_posbuf && bus->posbuf.addr) {
13063a2c
ZY
337 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
338 SOF_HDA_ADSP_DPLBASE, 0);
339 snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
340 SOF_HDA_ADSP_DPUBASE, 0);
341 }
342
343 bus->chip_init = false;
344}