Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
  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
 18#include <linux/module.h>
 19#include <sound/hdaudio_ext.h>
 20#include <sound/hda_register.h>
 21#include <sound/hda_component.h>
 22#include "../ops.h"
 23#include "hda.h"
 24
 25/*
 26 * HDA Operations.
 27 */
 28
 29int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset)
 30{
 31	unsigned long timeout;
 32	u32 gctl = 0;
 33	u32 val;
 34
 35	/* 0 to enter reset and 1 to exit reset */
 36	val = reset ? 0 : SOF_HDA_GCTL_RESET;
 37
 38	/* enter/exit HDA controller reset */
 39	snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL,
 40				SOF_HDA_GCTL_RESET, val);
 41
 42	/* wait to enter/exit reset */
 43	timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT);
 44	while (time_before(jiffies, timeout)) {
 45		gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL);
 46		if ((gctl & SOF_HDA_GCTL_RESET) == val)
 47			return 0;
 48		usleep_range(500, 1000);
 49	}
 50
 51	/* enter/exit reset failed */
 52	dev_err(sdev->dev, "error: failed to %s HDA controller gctl 0x%x\n",
 53		reset ? "reset" : "ready", gctl);
 54	return -EIO;
 55}
 56
 57int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev)
 58{
 59	struct hdac_bus *bus = sof_to_bus(sdev);
 60	u32 cap, offset, feature;
 61	int count = 0;
 62	int ret;
 63
 64	/*
 65	 * On some devices, one reset cycle is necessary before reading
 66	 * capabilities
 67	 */
 68	ret = hda_dsp_ctrl_link_reset(sdev, true);
 69	if (ret < 0)
 70		return ret;
 71	ret = hda_dsp_ctrl_link_reset(sdev, false);
 72	if (ret < 0)
 73		return ret;
 74
 75	offset = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_LLCH);
 76
 77	do {
 78		dev_dbg(sdev->dev, "checking for capabilities at offset 0x%x\n",
 79			offset & SOF_HDA_CAP_NEXT_MASK);
 80
 81		cap = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, offset);
 82
 83		if (cap == -1) {
 84			dev_dbg(bus->dev, "Invalid capability reg read\n");
 85			break;
 86		}
 87
 88		feature = (cap & SOF_HDA_CAP_ID_MASK) >> SOF_HDA_CAP_ID_OFF;
 89
 90		switch (feature) {
 91		case SOF_HDA_PP_CAP_ID:
 92			dev_dbg(sdev->dev, "found DSP capability at 0x%x\n",
 93				offset);
 94			bus->ppcap = bus->remap_addr + offset;
 95			sdev->bar[HDA_DSP_PP_BAR] = bus->ppcap;
 96			break;
 97		case SOF_HDA_SPIB_CAP_ID:
 98			dev_dbg(sdev->dev, "found SPIB capability at 0x%x\n",
 99				offset);
100			bus->spbcap = bus->remap_addr + offset;
101			sdev->bar[HDA_DSP_SPIB_BAR] = bus->spbcap;
102			break;
103		case SOF_HDA_DRSM_CAP_ID:
104			dev_dbg(sdev->dev, "found DRSM capability at 0x%x\n",
105				offset);
106			bus->drsmcap = bus->remap_addr + offset;
107			sdev->bar[HDA_DSP_DRSM_BAR] = bus->drsmcap;
108			break;
109		case SOF_HDA_GTS_CAP_ID:
110			dev_dbg(sdev->dev, "found GTS capability at 0x%x\n",
111				offset);
112			bus->gtscap = bus->remap_addr + offset;
113			break;
114		case SOF_HDA_ML_CAP_ID:
115			dev_dbg(sdev->dev, "found ML capability at 0x%x\n",
116				offset);
117			bus->mlcap = bus->remap_addr + offset;
118			break;
119		default:
120			dev_dbg(sdev->dev, "found capability %d at 0x%x\n",
121				feature, offset);
122			break;
123		}
124
125		offset = cap & SOF_HDA_CAP_NEXT_MASK;
126	} while (count++ <= SOF_HDA_MAX_CAPS && offset);
127
128	return 0;
129}
130
131void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable)
132{
133	u32 val = enable ? SOF_HDA_PPCTL_GPROCEN : 0;
134
135	snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
136				SOF_HDA_PPCTL_GPROCEN, val);
137}
138
139void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable)
140{
141	u32 val	= enable ? SOF_HDA_PPCTL_PIE : 0;
142
143	snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
144				SOF_HDA_PPCTL_PIE, val);
145}
146
147void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable)
148{
149	u32 val = enable ? PCI_CGCTL_MISCBDCGE_MASK : 0;
150
151	snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_MISCBDCGE_MASK, val);
152}
153
154/*
155 * enable/disable audio dsp clock gating and power gating bits.
156 * This allows the HW to opportunistically power and clock gate
157 * the audio dsp when it is idle
158 */
159int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
160{
161	u32 val;
162
163	/* enable/disable audio dsp clock gating */
164	val = enable ? PCI_CGCTL_ADSPDCGE : 0;
165	snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val);
166
167	/* enable/disable DMI Link L1 support */
168	val = enable ? HDA_VS_INTEL_EM2_L1SEN : 0;
169	snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_EM2,
170				HDA_VS_INTEL_EM2_L1SEN, val);
171
172	/* enable/disable audio dsp power gating */
173	val = enable ? 0 : PCI_PGCTL_ADSPPGD;
174	snd_sof_pci_update_bits(sdev, PCI_PGCTL, PCI_PGCTL_ADSPPGD, val);
175
176	return 0;
177}
178
179int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev)
180{
181	struct hdac_bus *bus = sof_to_bus(sdev);
182	struct hdac_stream *stream;
183	int sd_offset, ret = 0;
184
185	if (bus->chip_init)
186		return 0;
187
188	hda_codec_set_codec_wakeup(sdev, true);
189
190	hda_dsp_ctrl_misc_clock_gating(sdev, false);
191
192	/* reset HDA controller */
193	ret = hda_dsp_ctrl_link_reset(sdev, true);
194	if (ret < 0) {
195		dev_err(sdev->dev, "error: failed to reset HDA controller\n");
196		goto err;
197	}
198
199	/* exit HDA controller reset */
200	ret = hda_dsp_ctrl_link_reset(sdev, false);
201	if (ret < 0) {
202		dev_err(sdev->dev, "error: failed to exit HDA controller reset\n");
203		goto err;
204	}
205
206	hda_codec_detect_mask(sdev);
207
208	/* clear stream status */
209	list_for_each_entry(stream, &bus->stream_list, list) {
210		sd_offset = SOF_STREAM_SD_OFFSET(stream);
211		snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
212				  sd_offset + SOF_HDA_ADSP_REG_SD_STS,
213				  SOF_HDA_CL_DMA_SD_INT_MASK);
214	}
215
216	/* clear WAKESTS */
217	snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
218			  SOF_HDA_WAKESTS_INT_MASK);
219
220	hda_codec_rirb_status_clear(sdev);
221
222	/* clear interrupt status register */
223	snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
224			  SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
225
226	hda_codec_init_cmd_io(sdev);
227
228	/* enable CIE and GIE interrupts */
229	snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
230				SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
231				SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN);
232
233	/* program the position buffer */
234	if (bus->use_posbuf && bus->posbuf.addr) {
235		snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE,
236				  (u32)bus->posbuf.addr);
237		snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPUBASE,
238				  upper_32_bits(bus->posbuf.addr));
239	}
240
241	hda_bus_ml_reset_losidv(bus);
242
243	bus->chip_init = true;
244
245err:
246	hda_dsp_ctrl_misc_clock_gating(sdev, true);
247
248	hda_codec_set_codec_wakeup(sdev, false);
249
250	return ret;
251}
252
253void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
254{
255	struct hdac_bus *bus = sof_to_bus(sdev);
256	struct hdac_stream *stream;
257	int sd_offset;
258
259	if (!bus->chip_init)
260		return;
261
262	/* disable interrupts in stream descriptor */
263	list_for_each_entry(stream, &bus->stream_list, list) {
264		sd_offset = SOF_STREAM_SD_OFFSET(stream);
265		snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
266					sd_offset +
267					SOF_HDA_ADSP_REG_SD_CTL,
268					SOF_HDA_CL_DMA_SD_INT_MASK,
269					0);
270	}
271
272	/* disable SIE for all streams */
273	snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
274				SOF_HDA_INT_ALL_STREAM,	0);
275
276	/* disable controller CIE and GIE */
277	snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
278				SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN,
279				0);
280
281	/* clear stream status */
282	list_for_each_entry(stream, &bus->stream_list, list) {
283		sd_offset = SOF_STREAM_SD_OFFSET(stream);
284		snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
285				  sd_offset + SOF_HDA_ADSP_REG_SD_STS,
286				  SOF_HDA_CL_DMA_SD_INT_MASK);
287	}
288
289	/* clear WAKESTS */
290	snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS,
291			  SOF_HDA_WAKESTS_INT_MASK);
292
293	hda_codec_rirb_status_clear(sdev);
294
295	/* clear interrupt status register */
296	snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS,
297			  SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM);
298
299	hda_codec_stop_cmd_io(sdev);
300
301	/* disable position buffer */
302	if (bus->use_posbuf && bus->posbuf.addr) {
303		snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
304				  SOF_HDA_ADSP_DPLBASE, 0);
305		snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR,
306				  SOF_HDA_ADSP_DPUBASE, 0);
307	}
308
309	bus->chip_init = false;
310}