// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
// Copyright(c) 2018 Intel Corporation
//
// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
// Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
// Rander Wang <rander.wang@intel.com>
// Keyon Jie <yang.jie@linux.intel.com>
//
/*
* Hardware interface for generic Intel audio DSP HDA IP
*/
#include <sound/hdaudio_ext.h>
#include <sound/hda_register.h>
#include <sound/sof.h>
#include <trace/events/sof_intel.h>
#include "../ops.h"
#include "../sof-audio.h"
#include "../ipc4-priv.h"
#include "hda.h"
int sof_hda_position_quirk = SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS;
module_param_named(position_quirk, sof_hda_position_quirk, int, 0444);
MODULE_PARM_DESC(position_quirk, "SOF HDaudio position quirk");
EXPORT_SYMBOL_NS(sof_hda_position_quirk, "SND_SOC_SOF_INTEL_HDA_COMMON");
#define HDA_LTRP_GB_VALUE_US 95
static inline const char *hda_hstream_direction_str(struct hdac_stream *hstream)
{
if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK)
return "Playback";
else
return "Capture";
}
static char *hda_hstream_dbg_get_stream_info_str(struct hdac_stream *hstream)
{
struct snd_soc_pcm_runtime *rtd;
if (hstream->substream)
rtd = snd_soc_substream_to_rtd(hstream->substream);
else if (hstream->cstream)
rtd = hstream->cstream->private_data;
else
/* Non audio DMA user, like dma-trace */
return kasprintf(GFP_KERNEL, "-- (%s, stream_tag: %u)",
hda_hstream_direction_str(hstream),
hstream->stream_tag);
return kasprintf(GFP_KERNEL, "dai_link \"%s\" (%s, stream_tag: %u)",
rtd->dai_link->name, hda_hstream_direction_str(hstream),
hstream->stream_tag);
}
/*
* set up one of BDL entries for a stream
*/
static int hda_setup_bdle(struct snd_sof_dev *sdev,
struct snd_dma_buffer *dmab,
struct hdac_stream *hstream,
struct sof_intel_dsp_bdl **bdlp,
int offset, int size, int ioc)
{
struct hdac_bus *bus = sof_to_bus(sdev);
struct sof_intel_dsp_bdl *bdl = *bdlp;
while (size > 0) {
dma_addr_t addr;
int chunk;
if (hstream->frags >= HDA_DSP_MAX_BDL_ENTRIES) {
dev_err(sdev->dev, "error: stream frags exceeded\n");
return -EINVAL;
}
addr = snd_sgbuf_get_addr(dmab, offset);
/* program BDL addr */
bdl->addr_l = cpu_to_le32(lower_32_bits(addr));
bdl->addr_h = cpu_to_le32(upper_32_bits(addr));
/* program BDL size */
chunk = snd_sgbuf_get_chunk_size(dmab, offset, size);
/* one BDLE should not cross 4K boundary */
if (bus->align_bdle_4k) {
u32 remain = 0x1000 - (offset & 0xfff);
if (chunk > remain)
chunk = remain;
}
bdl->size = cpu_t