mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-03-16 04:04:06 +00:00
ASoC: Updates for v6.2
A few more updates for v6.2 which can hopefully go into a later pull request, the bulk of these are fixes, minor cleanups or new board quirks - the one big bit that isn't is support for getting diagnostic data out of the Intel AVS firmwares. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmOR9PIACgkQJNaLcl1U h9C3wAf9FkTPVSSljH3u0mHDWrFjz4h+MRW8bzNGFmTSU9IEQwk2vjfXcSod1D8o aDUhMVd1pGujc/1u6jk7virAG6IrT7mt0N6VHh4Qckxlj10EnAn/lVW0A/BWbtj3 j2j1AS1XxtYEdG0DQX7A4TAcdDysI1q66BEX3+kOlozAs8bn8Q1ZiEc2p2uaHKkY pPNdvYQnZyxng4sQb2l3MmHtRAt3gwG6QC3VwAsGX1PNwlHqQNd6U2Tg9MQKP9q0 rwcUeutXcJihE576y+H7jsBpkopsIpSAl8Wb/LQzgDBfScY0YITPw/wUGNIUhNk7 LMNuJBQAQ66EyNJH58K2DrmXsSXOjA== =lNJM -----END PGP SIGNATURE----- Merge tag 'asoc-v6.2-2' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next ASoC: Updates for v6.2 A few more updates for v6.2 which can hopefully go into a later pull request, the bulk of these are fixes, minor cleanups or new board quirks - the one big bit that isn't is support for getting diagnostic data out of the Intel AVS firmwares.
This commit is contained in:
commit
a587601b55
44 changed files with 1381 additions and 600 deletions
|
@ -38,6 +38,7 @@ properties:
|
|||
- fsl,imx8mq-sai
|
||||
- fsl,imx8qm-sai
|
||||
- fsl,imx8ulp-sai
|
||||
- fsl,imx93-sai
|
||||
- fsl,vf610-sai
|
||||
|
||||
reg:
|
||||
|
|
|
@ -75,6 +75,8 @@ struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
|
|||
struct snd_pcm_substream *substream,
|
||||
int type);
|
||||
void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type);
|
||||
struct hdac_ext_stream *snd_hdac_ext_cstream_assign(struct hdac_bus *bus,
|
||||
struct snd_compr_stream *cstream);
|
||||
void snd_hdac_ext_stream_decouple_locked(struct hdac_bus *bus,
|
||||
struct hdac_ext_stream *hext_stream, bool decouple);
|
||||
void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <sound/pcm.h>
|
||||
#include <sound/hda_register.h>
|
||||
#include <sound/hdaudio_ext.h>
|
||||
#include <sound/compress_driver.h>
|
||||
|
||||
/**
|
||||
* snd_hdac_ext_stream_init - initialize each stream (aka device)
|
||||
|
@ -367,3 +368,43 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *hext_stream, int type)
|
|||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release);
|
||||
|
||||
/**
|
||||
* snd_hdac_ext_cstream_assign - assign a host stream for compress
|
||||
* @bus: HD-audio core bus
|
||||
* @cstream: Compress stream to assign
|
||||
*
|
||||
* Assign an unused host stream for the given compress stream.
|
||||
* If no stream is free, NULL is returned. Stream is decoupled
|
||||
* before assignment.
|
||||
*/
|
||||
struct hdac_ext_stream *snd_hdac_ext_cstream_assign(struct hdac_bus *bus,
|
||||
struct snd_compr_stream *cstream)
|
||||
{
|
||||
struct hdac_ext_stream *res = NULL;
|
||||
struct hdac_stream *hstream;
|
||||
|
||||
spin_lock_irq(&bus->reg_lock);
|
||||
list_for_each_entry(hstream, &bus->stream_list, list) {
|
||||
struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
|
||||
|
||||
if (hstream->direction != cstream->direction)
|
||||
continue;
|
||||
|
||||
if (!hstream->opened) {
|
||||
res = hext_stream;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res) {
|
||||
snd_hdac_ext_stream_decouple_locked(bus, res, true);
|
||||
res->hstream.opened = 1;
|
||||
res->hstream.running = 0;
|
||||
res->hstream.cstream = cstream;
|
||||
}
|
||||
spin_unlock_irq(&bus->reg_lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_ext_cstream_assign);
|
||||
|
|
|
@ -578,8 +578,8 @@ int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
|
|||
sd_status = snd_hdac_stream_readb(azx_dev, SD_STS);
|
||||
snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK);
|
||||
handled |= 1 << azx_dev->index;
|
||||
if (!azx_dev->substream || !azx_dev->running ||
|
||||
!(sd_status & SD_INT_COMPLETE))
|
||||
if ((!azx_dev->substream && !azx_dev->cstream) ||
|
||||
!azx_dev->running || !(sd_status & SD_INT_COMPLETE))
|
||||
continue;
|
||||
if (ack)
|
||||
ack(bus, azx_dev);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <sound/compress_driver.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/hdaudio.h>
|
||||
|
@ -487,11 +488,20 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
|
|||
{
|
||||
struct hdac_bus *bus = azx_dev->bus;
|
||||
struct snd_pcm_substream *substream = azx_dev->substream;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct snd_compr_stream *cstream = azx_dev->cstream;
|
||||
struct snd_pcm_runtime *runtime = NULL;
|
||||
struct snd_dma_buffer *dmab;
|
||||
__le32 *bdl;
|
||||
int i, ofs, periods, period_bytes;
|
||||
int pos_adj, pos_align;
|
||||
|
||||
if (substream) {
|
||||
runtime = substream->runtime;
|
||||
dmab = snd_pcm_get_dma_buf(substream);
|
||||
} else if (cstream) {
|
||||
dmab = snd_pcm_get_dma_buf(cstream);
|
||||
}
|
||||
|
||||
/* reset BDL address */
|
||||
snd_hdac_stream_writel(azx_dev, SD_BDLPL, 0);
|
||||
snd_hdac_stream_writel(azx_dev, SD_BDLPU, 0);
|
||||
|
@ -505,7 +515,7 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
|
|||
azx_dev->frags = 0;
|
||||
|
||||
pos_adj = bus->bdl_pos_adj;
|
||||
if (!azx_dev->no_period_wakeup && pos_adj > 0) {
|
||||
if (runtime && !azx_dev->no_period_wakeup && pos_adj > 0) {
|
||||
pos_align = pos_adj;
|
||||
pos_adj = DIV_ROUND_UP(pos_adj * runtime->rate, 48000);
|
||||
if (!pos_adj)
|
||||
|
@ -518,8 +528,7 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
|
|||
pos_adj);
|
||||
pos_adj = 0;
|
||||
} else {
|
||||
ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream),
|
||||
azx_dev,
|
||||
ofs = setup_bdle(bus, dmab, azx_dev,
|
||||
&bdl, ofs, pos_adj, true);
|
||||
if (ofs < 0)
|
||||
goto error;
|
||||
|
@ -529,13 +538,11 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
|
|||
|
||||
for (i = 0; i < periods; i++) {
|
||||
if (i == periods - 1 && pos_adj)
|
||||
ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream),
|
||||
azx_dev, &bdl, ofs,
|
||||
period_bytes - pos_adj, 0);
|
||||
ofs = setup_bdle(bus, dmab, azx_dev,
|
||||
&bdl, ofs, period_bytes - pos_adj, 0);
|
||||
else
|
||||
ofs = setup_bdle(bus, snd_pcm_get_dma_buf(substream),
|
||||
azx_dev, &bdl, ofs,
|
||||
period_bytes,
|
||||
ofs = setup_bdle(bus, dmab, azx_dev,
|
||||
&bdl, ofs, period_bytes,
|
||||
!azx_dev->no_period_wakeup);
|
||||
if (ofs < 0)
|
||||
goto error;
|
||||
|
@ -560,26 +567,32 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_setup_periods);
|
|||
int snd_hdac_stream_set_params(struct hdac_stream *azx_dev,
|
||||
unsigned int format_val)
|
||||
{
|
||||
|
||||
unsigned int bufsize, period_bytes;
|
||||
struct snd_pcm_substream *substream = azx_dev->substream;
|
||||
struct snd_pcm_runtime *runtime;
|
||||
struct snd_compr_stream *cstream = azx_dev->cstream;
|
||||
unsigned int bufsize, period_bytes;
|
||||
unsigned int no_period_wakeup;
|
||||
int err;
|
||||
|
||||
if (!substream)
|
||||
if (substream) {
|
||||
bufsize = snd_pcm_lib_buffer_bytes(substream);
|
||||
period_bytes = snd_pcm_lib_period_bytes(substream);
|
||||
no_period_wakeup = substream->runtime->no_period_wakeup;
|
||||
} else if (cstream) {
|
||||
bufsize = cstream->runtime->buffer_size;
|
||||
period_bytes = cstream->runtime->fragment_size;
|
||||
no_period_wakeup = 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
runtime = substream->runtime;
|
||||
bufsize = snd_pcm_lib_buffer_bytes(substream);
|
||||
period_bytes = snd_pcm_lib_period_bytes(substream);
|
||||
}
|
||||
|
||||
if (bufsize != azx_dev->bufsize ||
|
||||
period_bytes != azx_dev->period_bytes ||
|
||||
format_val != azx_dev->format_val ||
|
||||
runtime->no_period_wakeup != azx_dev->no_period_wakeup) {
|
||||
no_period_wakeup != azx_dev->no_period_wakeup) {
|
||||
azx_dev->bufsize = bufsize;
|
||||
azx_dev->period_bytes = period_bytes;
|
||||
azx_dev->format_val = format_val;
|
||||
azx_dev->no_period_wakeup = runtime->no_period_wakeup;
|
||||
azx_dev->no_period_wakeup = no_period_wakeup;
|
||||
err = snd_hdac_stream_setup_periods(azx_dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
|
|
@ -130,12 +130,6 @@ static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl,
|
|||
ctrl->clsh_users = 0;
|
||||
}
|
||||
|
||||
static inline bool wcd_clsh_enable_status(struct snd_soc_component *comp)
|
||||
{
|
||||
return snd_soc_component_read(comp, WCD9XXX_A_CDC_CLSH_CRC) &
|
||||
WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK;
|
||||
}
|
||||
|
||||
static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp,
|
||||
int mode)
|
||||
{
|
||||
|
|
|
@ -75,8 +75,7 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
|
|||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = scnprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n",
|
||||
pdcr, ptcr);
|
||||
ret = sysfs_emit(buf, "PDCR: %08x\nPTCR: %08x\n", pdcr, ptcr);
|
||||
|
||||
if (ptcr & IMX_AUDMUX_V2_PTCR_TFSDIR)
|
||||
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
|
||||
|
|
|
@ -485,8 +485,10 @@ static int __graph_for_each_link(struct asoc_simple_priv *priv,
|
|||
of_node_put(codec_ep);
|
||||
of_node_put(codec_port);
|
||||
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
of_node_put(cpu_ep);
|
||||
return ret;
|
||||
}
|
||||
|
||||
codec_port_old = codec_port;
|
||||
}
|
||||
|
|
|
@ -217,6 +217,7 @@ config SND_SOC_INTEL_AVS
|
|||
select SND_SOC_ACPI if ACPI
|
||||
select SND_SOC_TOPOLOGY
|
||||
select SND_SOC_HDA
|
||||
select SND_SOC_COMPRESS if DEBUG_FS
|
||||
select SND_HDA_EXT_CORE
|
||||
select SND_HDA_DSP_LOADER
|
||||
select SND_INTEL_DSP_CONFIG
|
||||
|
|
|
@ -9,6 +9,10 @@ snd-soc-avs-objs += trace.o
|
|||
# tell define_trace.h where to find the trace header
|
||||
CFLAGS_trace.o := -I$(src)
|
||||
|
||||
ifneq ($(CONFIG_DEBUG_FS),)
|
||||
snd-soc-avs-objs += probes.o debugfs.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o
|
||||
|
||||
# Machine support
|
||||
|
|
|
@ -13,8 +13,9 @@
|
|||
#include "path.h"
|
||||
#include "topology.h"
|
||||
|
||||
static int apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
|
||||
u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
|
||||
static int __maybe_unused
|
||||
apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
|
||||
u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
|
||||
{
|
||||
struct apl_log_state_info *info;
|
||||
u32 size, num_cores = adev->hw_cfg.dsp_cores;
|
||||
|
@ -50,7 +51,6 @@ static int apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32
|
|||
static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
|
||||
{
|
||||
struct apl_log_buffer_layout layout;
|
||||
unsigned long flags;
|
||||
void __iomem *addr, *buf;
|
||||
|
||||
addr = avs_log_buffer_addr(adev, msg->log.core);
|
||||
|
@ -59,26 +59,20 @@ static int apl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg
|
|||
|
||||
memcpy_fromio(&layout, addr, sizeof(layout));
|
||||
|
||||
spin_lock_irqsave(&adev->dbg.trace_lock, flags);
|
||||
if (!kfifo_initialized(&adev->dbg.trace_fifo))
|
||||
if (!avs_logging_fw(adev))
|
||||
/* consume the logs regardless of consumer presence */
|
||||
goto update_read_ptr;
|
||||
|
||||
buf = apl_log_payload_addr(addr);
|
||||
|
||||
if (layout.read_ptr > layout.write_ptr) {
|
||||
__kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr,
|
||||
apl_log_payload_size(adev) - layout.read_ptr,
|
||||
&adev->dbg.fifo_lock);
|
||||
avs_dump_fw_log(adev, buf + layout.read_ptr,
|
||||
apl_log_payload_size(adev) - layout.read_ptr);
|
||||
layout.read_ptr = 0;
|
||||
}
|
||||
__kfifo_fromio_locked(&adev->dbg.trace_fifo, buf + layout.read_ptr,
|
||||
layout.write_ptr - layout.read_ptr, &adev->dbg.fifo_lock);
|
||||
|
||||
wake_up(&adev->dbg.trace_waitq);
|
||||
avs_dump_fw_log_wakeup(adev, buf + layout.read_ptr, layout.write_ptr - layout.read_ptr);
|
||||
|
||||
update_read_ptr:
|
||||
spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
|
||||
writel(layout.write_ptr, addr);
|
||||
return 0;
|
||||
}
|
||||
|
@ -140,7 +134,7 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
|
|||
* gathered before dumping stack
|
||||
*/
|
||||
lbs_msg.log.core = msg->ext.coredump.core_id;
|
||||
avs_dsp_op(adev, log_buffer_status, &lbs_msg);
|
||||
avs_log_buffer_status_locked(adev, &lbs_msg);
|
||||
}
|
||||
|
||||
pos = dump + AVS_FW_REGS_SIZE;
|
||||
|
@ -243,10 +237,10 @@ const struct avs_dsp_ops apl_dsp_ops = {
|
|||
.load_basefw = avs_hda_load_basefw,
|
||||
.load_lib = avs_hda_load_library,
|
||||
.transfer_mods = avs_hda_transfer_modules,
|
||||
.enable_logs = apl_enable_logs,
|
||||
.log_buffer_offset = skl_log_buffer_offset,
|
||||
.log_buffer_status = apl_log_buffer_status,
|
||||
.coredump = apl_coredump,
|
||||
.d0ix_toggle = apl_d0ix_toggle,
|
||||
.set_d0ix = apl_set_d0ix,
|
||||
AVS_SET_ENABLE_LOGS_OP(apl)
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef __SOUND_SOC_INTEL_AVS_H
|
||||
#define __SOUND_SOC_INTEL_AVS_H
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
@ -93,16 +94,6 @@ struct avs_fw_entry {
|
|||
struct list_head node;
|
||||
};
|
||||
|
||||
struct avs_debug {
|
||||
struct kfifo trace_fifo;
|
||||
spinlock_t fifo_lock; /* serialize I/O for trace_fifo */
|
||||
spinlock_t trace_lock; /* serialize debug window I/O between each LOG_BUFFER_STATUS */
|
||||
wait_queue_head_t trace_waitq;
|
||||
u32 aging_timer_period;
|
||||
u32 fifo_full_timer_period;
|
||||
u32 logged_resources; /* context dependent: core or library */
|
||||
};
|
||||
|
||||
/*
|
||||
* struct avs_dev - Intel HD-Audio driver data
|
||||
*
|
||||
|
@ -146,7 +137,18 @@ struct avs_dev {
|
|||
spinlock_t path_list_lock;
|
||||
struct mutex path_mutex;
|
||||
|
||||
struct avs_debug dbg;
|
||||
spinlock_t trace_lock; /* serialize debug window I/O between each LOG_BUFFER_STATUS */
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct kfifo trace_fifo;
|
||||
wait_queue_head_t trace_waitq;
|
||||
u32 aging_timer_period;
|
||||
u32 fifo_full_timer_period;
|
||||
u32 logged_resources; /* context dependent: core or library */
|
||||
struct dentry *debugfs_root;
|
||||
/* probes */
|
||||
struct hdac_ext_stream *extractor;
|
||||
unsigned int num_probe_streams;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* from hda_bus to avs_dev */
|
||||
|
@ -321,6 +323,9 @@ struct avs_soc_component {
|
|||
|
||||
extern const struct snd_soc_dai_ops avs_dai_fe_ops;
|
||||
|
||||
int avs_soc_component_register(struct device *dev, const char *name,
|
||||
const struct snd_soc_component_driver *drv,
|
||||
struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais);
|
||||
int avs_dmic_platform_register(struct avs_dev *adev, const char *name);
|
||||
int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask,
|
||||
unsigned long *tdms);
|
||||
|
@ -331,9 +336,6 @@ void avs_unregister_all_boards(struct avs_dev *adev);
|
|||
|
||||
/* Firmware tracing helpers */
|
||||
|
||||
unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len,
|
||||
spinlock_t *lock);
|
||||
|
||||
#define avs_log_buffer_size(adev) \
|
||||
((adev)->fw_cfg.trace_log_bytes / (adev)->hw_cfg.dsp_cores)
|
||||
|
||||
|
@ -344,6 +346,18 @@ unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src,
|
|||
(avs_sram_addr(adev, AVS_DEBUG_WINDOW) + __offset); \
|
||||
})
|
||||
|
||||
static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&adev->trace_lock, flags);
|
||||
ret = avs_dsp_op(adev, log_buffer_status, msg);
|
||||
spin_unlock_irqrestore(&adev->trace_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct apl_log_buffer_layout {
|
||||
u32 read_ptr;
|
||||
u32 write_ptr;
|
||||
|
@ -356,4 +370,42 @@ struct apl_log_buffer_layout {
|
|||
#define apl_log_payload_addr(addr) \
|
||||
(addr + sizeof(struct apl_log_buffer_layout))
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
#define AVS_SET_ENABLE_LOGS_OP(name) \
|
||||
.enable_logs = name##_enable_logs
|
||||
|
||||
bool avs_logging_fw(struct avs_dev *adev);
|
||||
void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len);
|
||||
void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len);
|
||||
|
||||
int avs_probe_platform_register(struct avs_dev *adev, const char *name);
|
||||
|
||||
void avs_debugfs_init(struct avs_dev *adev);
|
||||
void avs_debugfs_exit(struct avs_dev *adev);
|
||||
#else
|
||||
#define AVS_SET_ENABLE_LOGS_OP(name)
|
||||
|
||||
static inline bool avs_logging_fw(struct avs_dev *adev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void
|
||||
avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int avs_probe_platform_register(struct avs_dev *adev, const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void avs_debugfs_init(struct avs_dev *adev) { }
|
||||
static inline void avs_debugfs_exit(struct avs_dev *adev) { }
|
||||
#endif
|
||||
|
||||
#endif /* __SOUND_SOC_INTEL_AVS_H */
|
||||
|
|
|
@ -291,6 +291,33 @@ static void board_pdev_unregister(void *data)
|
|||
platform_device_unregister(data);
|
||||
}
|
||||
|
||||
static int __maybe_unused avs_register_probe_board(struct avs_dev *adev)
|
||||
{
|
||||
struct platform_device *board;
|
||||
struct snd_soc_acpi_mach mach = {{0}};
|
||||
int ret;
|
||||
|
||||
ret = avs_probe_platform_register(adev, "probe-platform");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mach.mach_params.platform = "probe-platform";
|
||||
|
||||
board = platform_device_register_data(NULL, "avs_probe_mb", PLATFORM_DEVID_NONE,
|
||||
(const void *)&mach, sizeof(mach));
|
||||
if (IS_ERR(board)) {
|
||||
dev_err(adev->dev, "probe board register failed\n");
|
||||
return PTR_ERR(board);
|
||||
}
|
||||
|
||||
ret = devm_add_action(adev->dev, board_pdev_unregister, board);
|
||||
if (ret < 0) {
|
||||
platform_device_unregister(board);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int avs_register_dmic_board(struct avs_dev *adev)
|
||||
{
|
||||
struct platform_device *codec, *board;
|
||||
|
@ -500,6 +527,12 @@ int avs_register_all_boards(struct avs_dev *adev)
|
|||
{
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
ret = avs_register_probe_board(adev);
|
||||
if (ret < 0)
|
||||
dev_warn(adev->dev, "enumerate PROBE endpoints failed: %d\n", ret);
|
||||
#endif
|
||||
|
||||
ret = avs_register_dmic_board(adev);
|
||||
if (ret < 0)
|
||||
dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",
|
||||
|
|
|
@ -77,6 +77,14 @@ config SND_SOC_INTEL_AVS_MACH_NAU8825
|
|||
Say Y or m if you have such a device. This is a recommended option.
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_INTEL_AVS_MACH_PROBE
|
||||
tristate "Probing (data) board"
|
||||
depends on DEBUG_FS
|
||||
select SND_HWDEP
|
||||
help
|
||||
This adds support for data probing board which can be used to
|
||||
gather data from runtime stream over compress operations.
|
||||
|
||||
config SND_SOC_INTEL_AVS_MACH_RT274
|
||||
tristate "rt274 in I2S mode"
|
||||
depends on I2C
|
||||
|
|
|
@ -8,6 +8,7 @@ snd-soc-avs-max98927-objs := max98927.o
|
|||
snd-soc-avs-max98357a-objs := max98357a.o
|
||||
snd-soc-avs-max98373-objs := max98373.o
|
||||
snd-soc-avs-nau8825-objs := nau8825.o
|
||||
snd-soc-avs-probe-objs := probe.o
|
||||
snd-soc-avs-rt274-objs := rt274.o
|
||||
snd-soc-avs-rt286-objs := rt286.o
|
||||
snd-soc-avs-rt298-objs := rt298.o
|
||||
|
@ -22,6 +23,7 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927) += snd-soc-avs-max98927.o
|
|||
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PROBE) += snd-soc-avs-probe.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT298) += snd-soc-avs-rt298.o
|
||||
|
|
64
sound/soc/intel/avs/boards/probe.c
Normal file
64
sound/soc/intel/avs/boards/probe.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
|
||||
//
|
||||
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
|
||||
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
|
||||
//
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-acpi.h>
|
||||
|
||||
SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
|
||||
SND_SOC_DAILINK_DEF(probe_cp, DAILINK_COMP_ARRAY(COMP_CPU("Probe Extraction CPU DAI")));
|
||||
SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("probe-platform")));
|
||||
|
||||
static struct snd_soc_dai_link probe_mb_dai_links[] = {
|
||||
{
|
||||
.name = "Compress Probe Capture",
|
||||
.nonatomic = 1,
|
||||
SND_SOC_DAILINK_REG(probe_cp, dummy, platform),
|
||||
},
|
||||
};
|
||||
|
||||
static int avs_probe_mb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct snd_soc_acpi_mach *mach;
|
||||
struct snd_soc_card *card;
|
||||
int ret;
|
||||
|
||||
mach = dev_get_platdata(dev);
|
||||
|
||||
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
|
||||
if (!card)
|
||||
return -ENOMEM;
|
||||
|
||||
card->name = "avs_probe_mb";
|
||||
card->dev = dev;
|
||||
card->owner = THIS_MODULE;
|
||||
card->dai_link = probe_mb_dai_links;
|
||||
card->num_links = ARRAY_SIZE(probe_mb_dai_links);
|
||||
card->fully_routed = true;
|
||||
|
||||
ret = snd_soc_fixup_dai_links_platform_name(card, mach->mach_params.platform);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_snd_soc_register_card(dev, card);
|
||||
}
|
||||
|
||||
static struct platform_driver avs_probe_mb_driver = {
|
||||
.probe = avs_probe_mb_probe,
|
||||
.driver = {
|
||||
.name = "avs_probe_mb",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(avs_probe_mb_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:avs_probe_mb");
|
|
@ -214,6 +214,7 @@ static void avs_hda_probe_work(struct work_struct *work)
|
|||
adev->nhlt = intel_nhlt_init(adev->dev);
|
||||
if (!adev->nhlt)
|
||||
dev_info(bus->dev, "platform has no NHLT\n");
|
||||
avs_debugfs_init(adev);
|
||||
|
||||
avs_register_all_boards(adev);
|
||||
|
||||
|
@ -491,6 +492,7 @@ static void avs_pci_remove(struct pci_dev *pci)
|
|||
|
||||
avs_unregister_all_boards(adev);
|
||||
|
||||
avs_debugfs_exit(adev);
|
||||
if (adev->nhlt)
|
||||
intel_nhlt_free(adev->nhlt);
|
||||
|
||||
|
|
436
sound/soc/intel/avs/debugfs.c
Normal file
436
sound/soc/intel/avs/debugfs.c
Normal file
|
@ -0,0 +1,436 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
|
||||
//
|
||||
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
|
||||
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
|
||||
//
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <sound/soc.h>
|
||||
#include "avs.h"
|
||||
#include "messages.h"
|
||||
|
||||
static unsigned int __kfifo_fromio(struct kfifo *fifo, const void __iomem *src, unsigned int len)
|
||||
{
|
||||
struct __kfifo *__fifo = &fifo->kfifo;
|
||||
unsigned int l, off;
|
||||
|
||||
len = min(len, kfifo_avail(fifo));
|
||||
off = __fifo->in & __fifo->mask;
|
||||
l = min(len, kfifo_size(fifo) - off);
|
||||
|
||||
memcpy_fromio(__fifo->data + off, src, l);
|
||||
memcpy_fromio(__fifo->data, src + l, len - l);
|
||||
/* Make sure data copied from SRAM is visible to all CPUs. */
|
||||
smp_mb();
|
||||
__fifo->in += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
bool avs_logging_fw(struct avs_dev *adev)
|
||||
{
|
||||
return kfifo_initialized(&adev->trace_fifo);
|
||||
}
|
||||
|
||||
void avs_dump_fw_log(struct avs_dev *adev, const void __iomem *src, unsigned int len)
|
||||
{
|
||||
__kfifo_fromio(&adev->trace_fifo, src, len);
|
||||
}
|
||||
|
||||
void avs_dump_fw_log_wakeup(struct avs_dev *adev, const void __iomem *src, unsigned int len)
|
||||
{
|
||||
avs_dump_fw_log(adev, src, len);
|
||||
wake_up(&adev->trace_waitq);
|
||||
}
|
||||
|
||||
static ssize_t fw_regs_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct avs_dev *adev = file->private_data;
|
||||
char *buf;
|
||||
int ret;
|
||||
|
||||
buf = kzalloc(AVS_FW_REGS_SIZE, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy_fromio(buf, avs_sram_addr(adev, AVS_FW_REGS_WINDOW), AVS_FW_REGS_SIZE);
|
||||
|
||||
ret = simple_read_from_buffer(to, count, ppos, buf, AVS_FW_REGS_SIZE);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fw_regs_fops = {
|
||||
.open = simple_open,
|
||||
.read = fw_regs_read,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
||||
static ssize_t debug_window_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct avs_dev *adev = file->private_data;
|
||||
size_t size;
|
||||
char *buf;
|
||||
int ret;
|
||||
|
||||
size = adev->hw_cfg.dsp_cores * AVS_WINDOW_CHUNK_SIZE;
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy_fromio(buf, avs_sram_addr(adev, AVS_DEBUG_WINDOW), size);
|
||||
|
||||
ret = simple_read_from_buffer(to, count, ppos, buf, size);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations debug_window_fops = {
|
||||
.open = simple_open,
|
||||
.read = debug_window_read,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
||||
static ssize_t probe_points_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct avs_dev *adev = file->private_data;
|
||||
struct avs_probe_point_desc *desc;
|
||||
size_t num_desc, len = 0;
|
||||
char *buf;
|
||||
int i, ret;
|
||||
|
||||
/* Prevent chaining, send and dump IPC value just once. */
|
||||
if (*ppos)
|
||||
return 0;
|
||||
|
||||
buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = avs_ipc_probe_get_points(adev, &desc, &num_desc);
|
||||
if (ret) {
|
||||
ret = AVS_IPC_RET(ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_desc; i++) {
|
||||
ret = snprintf(buf + len, PAGE_SIZE - len,
|
||||
"Id: %#010x Purpose: %d Node id: %#x\n",
|
||||
desc[i].id.value, desc[i].purpose, desc[i].node_id.val);
|
||||
if (ret < 0)
|
||||
goto free_desc;
|
||||
len += ret;
|
||||
}
|
||||
|
||||
ret = simple_read_from_buffer(to, count, ppos, buf, len);
|
||||
free_desc:
|
||||
kfree(desc);
|
||||
exit:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t probe_points_write(struct file *file, const char __user *from, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct avs_dev *adev = file->private_data;
|
||||
struct avs_probe_point_desc *desc;
|
||||
u32 *array, num_elems;
|
||||
size_t bytes;
|
||||
int ret;
|
||||
|
||||
ret = parse_int_array_user(from, count, (int **)&array);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
num_elems = *array;
|
||||
bytes = sizeof(*array) * num_elems;
|
||||
if (bytes % sizeof(*desc)) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
desc = (struct avs_probe_point_desc *)&array[1];
|
||||
ret = avs_ipc_probe_connect_points(adev, desc, bytes / sizeof(*desc));
|
||||
if (ret)
|
||||
ret = AVS_IPC_RET(ret);
|
||||
else
|
||||
ret = count;
|
||||
exit:
|
||||
kfree(array);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations probe_points_fops = {
|
||||
.open = simple_open,
|
||||
.read = probe_points_read,
|
||||
.write = probe_points_write,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
||||
static ssize_t probe_points_disconnect_write(struct file *file, const char __user *from,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct avs_dev *adev = file->private_data;
|
||||
union avs_probe_point_id *id;
|
||||
u32 *array, num_elems;
|
||||
size_t bytes;
|
||||
int ret;
|
||||
|
||||
ret = parse_int_array_user(from, count, (int **)&array);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
num_elems = *array;
|
||||
bytes = sizeof(*array) * num_elems;
|
||||
if (bytes % sizeof(*id)) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
id = (union avs_probe_point_id *)&array[1];
|
||||
ret = avs_ipc_probe_disconnect_points(adev, id, bytes / sizeof(*id));
|
||||
if (ret)
|
||||
ret = AVS_IPC_RET(ret);
|
||||
else
|
||||
ret = count;
|
||||
exit:
|
||||
kfree(array);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations probe_points_disconnect_fops = {
|
||||
.open = simple_open,
|
||||
.write = probe_points_disconnect_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t strace_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct avs_dev *adev = file->private_data;
|
||||
struct kfifo *fifo = &adev->trace_fifo;
|
||||
unsigned int copied;
|
||||
|
||||
if (kfifo_is_empty(fifo)) {
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
prepare_to_wait(&adev->trace_waitq, &wait, TASK_INTERRUPTIBLE);
|
||||
if (!signal_pending(current))
|
||||
schedule();
|
||||
finish_wait(&adev->trace_waitq, &wait);
|
||||
}
|
||||
|
||||
if (kfifo_to_user(fifo, to, count, &copied))
|
||||
return -EFAULT;
|
||||
*ppos += copied;
|
||||
return copied;
|
||||
}
|
||||
|
||||
static int strace_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct avs_dev *adev = inode->i_private;
|
||||
int ret;
|
||||
|
||||
if (kfifo_initialized(&adev->trace_fifo))
|
||||
return -EBUSY;
|
||||
|
||||
ret = kfifo_alloc(&adev->trace_fifo, PAGE_SIZE, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
file->private_data = adev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int strace_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
union avs_notify_msg msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS);
|
||||
struct avs_dev *adev = file->private_data;
|
||||
unsigned long resource_mask;
|
||||
unsigned long flags, i;
|
||||
u32 num_cores;
|
||||
|
||||
resource_mask = adev->logged_resources;
|
||||
num_cores = adev->hw_cfg.dsp_cores;
|
||||
|
||||
spin_lock_irqsave(&adev->trace_lock, flags);
|
||||
|
||||
/* Gather any remaining logs. */
|
||||
for_each_set_bit(i, &resource_mask, num_cores) {
|
||||
msg.log.core = i;
|
||||
avs_dsp_op(adev, log_buffer_status, &msg);
|
||||
}
|
||||
|
||||
kfifo_free(&adev->trace_fifo);
|
||||
|
||||
spin_unlock_irqrestore(&adev->trace_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations strace_fops = {
|
||||
.llseek = default_llseek,
|
||||
.read = strace_read,
|
||||
.open = strace_open,
|
||||
.release = strace_release,
|
||||
};
|
||||
|
||||
#define DISABLE_TIMERS UINT_MAX
|
||||
|
||||
static int enable_logs(struct avs_dev *adev, u32 resource_mask, u32 *priorities)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Logging demands D0i0 state from DSP. */
|
||||
if (!adev->logged_resources) {
|
||||
pm_runtime_get_sync(adev->dev);
|
||||
|
||||
ret = avs_dsp_disable_d0ix(adev);
|
||||
if (ret)
|
||||
goto err_d0ix;
|
||||
}
|
||||
|
||||
ret = avs_ipc_set_system_time(adev);
|
||||
if (ret && ret != AVS_IPC_NOT_SUPPORTED) {
|
||||
ret = AVS_IPC_RET(ret);
|
||||
goto err_ipc;
|
||||
}
|
||||
|
||||
ret = avs_dsp_op(adev, enable_logs, AVS_LOG_ENABLE, adev->aging_timer_period,
|
||||
adev->fifo_full_timer_period, resource_mask, priorities);
|
||||
if (ret)
|
||||
goto err_ipc;
|
||||
|
||||
adev->logged_resources |= resource_mask;
|
||||
return 0;
|
||||
|
||||
err_ipc:
|
||||
if (!adev->logged_resources) {
|
||||
avs_dsp_enable_d0ix(adev);
|
||||
err_d0ix:
|
||||
pm_runtime_mark_last_busy(adev->dev);
|
||||
pm_runtime_put_autosuspend(adev->dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int disable_logs(struct avs_dev *adev, u32 resource_mask)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Check if there's anything to do. */
|
||||
if (!adev->logged_resources)
|
||||
return 0;
|
||||
|
||||
ret = avs_dsp_op(adev, enable_logs, AVS_LOG_DISABLE, DISABLE_TIMERS, DISABLE_TIMERS,
|
||||
resource_mask, NULL);
|
||||
|
||||
/*
|
||||
* If IPC fails causing recovery, logged_resources is already zero
|
||||
* so unsetting bits is still safe.
|
||||
*/
|
||||
adev->logged_resources &= ~resource_mask;
|
||||
|
||||
/* If that's the last resource, allow for D3. */
|
||||
if (!adev->logged_resources) {
|
||||
avs_dsp_enable_d0ix(adev);
|
||||
pm_runtime_mark_last_busy(adev->dev);
|
||||
pm_runtime_put_autosuspend(adev->dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t trace_control_read(struct file *file, char __user *to, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct avs_dev *adev = file->private_data;
|
||||
char buf[64];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "0x%08x\n", adev->logged_resources);
|
||||
|
||||
return simple_read_from_buffer(to, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static ssize_t trace_control_write(struct file *file, const char __user *from, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct avs_dev *adev = file->private_data;
|
||||
u32 *array, num_elems;
|
||||
u32 resource_mask;
|
||||
int ret;
|
||||
|
||||
ret = parse_int_array_user(from, count, (int **)&array);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
num_elems = *array;
|
||||
resource_mask = array[1];
|
||||
|
||||
/*
|
||||
* Disable if just resource mask is provided - no log priority flags.
|
||||
*
|
||||
* Enable input format: mask, prio1, .., prioN
|
||||
* Where 'N' equals number of bits set in the 'mask'.
|
||||
*/
|
||||
if (num_elems == 1) {
|
||||
ret = disable_logs(adev, resource_mask);
|
||||
} else {
|
||||
if (num_elems != (hweight_long(resource_mask) + 1)) {
|
||||
ret = -EINVAL;
|
||||
goto free_array;
|
||||
}
|
||||
|
||||
ret = enable_logs(adev, resource_mask, &array[2]);
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
ret = count;
|
||||
free_array:
|
||||
kfree(array);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations trace_control_fops = {
|
||||
.llseek = default_llseek,
|
||||
.read = trace_control_read,
|
||||
.write = trace_control_write,
|
||||
.open = simple_open,
|
||||
};
|
||||
|
||||
void avs_debugfs_init(struct avs_dev *adev)
|
||||
{
|
||||
init_waitqueue_head(&adev->trace_waitq);
|
||||
spin_lock_init(&adev->trace_lock);
|
||||
|
||||
adev->debugfs_root = debugfs_create_dir("avs", snd_soc_debugfs_root);
|
||||
|
||||
/* Initialize timer periods with recommended defaults. */
|
||||
adev->aging_timer_period = 10;
|
||||
adev->fifo_full_timer_period = 10;
|
||||
|
||||
debugfs_create_file("strace", 0444, adev->debugfs_root, adev, &strace_fops);
|
||||
debugfs_create_file("trace_control", 0644, adev->debugfs_root, adev, &trace_control_fops);
|
||||
debugfs_create_file("fw_regs", 0444, adev->debugfs_root, adev, &fw_regs_fops);
|
||||
debugfs_create_file("debug_window", 0444, adev->debugfs_root, adev, &debug_window_fops);
|
||||
|
||||
debugfs_create_u32("trace_aging_period", 0644, adev->debugfs_root,
|
||||
&adev->aging_timer_period);
|
||||
debugfs_create_u32("trace_fifo_full_period", 0644, adev->debugfs_root,
|
||||
&adev->fifo_full_timer_period);
|
||||
|
||||
debugfs_create_file("probe_points", 0644, adev->debugfs_root, adev, &probe_points_fops);
|
||||
debugfs_create_file("probe_points_disconnect", 0200, adev->debugfs_root, adev,
|
||||
&probe_points_disconnect_fops);
|
||||
}
|
||||
|
||||
void avs_debugfs_exit(struct avs_dev *adev)
|
||||
{
|
||||
debugfs_remove_recursive(adev->debugfs_root);
|
||||
}
|
|
@ -266,7 +266,7 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
|
|||
break;
|
||||
|
||||
case AVS_NOTIFY_LOG_BUFFER_STATUS:
|
||||
avs_dsp_op(adev, log_buffer_status, &msg);
|
||||
avs_log_buffer_status_locked(adev, &msg);
|
||||
break;
|
||||
|
||||
case AVS_NOTIFY_EXCEPTION_CAUGHT:
|
||||
|
|
|
@ -685,6 +685,24 @@ int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
|
||||
u8 instance_id, u32 sink_id,
|
||||
const struct avs_audio_format *src_fmt,
|
||||
const struct avs_audio_format *sink_fmt)
|
||||
{
|
||||
struct avs_copier_sink_format cpr_fmt;
|
||||
|
||||
cpr_fmt.sink_id = sink_id;
|
||||
/* Firmware expects driver to resend copier's input format. */
|
||||
cpr_fmt.src_fmt = *src_fmt;
|
||||
cpr_fmt.sink_fmt = *sink_fmt;
|
||||
|
||||
return avs_ipc_set_large_config(adev, module_id, instance_id,
|
||||
AVS_COPIER_SET_SINK_FORMAT,
|
||||
(u8 *)&cpr_fmt, sizeof(cpr_fmt));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size)
|
||||
{
|
||||
return avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
|
||||
|
@ -705,19 +723,81 @@ int avs_ipc_set_system_time(struct avs_dev *adev)
|
|||
AVS_BASEFW_SYSTEM_TIME, (u8 *)&sys_time, sizeof(sys_time));
|
||||
}
|
||||
|
||||
int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
|
||||
u8 instance_id, u32 sink_id,
|
||||
const struct avs_audio_format *src_fmt,
|
||||
const struct avs_audio_format *sink_fmt)
|
||||
int avs_ipc_probe_get_dma(struct avs_dev *adev, struct avs_probe_dma **dmas, size_t *num_dmas)
|
||||
{
|
||||
struct avs_copier_sink_format cpr_fmt;
|
||||
size_t payload_size;
|
||||
u32 module_id;
|
||||
u8 *payload;
|
||||
int ret;
|
||||
|
||||
cpr_fmt.sink_id = sink_id;
|
||||
/* Firmware expects driver to resend copier's input format. */
|
||||
cpr_fmt.src_fmt = *src_fmt;
|
||||
cpr_fmt.sink_fmt = *sink_fmt;
|
||||
module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
|
||||
|
||||
return avs_ipc_set_large_config(adev, module_id, instance_id,
|
||||
AVS_COPIER_SET_SINK_FORMAT,
|
||||
(u8 *)&cpr_fmt, sizeof(cpr_fmt));
|
||||
ret = avs_ipc_get_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_INJECTION_DMA,
|
||||
NULL, 0, &payload, &payload_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*dmas = (struct avs_probe_dma *)payload;
|
||||
*num_dmas = payload_size / sizeof(**dmas);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int avs_ipc_probe_attach_dma(struct avs_dev *adev, struct avs_probe_dma *dmas, size_t num_dmas)
|
||||
{
|
||||
u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
|
||||
|
||||
return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_INJECTION_DMA,
|
||||
(u8 *)dmas, array_size(sizeof(*dmas), num_dmas));
|
||||
}
|
||||
|
||||
int avs_ipc_probe_detach_dma(struct avs_dev *adev, union avs_connector_node_id *node_ids,
|
||||
size_t num_node_ids)
|
||||
{
|
||||
u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
|
||||
|
||||
return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID,
|
||||
AVS_PROBE_INJECTION_DMA_DETACH, (u8 *)node_ids,
|
||||
array_size(sizeof(*node_ids), num_node_ids));
|
||||
}
|
||||
|
||||
int avs_ipc_probe_get_points(struct avs_dev *adev, struct avs_probe_point_desc **descs,
|
||||
size_t *num_descs)
|
||||
{
|
||||
size_t payload_size;
|
||||
u32 module_id;
|
||||
u8 *payload;
|
||||
int ret;
|
||||
|
||||
module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
|
||||
|
||||
ret = avs_ipc_get_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_POINTS, NULL,
|
||||
0, &payload, &payload_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*descs = (struct avs_probe_point_desc *)payload;
|
||||
*num_descs = payload_size / sizeof(**descs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int avs_ipc_probe_connect_points(struct avs_dev *adev, struct avs_probe_point_desc *descs,
|
||||
size_t num_descs)
|
||||
{
|
||||
u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
|
||||
|
||||
return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID, AVS_PROBE_POINTS,
|
||||
(u8 *)descs, array_size(sizeof(*descs), num_descs));
|
||||
}
|
||||
|
||||
int avs_ipc_probe_disconnect_points(struct avs_dev *adev, union avs_probe_point_id *ids,
|
||||
size_t num_ids)
|
||||
{
|
||||
u32 module_id = avs_get_module_id(adev, &AVS_PROBE_MOD_UUID);
|
||||
|
||||
return avs_ipc_set_large_config(adev, module_id, AVS_PROBE_INST_ID,
|
||||
AVS_PROBE_POINTS_DISCONNECT, (u8 *)ids,
|
||||
array_size(sizeof(*ids), num_ids));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -802,4 +802,57 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
|
|||
const struct avs_audio_format *src_fmt,
|
||||
const struct avs_audio_format *sink_fmt);
|
||||
|
||||
#define AVS_PROBE_INST_ID 0
|
||||
|
||||
enum avs_probe_runtime_param {
|
||||
AVS_PROBE_INJECTION_DMA = 1,
|
||||
AVS_PROBE_INJECTION_DMA_DETACH,
|
||||
AVS_PROBE_POINTS,
|
||||
AVS_PROBE_POINTS_DISCONNECT,
|
||||
};
|
||||
|
||||
struct avs_probe_dma {
|
||||
union avs_connector_node_id node_id;
|
||||
u32 dma_buffer_size;
|
||||
} __packed;
|
||||
|
||||
enum avs_probe_type {
|
||||
AVS_PROBE_TYPE_INPUT = 0,
|
||||
AVS_PROBE_TYPE_OUTPUT,
|
||||
AVS_PROBE_TYPE_INTERNAL
|
||||
};
|
||||
|
||||
union avs_probe_point_id {
|
||||
u32 value;
|
||||
struct {
|
||||
u32 module_id:16;
|
||||
u32 instance_id:8;
|
||||
u32 type:2;
|
||||
u32 index:6;
|
||||
} id;
|
||||
} __packed;
|
||||
|
||||
enum avs_connection_purpose {
|
||||
AVS_CONNECTION_PURPOSE_EXTRACT = 0,
|
||||
AVS_CONNECTION_PURPOSE_INJECT,
|
||||
AVS_CONNECTION_PURPOSE_INJECT_REEXTRACT,
|
||||
};
|
||||
|
||||
struct avs_probe_point_desc {
|
||||
union avs_probe_point_id id;
|
||||
u32 purpose;
|
||||
union avs_connector_node_id node_id;
|
||||
} __packed;
|
||||
|
||||
int avs_ipc_probe_get_dma(struct avs_dev *adev, struct avs_probe_dma **dmas, size_t *num_dmas);
|
||||
int avs_ipc_probe_attach_dma(struct avs_dev *adev, struct avs_probe_dma *dmas, size_t num_dmas);
|
||||
int avs_ipc_probe_detach_dma(struct avs_dev *adev, union avs_connector_node_id *node_ids,
|
||||
size_t num_node_ids);
|
||||
int avs_ipc_probe_get_points(struct avs_dev *adev, struct avs_probe_point_desc **descs,
|
||||
size_t *num_descs);
|
||||
int avs_ipc_probe_connect_points(struct avs_dev *adev, struct avs_probe_point_desc *descs,
|
||||
size_t num_descs);
|
||||
int avs_ipc_probe_disconnect_points(struct avs_dev *adev, union avs_probe_point_id *ids,
|
||||
size_t num_ids);
|
||||
|
||||
#endif /* __SOUND_SOC_INTEL_AVS_MSGS_H */
|
||||
|
|
|
@ -1126,9 +1126,9 @@ static const struct snd_soc_component_driver avs_component_driver = {
|
|||
.topology_name_prefix = "intel/avs",
|
||||
};
|
||||
|
||||
static int avs_soc_component_register(struct device *dev, const char *name,
|
||||
const struct snd_soc_component_driver *drv,
|
||||
struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
|
||||
int avs_soc_component_register(struct device *dev, const char *name,
|
||||
const struct snd_soc_component_driver *drv,
|
||||
struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
|
||||
{
|
||||
struct avs_soc_component *acomp;
|
||||
int ret;
|
||||
|
|
313
sound/soc/intel/avs/probes.c
Normal file
313
sound/soc/intel/avs/probes.c
Normal file
|
@ -0,0 +1,313 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
|
||||
//
|
||||
// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
|
||||
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
|
||||
//
|
||||
|
||||
#include <sound/compress_driver.h>
|
||||
#include <sound/hdaudio_ext.h>
|
||||
#include <sound/hdaudio.h>
|
||||
#include <sound/soc.h>
|
||||
#include "avs.h"
|
||||
#include "messages.h"
|
||||
|
||||
static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id node_id,
|
||||
size_t buffer_size)
|
||||
{
|
||||
struct avs_probe_cfg cfg = {{0}};
|
||||
struct avs_module_entry mentry;
|
||||
u16 dummy;
|
||||
|
||||
avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
|
||||
|
||||
/*
|
||||
* Probe module uses no cycles, audio data format and input and output
|
||||
* frame sizes are unused. It is also not owned by any pipeline.
|
||||
*/
|
||||
cfg.base.ibs = 1;
|
||||
/* BSS module descriptor is always segment of index=2. */
|
||||
cfg.base.is_pages = mentry.segments[2].flags.length;
|
||||
cfg.gtw_cfg.node_id = node_id;
|
||||
cfg.gtw_cfg.dma_buffer_size = buffer_size;
|
||||
|
||||
return avs_dsp_init_module(adev, mentry.module_id, INVALID_PIPELINE_ID, 0, 0, &cfg,
|
||||
sizeof(cfg), &dummy);
|
||||
}
|
||||
|
||||
static void avs_dsp_delete_probe(struct avs_dev *adev)
|
||||
{
|
||||
struct avs_module_entry mentry;
|
||||
|
||||
avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
|
||||
|
||||
/* There is only ever one probe module instance. */
|
||||
avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0);
|
||||
}
|
||||
|
||||
static inline struct hdac_ext_stream *avs_compr_get_host_stream(struct snd_compr_stream *cstream)
|
||||
{
|
||||
return cstream->runtime->private_data;
|
||||
}
|
||||
|
||||
static int avs_probe_compr_open(struct snd_compr_stream *cstream, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct avs_dev *adev = to_avs_dev(dai->dev);
|
||||
struct hdac_bus *bus = &adev->base.core;
|
||||
struct hdac_ext_stream *host_stream;
|
||||
|
||||
if (adev->extractor) {
|
||||
dev_err(dai->dev, "Cannot open more than one extractor stream\n");
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
host_stream = snd_hdac_ext_cstream_assign(bus, cstream);
|
||||
if (!host_stream) {
|
||||
dev_err(dai->dev, "Failed to assign HDAudio stream for extraction\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
adev->extractor = host_stream;
|
||||
hdac_stream(host_stream)->curr_pos = 0;
|
||||
cstream->runtime->private_data = host_stream;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int avs_probe_compr_free(struct snd_compr_stream *cstream, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
|
||||
struct avs_dev *adev = to_avs_dev(dai->dev);
|
||||
struct avs_probe_point_desc *desc;
|
||||
/* Extractor node identifier. */
|
||||
unsigned int vindex = INVALID_NODE_ID.vindex;
|
||||
size_t num_desc;
|
||||
int i, ret;
|
||||
|
||||
/* Disconnect all probe points. */
|
||||
ret = avs_ipc_probe_get_points(adev, &desc, &num_desc);
|
||||
if (ret) {
|
||||
dev_err(dai->dev, "get probe points failed: %d\n", ret);
|
||||
ret = AVS_IPC_RET(ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_desc; i++)
|
||||
if (desc[i].node_id.vindex == vindex)
|
||||
avs_ipc_probe_disconnect_points(adev, &desc[i].id, 1);
|
||||
kfree(desc);
|
||||
|
||||
exit:
|
||||
if (adev->num_probe_streams) {
|
||||
adev->num_probe_streams--;
|
||||
if (!adev->num_probe_streams) {
|
||||
avs_dsp_delete_probe(adev);
|
||||
avs_dsp_enable_d0ix(adev);
|
||||
}
|
||||
}
|
||||
|
||||
snd_hdac_stream_cleanup(hdac_stream(host_stream));
|
||||
hdac_stream(host_stream)->prepared = 0;
|
||||
snd_hdac_ext_stream_release(host_stream, HDAC_EXT_STREAM_TYPE_HOST);
|
||||
|
||||
snd_compr_free_pages(cstream);
|
||||
adev->extractor = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int avs_probe_compr_set_params(struct snd_compr_stream *cstream,
|
||||
struct snd_compr_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
|
||||
struct snd_compr_runtime *rtd = cstream->runtime;
|
||||
struct avs_dev *adev = to_avs_dev(dai->dev);
|
||||
/* compr params do not store bit depth, default to S32_LE. */
|
||||
snd_pcm_format_t format = SNDRV_PCM_FORMAT_S32_LE;
|
||||
unsigned int format_val;
|
||||
int bps, ret;
|
||||
|
||||
hdac_stream(host_stream)->bufsize = 0;
|
||||
hdac_stream(host_stream)->period_bytes = 0;
|
||||
hdac_stream(host_stream)->format_val = 0;
|
||||
cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG;
|
||||
cstream->dma_buffer.dev.dev = adev->dev;
|
||||
|
||||
ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
bps = snd_pcm_format_physical_width(format);
|
||||
if (bps < 0)
|
||||
return bps;
|
||||
format_val = snd_hdac_calc_stream_format(params->codec.sample_rate, params->codec.ch_out,
|
||||
format, bps, 0);
|
||||
ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = snd_hdac_stream_setup(hdac_stream(host_stream));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
hdac_stream(host_stream)->prepared = 1;
|
||||
|
||||
if (!adev->num_probe_streams) {
|
||||
union avs_connector_node_id node_id;
|
||||
|
||||
/* D0ix not allowed during probing. */
|
||||
ret = avs_dsp_disable_d0ix(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
node_id.vindex = hdac_stream(host_stream)->stream_tag - 1;
|
||||
node_id.dma_type = AVS_DMA_HDA_HOST_INPUT;
|
||||
|
||||
ret = avs_dsp_init_probe(adev, node_id, rtd->dma_bytes);
|
||||
if (ret < 0) {
|
||||
dev_err(dai->dev, "probe init failed: %d\n", ret);
|
||||
avs_dsp_enable_d0ix(adev);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
adev->num_probe_streams++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int avs_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
|
||||
struct avs_dev *adev = to_avs_dev(dai->dev);
|
||||
struct hdac_bus *bus = &adev->base.core;
|
||||
unsigned long cookie;
|
||||
|
||||
if (!hdac_stream(host_stream)->prepared)
|
||||
return -EPIPE;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
spin_lock_irqsave(&bus->reg_lock, cookie);
|
||||
snd_hdac_stream_start(hdac_stream(host_stream), true);
|
||||
spin_unlock_irqrestore(&bus->reg_lock, cookie);
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
spin_lock_irqsave(&bus->reg_lock, cookie);
|
||||
snd_hdac_stream_stop(hdac_stream(host_stream));
|
||||
spin_unlock_irqrestore(&bus->reg_lock, cookie);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int avs_probe_compr_pointer(struct snd_compr_stream *cstream,
|
||||
struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
|
||||
struct snd_soc_pcm_stream *pstream;
|
||||
|
||||
pstream = &dai->driver->capture;
|
||||
tstamp->copied_total = hdac_stream(host_stream)->curr_pos;
|
||||
tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int avs_probe_compr_copy(struct snd_soc_component *comp, struct snd_compr_stream *cstream,
|
||||
char __user *buf, size_t count)
|
||||
{
|
||||
struct snd_compr_runtime *rtd = cstream->runtime;
|
||||
unsigned int offset, n;
|
||||
void *ptr;
|
||||
int ret;
|
||||
|
||||
if (count > rtd->buffer_size)
|
||||
count = rtd->buffer_size;
|
||||
|
||||
div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset);
|
||||
ptr = rtd->dma_area + offset;
|
||||
n = rtd->buffer_size - offset;
|
||||
|
||||
if (count < n) {
|
||||
ret = copy_to_user(buf, ptr, count);
|
||||
} else {
|
||||
ret = copy_to_user(buf, ptr, n);
|
||||
ret += copy_to_user(buf + n, rtd->dma_area, count - n);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return count - ret;
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct snd_soc_cdai_ops avs_probe_dai_ops = {
|
||||
.startup = avs_probe_compr_open,
|
||||
.shutdown = avs_probe_compr_free,
|
||||
.set_params = avs_probe_compr_set_params,
|
||||
.trigger = avs_probe_compr_trigger,
|
||||
.pointer = avs_probe_compr_pointer,
|
||||
};
|
||||
|
||||
static const struct snd_compress_ops avs_probe_compress_ops = {
|
||||
.copy = avs_probe_compr_copy,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver probe_cpu_dais[] = {
|
||||
{
|
||||
.name = "Probe Extraction CPU DAI",
|
||||
.compress_new = snd_soc_new_compress,
|
||||
.cops = &avs_probe_dai_ops,
|
||||
.capture = {
|
||||
.stream_name = "Probe Extraction",
|
||||
.channels_min = 1,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 48000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static int avs_probe_component_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct avs_soc_component *acomp = to_avs_soc_component(component);
|
||||
struct avs_dev *adev = to_avs_dev(component->dev);
|
||||
|
||||
mutex_lock(&adev->comp_list_mutex);
|
||||
list_add_tail(&acomp->node, &adev->comp_list);
|
||||
mutex_unlock(&adev->comp_list_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void avs_probe_component_remove(struct snd_soc_component *component)
|
||||
{
|
||||
struct avs_soc_component *acomp = to_avs_soc_component(component);
|
||||
struct avs_dev *adev = to_avs_dev(component->dev);
|
||||
|
||||
mutex_lock(&adev->comp_list_mutex);
|
||||
list_del(&acomp->node);
|
||||
mutex_unlock(&adev->comp_list_mutex);
|
||||
}
|
||||
|
||||
static const struct snd_soc_component_driver avs_probe_component_driver = {
|
||||
.name = "avs-probe-compr",
|
||||
.probe = avs_probe_component_probe,
|
||||
.remove = avs_probe_component_remove,
|
||||
.compress_ops = &avs_probe_compress_ops,
|
||||
.module_get_upon_open = 1, /* increment refcount when a stream is opened */
|
||||
};
|
||||
|
||||
int avs_probe_platform_register(struct avs_dev *adev, const char *name)
|
||||
{
|
||||
return avs_soc_component_register(adev->dev, name, &avs_probe_component_driver,
|
||||
probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais));
|
||||
}
|
|
@ -59,7 +59,8 @@
|
|||
#define AVS_FW_REG_STATUS(adev) (AVS_FW_REG_BASE(adev) + 0x0)
|
||||
#define AVS_FW_REG_ERROR_CODE(adev) (AVS_FW_REG_BASE(adev) + 0x4)
|
||||
|
||||
#define AVS_FW_REGS_SIZE PAGE_SIZE
|
||||
#define AVS_WINDOW_CHUNK_SIZE PAGE_SIZE
|
||||
#define AVS_FW_REGS_SIZE AVS_WINDOW_CHUNK_SIZE
|
||||
#define AVS_FW_REGS_WINDOW 0
|
||||
/* DSP -> HOST communication window */
|
||||
#define AVS_UPLINK_WINDOW AVS_FW_REGS_WINDOW
|
||||
|
|
|
@ -12,8 +12,9 @@
|
|||
#include "avs.h"
|
||||
#include "messages.h"
|
||||
|
||||
static int skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
|
||||
u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
|
||||
static int __maybe_unused
|
||||
skl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period,
|
||||
u32 fifo_full_period, unsigned long resource_mask, u32 *priorities)
|
||||
{
|
||||
struct skl_log_state_info *info;
|
||||
u32 size, num_cores = adev->hw_cfg.dsp_cores;
|
||||
|
@ -55,15 +56,11 @@ int skl_log_buffer_offset(struct avs_dev *adev, u32 core)
|
|||
static int
|
||||
skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
|
||||
{
|
||||
unsigned long flags;
|
||||
void __iomem *buf;
|
||||
u16 size, write, offset;
|
||||
|
||||
spin_lock_irqsave(&adev->dbg.trace_lock, flags);
|
||||
if (!kfifo_initialized(&adev->dbg.trace_fifo)) {
|
||||
spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
|
||||
if (!avs_logging_fw(adev))
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = avs_log_buffer_size(adev) / 2;
|
||||
write = readl(avs_sram_addr(adev, AVS_FW_REGS_WINDOW) + FW_REGS_DBG_LOG_WP(msg->log.core));
|
||||
|
@ -72,9 +69,7 @@ skl_log_buffer_status(struct avs_dev *adev, union avs_notify_msg *msg)
|
|||
|
||||
/* Address is guaranteed to exist in SRAM2. */
|
||||
buf = avs_log_buffer_addr(adev, msg->log.core) + offset;
|
||||
__kfifo_fromio_locked(&adev->dbg.trace_fifo, buf, size, &adev->dbg.fifo_lock);
|
||||
wake_up(&adev->dbg.trace_waitq);
|
||||
spin_unlock_irqrestore(&adev->dbg.trace_lock, flags);
|
||||
avs_dump_fw_log_wakeup(adev, buf, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -116,10 +111,10 @@ const struct avs_dsp_ops skl_dsp_ops = {
|
|||
.load_basefw = avs_cldma_load_basefw,
|
||||
.load_lib = avs_cldma_load_library,
|
||||
.transfer_mods = avs_cldma_transfer_modules,
|
||||
.enable_logs = skl_enable_logs,
|
||||
.log_buffer_offset = skl_log_buffer_offset,
|
||||
.log_buffer_status = skl_log_buffer_status,
|
||||
.coredump = skl_coredump,
|
||||
.d0ix_toggle = skl_d0ix_toggle,
|
||||
.set_d0ix = skl_set_d0ix,
|
||||
AVS_SET_ENABLE_LOGS_OP(skl)
|
||||
};
|
||||
|
|
|
@ -300,25 +300,3 @@ void avs_release_firmwares(struct avs_dev *adev)
|
|||
kfree(entry);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int __kfifo_fromio_locked(struct kfifo *fifo, const void __iomem *src, unsigned int len,
|
||||
spinlock_t *lock)
|
||||
{
|
||||
struct __kfifo *__fifo = &fifo->kfifo;
|
||||
unsigned long flags;
|
||||
unsigned int l, off;
|
||||
|
||||
spin_lock_irqsave(lock, flags);
|
||||
len = min(len, kfifo_avail(fifo));
|
||||
off = __fifo->in & __fifo->mask;
|
||||
l = min(len, kfifo_size(fifo) - off);
|
||||
|
||||
memcpy_fromio(__fifo->data + off, src, l);
|
||||
memcpy_fromio(__fifo->data, src + l, len - l);
|
||||
/* Make sure data copied from SRAM is visible to all CPUs. */
|
||||
smp_mb();
|
||||
__fifo->in += len;
|
||||
spin_unlock_irqrestore(lock, flags);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
|
|
@ -37,8 +37,7 @@ snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o
|
|||
snd-soc-ehl-rt5660-objs := ehl_rt5660.o
|
||||
snd-soc-sof-ssp-amp-objs := sof_ssp_amp.o
|
||||
snd-soc-sof-sdw-objs += sof_sdw.o \
|
||||
sof_sdw_max98373.o sof_sdw_rt1308.o \
|
||||
sof_sdw_rt1316.o sof_sdw_rt1318.o \
|
||||
sof_sdw_max98373.o sof_sdw_rt_amp.o \
|
||||
sof_sdw_rt5682.o sof_sdw_rt700.o \
|
||||
sof_sdw_rt711.o sof_sdw_rt711_sdca.o \
|
||||
sof_sdw_rt715.o sof_sdw_rt715_sdca.o \
|
||||
|
|
|
@ -783,7 +783,7 @@ static int sof_es8336_remove(struct platform_device *pdev)
|
|||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
struct sof_es8336_private *priv = snd_soc_card_get_drvdata(card);
|
||||
|
||||
cancel_delayed_work(&priv->pcm_pop_work);
|
||||
cancel_delayed_work_sync(&priv->pcm_pop_work);
|
||||
gpiod_put(priv->gpio_speakers);
|
||||
device_remove_software_node(priv->codec_dev);
|
||||
put_device(priv->codec_dev);
|
||||
|
|
|
@ -267,7 +267,8 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai_link *dai_link = rtd->dai_link;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
int i, clk_freq, ret;
|
||||
int i, clk_freq;
|
||||
int ret = 0;
|
||||
|
||||
clk_freq = sof_dai_get_bclk(rtd);
|
||||
|
||||
|
|
|
@ -1104,6 +1104,12 @@ static const struct platform_device_id board_ids[] = {
|
|||
SOF_RT5682_SSP_AMP(1) |
|
||||
SOF_RT5682_NUM_HDMIDEV(4)),
|
||||
},
|
||||
{
|
||||
.name = "jsl_rt5682",
|
||||
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
|
||||
SOF_RT5682_MCLK_24MHZ |
|
||||
SOF_RT5682_SSP_CODEC(0)),
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, board_ids);
|
||||
|
|
|
@ -550,23 +550,23 @@ static struct sof_sdw_codec_info codec_info_list[] = {
|
|||
.direction = {true, false},
|
||||
.dai_name = "rt1308-aif",
|
||||
.ops = &sof_sdw_rt1308_i2s_ops,
|
||||
.init = sof_sdw_rt1308_init,
|
||||
.exit = sof_sdw_rt1308_exit,
|
||||
.init = sof_sdw_rt_amp_init,
|
||||
.exit = sof_sdw_rt_amp_exit,
|
||||
.codec_type = SOF_SDW_CODEC_TYPE_AMP,
|
||||
},
|
||||
{
|
||||
.part_id = 0x1316,
|
||||
.direction = {true, true},
|
||||
.dai_name = "rt1316-aif",
|
||||
.init = sof_sdw_rt1316_init,
|
||||
.exit = sof_sdw_rt1316_exit,
|
||||
.init = sof_sdw_rt_amp_init,
|
||||
.exit = sof_sdw_rt_amp_exit,
|
||||
.codec_type = SOF_SDW_CODEC_TYPE_AMP,
|
||||
},
|
||||
{
|
||||
.part_id = 0x1318,
|
||||
.direction = {true, true},
|
||||
.dai_name = "rt1318-aif",
|
||||
.init = sof_sdw_rt1318_init,
|
||||
.init = sof_sdw_rt_amp_init,
|
||||
.codec_type = SOF_SDW_CODEC_TYPE_AMP,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -125,30 +125,18 @@ int sof_sdw_rt700_init(struct snd_soc_card *card,
|
|||
struct sof_sdw_codec_info *info,
|
||||
bool playback);
|
||||
|
||||
/* RT1308 support */
|
||||
/* RT1308 I2S support */
|
||||
extern struct snd_soc_ops sof_sdw_rt1308_i2s_ops;
|
||||
|
||||
int sof_sdw_rt1308_init(struct snd_soc_card *card,
|
||||
/* generic amp support */
|
||||
int sof_sdw_rt_amp_init(struct snd_soc_card *card,
|
||||
const struct snd_soc_acpi_link_adr *link,
|
||||
struct snd_soc_dai_link *dai_links,
|
||||
struct sof_sdw_codec_info *info,
|
||||
bool playback);
|
||||
int sof_sdw_rt1308_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
|
||||
int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
|
||||
|
||||
/* RT1316 support */
|
||||
int sof_sdw_rt1316_init(struct snd_soc_card *card,
|
||||
const struct snd_soc_acpi_link_adr *link,
|
||||
struct snd_soc_dai_link *dai_links,
|
||||
struct sof_sdw_codec_info *info,
|
||||
bool playback);
|
||||
int sof_sdw_rt1316_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
|
||||
|
||||
/* RT1318 support */
|
||||
int sof_sdw_rt1318_init(struct snd_soc_card *card,
|
||||
const struct snd_soc_acpi_link_adr *link,
|
||||
struct snd_soc_dai_link *dai_links,
|
||||
struct sof_sdw_codec_info *info,
|
||||
bool playback);
|
||||
|
||||
/* RT715 support */
|
||||
int sof_sdw_rt715_init(struct snd_soc_card *card,
|
||||
|
|
|
@ -1,239 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
|
||||
/*
|
||||
* sof_sdw_rt1316 - Helpers to handle RT1316 from generic machine driver
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-acpi.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_type.h>
|
||||
#include <linux/dmi.h>
|
||||
#include "sof_sdw_common.h"
|
||||
#include "sof_sdw_amp_coeff_tables.h"
|
||||
|
||||
struct rt1316_platform_data {
|
||||
const unsigned char *bq_params;
|
||||
const unsigned int bq_params_cnt;
|
||||
};
|
||||
|
||||
static const struct rt1316_platform_data dell_0b00_platform_data = {
|
||||
.bq_params = dell_0b00_bq_params,
|
||||
.bq_params_cnt = ARRAY_SIZE(dell_0b00_bq_params),
|
||||
};
|
||||
|
||||
static const struct dmi_system_id dmi_platform_data[] = {
|
||||
/* AlderLake devices */
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
|
||||
},
|
||||
.driver_data = (void *)&dell_0b00_platform_data,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
|
||||
},
|
||||
.driver_data = (void *)&dell_0b00_platform_data,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
|
||||
},
|
||||
.driver_data = (void *)&dell_0b00_platform_data,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
|
||||
},
|
||||
.driver_data = (void *)&dell_0b00_platform_data,
|
||||
},
|
||||
};
|
||||
|
||||
static int rt1316_add_device_props(struct device *sdw_dev)
|
||||
{
|
||||
struct property_entry props[3] = {};
|
||||
struct fwnode_handle *fwnode;
|
||||
const struct dmi_system_id *dmi_data;
|
||||
const struct rt1316_platform_data *pdata;
|
||||
unsigned char params[RT1316_MAX_BQ_REG];
|
||||
int ret;
|
||||
|
||||
dmi_data = dmi_first_match(dmi_platform_data);
|
||||
if (!dmi_data)
|
||||
return 0;
|
||||
|
||||
pdata = dmi_data->driver_data;
|
||||
memcpy(¶ms, pdata->bq_params, sizeof(unsigned char) * pdata->bq_params_cnt);
|
||||
|
||||
props[0] = PROPERTY_ENTRY_U8_ARRAY("realtek,bq-params", params);
|
||||
props[1] = PROPERTY_ENTRY_U32("realtek,bq-params-cnt", pdata->bq_params_cnt);
|
||||
|
||||
fwnode = fwnode_create_software_node(props, NULL);
|
||||
if (IS_ERR(fwnode))
|
||||
return PTR_ERR(fwnode);
|
||||
|
||||
ret = device_add_software_node(sdw_dev, to_software_node(fwnode));
|
||||
|
||||
fwnode_handle_put(fwnode);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget rt1316_widgets[] = {
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
};
|
||||
|
||||
/*
|
||||
* dapm routes for rt1316 will be registered dynamically according
|
||||
* to the number of rt1316 used. The first two entries will be registered
|
||||
* for one codec case, and the last two entries are also registered
|
||||
* if two 1316s are used.
|
||||
*/
|
||||
static const struct snd_soc_dapm_route rt1316_map[] = {
|
||||
{ "Speaker", NULL, "rt1316-1 SPOL" },
|
||||
{ "Speaker", NULL, "rt1316-1 SPOR" },
|
||||
{ "Speaker", NULL, "rt1316-2 SPOL" },
|
||||
{ "Speaker", NULL, "rt1316-2 SPOR" },
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new rt1316_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Speaker"),
|
||||
};
|
||||
|
||||
static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
int ret;
|
||||
|
||||
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
|
||||
"%s spk:rt1316",
|
||||
card->components);
|
||||
if (!card->components)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = snd_soc_add_card_controls(card, rt1316_controls,
|
||||
ARRAY_SIZE(rt1316_controls));
|
||||
if (ret) {
|
||||
dev_err(card->dev, "rt1316 controls addition failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dapm_new_controls(&card->dapm, rt1316_widgets,
|
||||
ARRAY_SIZE(rt1316_widgets));
|
||||
if (ret) {
|
||||
dev_err(card->dev, "rt1316 widgets addition failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm, rt1316_map, 2);
|
||||
if (ret)
|
||||
dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm, rt1316_map + 2, 2);
|
||||
if (ret)
|
||||
dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int all_spk_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = first_spk_init(rtd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return second_spk_init(rtd);
|
||||
}
|
||||
|
||||
int sof_sdw_rt1316_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
|
||||
{
|
||||
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
|
||||
if (ctx->amp_dev1) {
|
||||
device_remove_software_node(ctx->amp_dev1);
|
||||
put_device(ctx->amp_dev1);
|
||||
}
|
||||
|
||||
if (ctx->amp_dev2) {
|
||||
device_remove_software_node(ctx->amp_dev2);
|
||||
put_device(ctx->amp_dev2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sof_sdw_rt1316_init(struct snd_soc_card *card,
|
||||
const struct snd_soc_acpi_link_adr *link,
|
||||
struct snd_soc_dai_link *dai_links,
|
||||
struct sof_sdw_codec_info *info,
|
||||
bool playback)
|
||||
{
|
||||
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
struct device *sdw_dev1, *sdw_dev2;
|
||||
int ret;
|
||||
|
||||
/* Count amp number and do init on playback link only. */
|
||||
if (!playback)
|
||||
return 0;
|
||||
|
||||
info->amp_num++;
|
||||
if (info->amp_num == 1)
|
||||
dai_links->init = first_spk_init;
|
||||
|
||||
if (info->amp_num == 2) {
|
||||
sdw_dev1 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name);
|
||||
if (!sdw_dev1)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
ret = rt1316_add_device_props(sdw_dev1);
|
||||
if (ret < 0) {
|
||||
put_device(sdw_dev1);
|
||||
return ret;
|
||||
}
|
||||
ctx->amp_dev1 = sdw_dev1;
|
||||
|
||||
sdw_dev2 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[1].name);
|
||||
if (!sdw_dev2)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
ret = rt1316_add_device_props(sdw_dev2);
|
||||
if (ret < 0) {
|
||||
put_device(sdw_dev2);
|
||||
return ret;
|
||||
}
|
||||
ctx->amp_dev2 = sdw_dev2;
|
||||
|
||||
/*
|
||||
* if two 1316s are in one dai link, the init function
|
||||
* in this dai link will be first set for the first speaker,
|
||||
* and it should be reset to initialize all speakers when
|
||||
* the second speaker is found.
|
||||
*/
|
||||
if (dai_links->init)
|
||||
dai_links->init = all_spk_init;
|
||||
else
|
||||
dai_links->init = second_spk_init;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2022 Intel Corporation
|
||||
|
||||
/*
|
||||
* sof_sdw_rt1318 - Helpers to handle RT1318 from generic machine driver
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-acpi.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include "sof_sdw_common.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget rt1318_widgets[] = {
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
};
|
||||
|
||||
/*
|
||||
* dapm routes for rt1318 will be registered dynamically according
|
||||
* to the number of rt1318 used. The first two entries will be registered
|
||||
* for one codec case, and the last two entries are also registered
|
||||
* if two 1318s are used.
|
||||
*/
|
||||
static const struct snd_soc_dapm_route rt1318_map[] = {
|
||||
{ "Speaker", NULL, "rt1318-1 SPOL" },
|
||||
{ "Speaker", NULL, "rt1318-1 SPOR" },
|
||||
{ "Speaker", NULL, "rt1318-2 SPOL" },
|
||||
{ "Speaker", NULL, "rt1318-2 SPOR" },
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new rt1318_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Speaker"),
|
||||
};
|
||||
|
||||
static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
int ret;
|
||||
|
||||
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
|
||||
"%s spk:rt1318",
|
||||
card->components);
|
||||
if (!card->components)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = snd_soc_add_card_controls(card, rt1318_controls,
|
||||
ARRAY_SIZE(rt1318_controls));
|
||||
if (ret) {
|
||||
dev_err(card->dev, "rt1318 controls addition failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dapm_new_controls(&card->dapm, rt1318_widgets,
|
||||
ARRAY_SIZE(rt1318_widgets));
|
||||
if (ret) {
|
||||
dev_err(card->dev, "rt1318 widgets addition failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm, rt1318_map, 2);
|
||||
if (ret)
|
||||
dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm, rt1318_map + 2, 2);
|
||||
if (ret)
|
||||
dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int all_spk_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = first_spk_init(rtd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return second_spk_init(rtd);
|
||||
}
|
||||
|
||||
int sof_sdw_rt1318_init(struct snd_soc_card *card,
|
||||
const struct snd_soc_acpi_link_adr *link,
|
||||
struct snd_soc_dai_link *dai_links,
|
||||
struct sof_sdw_codec_info *info,
|
||||
bool playback)
|
||||
{
|
||||
/* Count amp number and do init on playback link only. */
|
||||
if (!playback)
|
||||
return 0;
|
||||
|
||||
info->amp_num++;
|
||||
if (info->amp_num == 1)
|
||||
dai_links->init = first_spk_init;
|
||||
|
||||
if (info->amp_num == 2) {
|
||||
/*
|
||||
* if two 1318s are in one dai link, the init function
|
||||
* in this dai link will be first set for the first speaker,
|
||||
* and it should be reset to initialize all speakers when
|
||||
* the second speaker is found.
|
||||
*/
|
||||
if (dai_links->init)
|
||||
dai_links->init = all_spk_init;
|
||||
else
|
||||
dai_links->init = second_spk_init;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
// Copyright (c) 2022 Intel Corporation
|
||||
|
||||
/*
|
||||
* sof_sdw_rt1308 - Helpers to handle RT1308 from generic machine driver
|
||||
* sof_sdw_rt_amp - Helpers to handle RT1308/RT1316/RT1318 from generic machine driver
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
|
@ -18,16 +18,26 @@
|
|||
#include "sof_sdw_amp_coeff_tables.h"
|
||||
#include "../../codecs/rt1308.h"
|
||||
|
||||
struct rt1308_platform_data {
|
||||
#define CODEC_NAME_SIZE 7
|
||||
|
||||
/* choose a larger value to resolve compatibility issues */
|
||||
#define RT_AMP_MAX_BQ_REG RT1316_MAX_BQ_REG
|
||||
|
||||
struct rt_amp_platform_data {
|
||||
const unsigned char *bq_params;
|
||||
const unsigned int bq_params_cnt;
|
||||
};
|
||||
|
||||
static const struct rt1308_platform_data dell_0a5d_platform_data = {
|
||||
static const struct rt_amp_platform_data dell_0a5d_platform_data = {
|
||||
.bq_params = dell_0a5d_bq_params,
|
||||
.bq_params_cnt = ARRAY_SIZE(dell_0a5d_bq_params),
|
||||
};
|
||||
|
||||
static const struct rt_amp_platform_data dell_0b00_platform_data = {
|
||||
.bq_params = dell_0b00_bq_params,
|
||||
.bq_params_cnt = ARRAY_SIZE(dell_0b00_bq_params),
|
||||
};
|
||||
|
||||
static const struct dmi_system_id dmi_platform_data[] = {
|
||||
/* CometLake devices */
|
||||
{
|
||||
|
@ -59,15 +69,45 @@ static const struct dmi_system_id dmi_platform_data[] = {
|
|||
},
|
||||
.driver_data = (void *)&dell_0a5d_platform_data,
|
||||
},
|
||||
/* AlderLake devices */
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
|
||||
},
|
||||
.driver_data = (void *)&dell_0b00_platform_data,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
|
||||
},
|
||||
.driver_data = (void *)&dell_0b00_platform_data,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
|
||||
},
|
||||
.driver_data = (void *)&dell_0b00_platform_data,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
|
||||
},
|
||||
.driver_data = (void *)&dell_0b00_platform_data,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static int rt1308_add_device_props(struct device *sdw_dev)
|
||||
static int rt_amp_add_device_props(struct device *sdw_dev)
|
||||
{
|
||||
struct property_entry props[3] = {};
|
||||
struct fwnode_handle *fwnode;
|
||||
const struct dmi_system_id *dmi_data;
|
||||
const struct rt1308_platform_data *pdata;
|
||||
unsigned char params[RT1308_MAX_BQ_REG];
|
||||
const struct rt_amp_platform_data *pdata;
|
||||
unsigned char params[RT_AMP_MAX_BQ_REG];
|
||||
int ret;
|
||||
|
||||
dmi_data = dmi_first_match(dmi_platform_data);
|
||||
|
@ -91,15 +131,19 @@ static int rt1308_add_device_props(struct device *sdw_dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget rt1308_widgets[] = {
|
||||
static const struct snd_kcontrol_new rt_amp_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Speaker"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget rt_amp_widgets[] = {
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
};
|
||||
|
||||
/*
|
||||
* dapm routes for rt1308 will be registered dynamically according
|
||||
* to the number of rt1308 used. The first two entries will be registered
|
||||
* for one codec case, and the last two entries are also registered
|
||||
* if two 1308s are used.
|
||||
* dapm routes for rt1308/rt1316/rt1318 will be registered dynamically
|
||||
* according to the number of rt1308/rt1316/rt1318 used. The first two
|
||||
* entries will be registered for one codec case, and the last two entries
|
||||
* are also registered if two 1308s/1316s/1318s are used.
|
||||
*/
|
||||
static const struct snd_soc_dapm_route rt1308_map[] = {
|
||||
{ "Speaker", NULL, "rt1308-1 SPOL" },
|
||||
|
@ -108,36 +152,69 @@ static const struct snd_soc_dapm_route rt1308_map[] = {
|
|||
{ "Speaker", NULL, "rt1308-2 SPOR" },
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new rt1308_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Speaker"),
|
||||
static const struct snd_soc_dapm_route rt1316_map[] = {
|
||||
{ "Speaker", NULL, "rt1316-1 SPOL" },
|
||||
{ "Speaker", NULL, "rt1316-1 SPOR" },
|
||||
{ "Speaker", NULL, "rt1316-2 SPOL" },
|
||||
{ "Speaker", NULL, "rt1316-2 SPOR" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route rt1318_map[] = {
|
||||
{ "Speaker", NULL, "rt1318-1 SPOL" },
|
||||
{ "Speaker", NULL, "rt1318-1 SPOR" },
|
||||
{ "Speaker", NULL, "rt1318-2 SPOL" },
|
||||
{ "Speaker", NULL, "rt1318-2 SPOR" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route *get_codec_name_and_route(struct snd_soc_pcm_runtime *rtd,
|
||||
char *codec_name)
|
||||
{
|
||||
const char *dai_name;
|
||||
|
||||
dai_name = rtd->dai_link->codecs->dai_name;
|
||||
|
||||
/* get the codec name */
|
||||
snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai_name);
|
||||
|
||||
/* choose the right codec's map */
|
||||
if (strcmp(codec_name, "rt1308") == 0)
|
||||
return rt1308_map;
|
||||
else if (strcmp(codec_name, "rt1316") == 0)
|
||||
return rt1316_map;
|
||||
else
|
||||
return rt1318_map;
|
||||
}
|
||||
|
||||
static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
const struct snd_soc_dapm_route *rt_amp_map;
|
||||
char codec_name[CODEC_NAME_SIZE];
|
||||
int ret;
|
||||
|
||||
rt_amp_map = get_codec_name_and_route(rtd, codec_name);
|
||||
|
||||
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
|
||||
"%s spk:rt1308",
|
||||
card->components);
|
||||
"%s spk:%s",
|
||||
card->components, codec_name);
|
||||
if (!card->components)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = snd_soc_add_card_controls(card, rt1308_controls,
|
||||
ARRAY_SIZE(rt1308_controls));
|
||||
ret = snd_soc_add_card_controls(card, rt_amp_controls,
|
||||
ARRAY_SIZE(rt_amp_controls));
|
||||
if (ret) {
|
||||
dev_err(card->dev, "rt1308 controls addition failed: %d\n", ret);
|
||||
dev_err(card->dev, "%s controls addition failed: %d\n", codec_name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_widgets,
|
||||
ARRAY_SIZE(rt1308_widgets));
|
||||
ret = snd_soc_dapm_new_controls(&card->dapm, rt_amp_widgets,
|
||||
ARRAY_SIZE(rt_amp_widgets));
|
||||
if (ret) {
|
||||
dev_err(card->dev, "rt1308 widgets addition failed: %d\n", ret);
|
||||
dev_err(card->dev, "%s widgets addition failed: %d\n", codec_name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map, 2);
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm, rt_amp_map, 2);
|
||||
if (ret)
|
||||
dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
|
||||
|
||||
|
@ -147,9 +224,13 @@ static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
|
|||
static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
const struct snd_soc_dapm_route *rt_amp_map;
|
||||
char codec_name[CODEC_NAME_SIZE];
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map + 2, 2);
|
||||
rt_amp_map = get_codec_name_and_route(rtd, codec_name);
|
||||
|
||||
ret = snd_soc_dapm_add_routes(&card->dapm, rt_amp_map + 2, 2);
|
||||
if (ret)
|
||||
dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
|
||||
|
||||
|
@ -204,7 +285,7 @@ struct snd_soc_ops sof_sdw_rt1308_i2s_ops = {
|
|||
.hw_params = rt1308_i2s_hw_params,
|
||||
};
|
||||
|
||||
int sof_sdw_rt1308_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
|
||||
int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
|
||||
{
|
||||
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
|
||||
|
||||
|
@ -221,7 +302,7 @@ int sof_sdw_rt1308_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sof_sdw_rt1308_init(struct snd_soc_card *card,
|
||||
int sof_sdw_rt_amp_init(struct snd_soc_card *card,
|
||||
const struct snd_soc_acpi_link_adr *link,
|
||||
struct snd_soc_dai_link *dai_links,
|
||||
struct sof_sdw_codec_info *info,
|
||||
|
@ -244,7 +325,7 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card,
|
|||
if (!sdw_dev1)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
ret = rt1308_add_device_props(sdw_dev1);
|
||||
ret = rt_amp_add_device_props(sdw_dev1);
|
||||
if (ret < 0) {
|
||||
put_device(sdw_dev1);
|
||||
return ret;
|
||||
|
@ -255,7 +336,7 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card,
|
|||
if (!sdw_dev2)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
ret = rt1308_add_device_props(sdw_dev2);
|
||||
ret = rt_amp_add_device_props(sdw_dev2);
|
||||
if (ret < 0) {
|
||||
put_device(sdw_dev2);
|
||||
return ret;
|
||||
|
@ -263,7 +344,7 @@ int sof_sdw_rt1308_init(struct snd_soc_card *card,
|
|||
ctx->amp_dev2 = sdw_dev2;
|
||||
|
||||
/*
|
||||
* if two 1308s are in one dai link, the init function
|
||||
* if two amps are in one dai link, the init function
|
||||
* in this dai link will be first set for the first speaker,
|
||||
* and it should be reset to initialize all speakers when
|
||||
* the second speaker is found.
|
|
@ -78,6 +78,11 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = {
|
|||
.quirk_data = &mx98360a_spk,
|
||||
.sof_tplg_filename = "sof-jsl-rt5682-mx98360a.tplg",
|
||||
},
|
||||
{
|
||||
.comp_ids = &rt5682_rt5682s_hp,
|
||||
.drv_name = "jsl_rt5682",
|
||||
.sof_tplg_filename = "sof-jsl-rt5682.tplg",
|
||||
},
|
||||
{
|
||||
.id = "10134242",
|
||||
.drv_name = "jsl_cs4242_mx98360a",
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/delay.h>
|
||||
#include <sound/hda_register.h>
|
||||
#include "../common/sst-dsp.h"
|
||||
#include "../common/sst-dsp-priv.h"
|
||||
|
||||
|
@ -79,21 +80,25 @@ static void skl_cldma_setup_bdle(struct sst_dsp *ctx,
|
|||
__le32 **bdlp, int size, int with_ioc)
|
||||
{
|
||||
__le32 *bdl = *bdlp;
|
||||
int remaining = ctx->cl_dev.bufsize;
|
||||
int offset = 0;
|
||||
|
||||
ctx->cl_dev.frags = 0;
|
||||
while (size > 0) {
|
||||
phys_addr_t addr = virt_to_phys(dmab_data->area +
|
||||
(ctx->cl_dev.frags * ctx->cl_dev.bufsize));
|
||||
while (remaining > 0) {
|
||||
phys_addr_t addr;
|
||||
int chunk;
|
||||
|
||||
addr = snd_sgbuf_get_addr(dmab_data, offset);
|
||||
bdl[0] = cpu_to_le32(lower_32_bits(addr));
|
||||
bdl[1] = cpu_to_le32(upper_32_bits(addr));
|
||||
chunk = snd_sgbuf_get_chunk_size(dmab_data, offset, size);
|
||||
bdl[2] = cpu_to_le32(chunk);
|
||||
|
||||
bdl[2] = cpu_to_le32(ctx->cl_dev.bufsize);
|
||||
|
||||
size -= ctx->cl_dev.bufsize;
|
||||
bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
|
||||
remaining -= chunk;
|
||||
bdl[3] = (remaining > 0) ? 0 : cpu_to_le32(0x01);
|
||||
|
||||
bdl += 4;
|
||||
offset += chunk;
|
||||
ctx->cl_dev.frags++;
|
||||
}
|
||||
}
|
||||
|
@ -338,15 +343,15 @@ int skl_cldma_prepare(struct sst_dsp *ctx)
|
|||
ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop;
|
||||
|
||||
/* Allocate buffer*/
|
||||
ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev,
|
||||
&ctx->cl_dev.dmab_data, ctx->cl_dev.bufsize);
|
||||
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, ctx->dev, ctx->cl_dev.bufsize,
|
||||
&ctx->cl_dev.dmab_data);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Alloc buffer for base fw failed: %x\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Setup Code loader BDL */
|
||||
ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev,
|
||||
&ctx->cl_dev.dmab_bdl, PAGE_SIZE);
|
||||
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, ctx->dev, BDL_SIZE, &ctx->cl_dev.dmab_bdl);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "Alloc buffer for blde failed: %x\n", ret);
|
||||
ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
|
||||
|
|
|
@ -582,36 +582,10 @@ static int skl_tplg_unload_pipe_modules(struct skl_dev *skl,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool skl_tplg_is_multi_fmt(struct skl_dev *skl, struct skl_pipe *pipe)
|
||||
static void skl_tplg_set_pipe_config_idx(struct skl_pipe *pipe, int idx)
|
||||
{
|
||||
struct skl_pipe_fmt *cur_fmt;
|
||||
struct skl_pipe_fmt *next_fmt;
|
||||
int i;
|
||||
|
||||
if (pipe->nr_cfgs <= 1)
|
||||
return false;
|
||||
|
||||
if (pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
|
||||
return true;
|
||||
|
||||
for (i = 0; i < pipe->nr_cfgs - 1; i++) {
|
||||
if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
cur_fmt = &pipe->configs[i].out_fmt;
|
||||
next_fmt = &pipe->configs[i + 1].out_fmt;
|
||||
} else {
|
||||
cur_fmt = &pipe->configs[i].in_fmt;
|
||||
next_fmt = &pipe->configs[i + 1].in_fmt;
|
||||
}
|
||||
|
||||
if (!CHECK_HW_PARAMS(cur_fmt->channels, cur_fmt->freq,
|
||||
cur_fmt->bps,
|
||||
next_fmt->channels,
|
||||
next_fmt->freq,
|
||||
next_fmt->bps))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
pipe->cur_config_idx = idx;
|
||||
pipe->memory_pages = pipe->configs[idx].mem_pages;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -632,24 +606,14 @@ skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
|
|||
int i;
|
||||
|
||||
if (pipe->nr_cfgs == 0) {
|
||||
pipe->cur_config_idx = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (skl_tplg_is_multi_fmt(skl, pipe)) {
|
||||
pipe->cur_config_idx = pipe->pipe_config_idx;
|
||||
pipe->memory_pages = pconfig->mem_pages;
|
||||
dev_dbg(skl->dev, "found pipe config idx:%d\n",
|
||||
pipe->cur_config_idx);
|
||||
skl_tplg_set_pipe_config_idx(pipe, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE || pipe->nr_cfgs == 1) {
|
||||
dev_dbg(skl->dev, "No conn_type or just 1 pathcfg, taking 0th for %d\n",
|
||||
pipe->ppl_id);
|
||||
pipe->cur_config_idx = 0;
|
||||
pipe->memory_pages = pconfig->mem_pages;
|
||||
|
||||
skl_tplg_set_pipe_config_idx(pipe, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -668,10 +632,8 @@ skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig)
|
|||
|
||||
if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt,
|
||||
fmt->channels, fmt->freq, fmt->bps)) {
|
||||
pipe->cur_config_idx = i;
|
||||
pipe->memory_pages = pconfig->mem_pages;
|
||||
skl_tplg_set_pipe_config_idx(pipe, i);
|
||||
dev_dbg(skl->dev, "Using pipe config: %d\n", i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1391,9 +1353,9 @@ static int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol,
|
|||
return -EIO;
|
||||
|
||||
if (is_set)
|
||||
pipe->pipe_config_idx = ucontrol->value.enumerated.item[0];
|
||||
skl_tplg_set_pipe_config_idx(pipe, ucontrol->value.enumerated.item[0]);
|
||||
else
|
||||
ucontrol->value.enumerated.item[0] = pipe->pipe_config_idx;
|
||||
ucontrol->value.enumerated.item[0] = pipe->cur_config_idx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1837,20 +1799,28 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
|
|||
{
|
||||
struct nhlt_specific_cfg *cfg;
|
||||
struct skl_pipe *pipe = mconfig->pipe;
|
||||
struct skl_pipe_params save = *pipe->p_params;
|
||||
struct skl_pipe_fmt *pipe_fmt;
|
||||
struct skl_dev *skl = get_skl_ctx(dai->dev);
|
||||
int link_type = skl_tplg_be_link_type(mconfig->dev_type);
|
||||
u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type);
|
||||
int ret;
|
||||
|
||||
skl_tplg_fill_dma_id(mconfig, params);
|
||||
|
||||
if (link_type == NHLT_LINK_HDA)
|
||||
return 0;
|
||||
|
||||
*pipe->p_params = *params;
|
||||
ret = skl_tplg_get_pipe_config(skl, mconfig);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
dev_dbg(skl->dev, "%s using pipe config: %d\n", __func__, pipe->cur_config_idx);
|
||||
if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
pipe_fmt = &pipe->configs[pipe->pipe_config_idx].out_fmt;
|
||||
pipe_fmt = &pipe->configs[pipe->cur_config_idx].out_fmt;
|
||||
else
|
||||
pipe_fmt = &pipe->configs[pipe->pipe_config_idx].in_fmt;
|
||||
pipe_fmt = &pipe->configs[pipe->cur_config_idx].in_fmt;
|
||||
|
||||
/* update the blob based on virtual bus_id*/
|
||||
cfg = intel_nhlt_get_endpoint_blob(dai->dev, skl->nhlt,
|
||||
|
@ -1865,10 +1835,15 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai,
|
|||
dev_err(dai->dev, "Blob NULL for id:%d type:%d dirn:%d ch:%d, freq:%d, fmt:%d\n",
|
||||
mconfig->vbus_id, link_type, params->stream,
|
||||
params->ch, params->s_freq, params->s_fmt);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
*pipe->p_params = save;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai,
|
||||
|
|
|
@ -324,7 +324,6 @@ struct skl_pipe {
|
|||
struct skl_path_config configs[SKL_MAX_PATH_CONFIGS];
|
||||
struct list_head w_list;
|
||||
bool passthru;
|
||||
u32 pipe_config_idx;
|
||||
};
|
||||
|
||||
enum skl_module_state {
|
||||
|
|
|
@ -1107,7 +1107,10 @@ static void skl_shutdown(struct pci_dev *pci)
|
|||
if (!skl->init_done)
|
||||
return;
|
||||
|
||||
snd_hdac_stop_streams_and_chip(bus);
|
||||
snd_hdac_stop_streams(bus);
|
||||
snd_hdac_ext_bus_link_power_down_all(bus);
|
||||
skl_dsp_sleep(skl->dsp);
|
||||
|
||||
list_for_each_entry(s, &bus->stream_list, list) {
|
||||
stream = stream_to_hdac_ext_stream(s);
|
||||
snd_hdac_ext_stream_decouple(bus, stream, false);
|
||||
|
|
|
@ -200,14 +200,16 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev)
|
|||
if (!mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) {
|
||||
dev_err(&pdev->dev,
|
||||
"Property 'audio-codec' missing or invalid\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node =
|
||||
of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
|
||||
if (!mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node) {
|
||||
dev_err(&pdev->dev,
|
||||
"Property 'audio-codec' missing or invalid\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
mt8173_rt5650_rt5514_codec_conf[0].dlc.of_node =
|
||||
mt8173_rt5650_rt5514_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;
|
||||
|
@ -216,6 +218,7 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev)
|
|||
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, card);
|
||||
|
||||
out:
|
||||
of_node_put(platform_node);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -677,8 +677,10 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev);
|
||||
if (!card)
|
||||
if (!card) {
|
||||
of_node_put(platform_node);
|
||||
return -EINVAL;
|
||||
}
|
||||
card->dev = &pdev->dev;
|
||||
|
||||
ec_codec = of_parse_phandle(pdev->dev.of_node, "mediatek,ec-codec", 0);
|
||||
|
@ -767,8 +769,10 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
if (!priv) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
snd_soc_card_set_drvdata(card, priv);
|
||||
|
||||
|
@ -776,7 +780,8 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(priv->pinctrl)) {
|
||||
dev_err(&pdev->dev, "%s devm_pinctrl_get failed\n",
|
||||
__func__);
|
||||
return PTR_ERR(priv->pinctrl);
|
||||
ret = PTR_ERR(priv->pinctrl);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < PIN_STATE_MAX; i++) {
|
||||
|
@ -809,6 +814,7 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
|
|||
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, card);
|
||||
|
||||
out:
|
||||
of_node_put(platform_node);
|
||||
of_node_put(ec_codec);
|
||||
of_node_put(hdmi_codec);
|
||||
|
|
|
@ -431,6 +431,7 @@ static int rockchip_pdm_runtime_resume(struct device *dev)
|
|||
|
||||
ret = clk_prepare_enable(pdm->hclk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(pdm->clk);
|
||||
dev_err(pdm->dev, "hclock enable failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -709,8 +709,17 @@ static int soc_pcm_clean(struct snd_soc_pcm_runtime *rtd,
|
|||
|
||||
snd_soc_dpcm_mutex_assert_held(rtd);
|
||||
|
||||
if (!rollback)
|
||||
if (!rollback) {
|
||||
snd_soc_runtime_deactivate(rtd, substream->stream);
|
||||
/* clear the corresponding DAIs parameters when going to be inactive */
|
||||
for_each_rtd_dais(rtd, i, dai) {
|
||||
if (snd_soc_dai_active(dai) == 0)
|
||||
soc_pcm_set_dai_params(dai, NULL);
|
||||
|
||||
if (snd_soc_dai_stream_active(dai, substream->stream) == 0)
|
||||
snd_soc_dai_digital_mute(dai, 1, substream->stream);
|
||||
}
|
||||
}
|
||||
|
||||
for_each_rtd_dais(rtd, i, dai)
|
||||
snd_soc_dai_shutdown(dai, substream, rollback);
|
||||
|
@ -940,15 +949,6 @@ static int soc_pcm_hw_clean(struct snd_soc_pcm_runtime *rtd,
|
|||
|
||||
snd_soc_dpcm_mutex_assert_held(rtd);
|
||||
|
||||
/* clear the corresponding DAIs parameters when going to be inactive */
|
||||
for_each_rtd_dais(rtd, i, dai) {
|
||||
if (snd_soc_dai_active(dai) == 1)
|
||||
soc_pcm_set_dai_params(dai, NULL);
|
||||
|
||||
if (snd_soc_dai_stream_active(dai, substream->stream) == 1)
|
||||
snd_soc_dai_digital_mute(dai, 1, substream->stream);
|
||||
}
|
||||
|
||||
/* run the stream event */
|
||||
snd_soc_dapm_stream_stop(rtd, substream->stream);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue