ASoC: rockchip: Introduce rockchip utils common API
At the monment, we add utils_get/put_performance for
DMC-DVFS-SCENE policy.
Ref: commit cae65d78f0 ("ASoC: rockchip: i2s-tdm: Add support for FIFO-XRUN detection")
Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
Change-Id: I188e5cfff960aa3679db5c3a8ee847d9c7b685ee
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# ROCKCHIP Platform Support
|
||||
snd-soc-rockchip-objs := rockchip_utils.o
|
||||
snd-soc-rockchip-dlp-objs := rockchip_dlp.o
|
||||
snd-soc-rockchip-dlp-pcm-objs := rockchip_dlp_pcm.o
|
||||
snd-soc-rockchip-i2s-objs := rockchip_i2s.o
|
||||
@@ -17,6 +18,7 @@ snd-soc-rockchip-vad-$(CONFIG_ARM64) += vad_preprocess_arm64.o
|
||||
snd-soc-rockchip-vad-$(CONFIG_ARM) += vad_preprocess_arm.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_SND_SOC_ROCKCHIP) += snd-soc-rockchip.o
|
||||
obj-$(CONFIG_SND_SOC_ROCKCHIP_DLP) += snd-soc-rockchip-dlp.o
|
||||
obj-$(CONFIG_SND_SOC_ROCKCHIP_DLP_PCM) += snd-soc-rockchip-dlp-pcm.o
|
||||
obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-rockchip-i2s.o
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Rockchip Utils API
|
||||
*
|
||||
* Copyright (c) 2023 Rockchip Electronics Co. Ltd.
|
||||
*/
|
||||
|
||||
#include <dt-bindings/soc/rockchip-system-status.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <soc/rockchip/rockchip_dmc.h>
|
||||
#include <soc/rockchip/rockchip-system-status.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
#define DMC_STALL_TIME_US_DEFAULT 100
|
||||
#define TIME_MARGIN_US 20
|
||||
|
||||
static DEFINE_MUTEX(list_mutex);
|
||||
static LIST_HEAD(substream_ref_list);
|
||||
|
||||
struct substream_ref {
|
||||
struct list_head node;
|
||||
struct snd_pcm_substream *substream;
|
||||
};
|
||||
|
||||
static int substream_ref_new(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct substream_ref *ref = NULL;
|
||||
bool found = false;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&list_mutex);
|
||||
list_for_each_entry(ref, &substream_ref_list, node) {
|
||||
if (ref->substream == substream) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
ret = -EEXIST;
|
||||
goto _err_unlock;
|
||||
}
|
||||
|
||||
ref = kzalloc(sizeof(*ref), GFP_KERNEL);
|
||||
if (!ref) {
|
||||
ret = -ENOMEM;
|
||||
goto _err_unlock;
|
||||
}
|
||||
|
||||
ref->substream = substream;
|
||||
|
||||
list_add(&ref->node, &substream_ref_list);
|
||||
|
||||
_err_unlock:
|
||||
mutex_unlock(&list_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool substream_ref_found(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct substream_ref *ref = NULL, *_ref = NULL;
|
||||
bool found = false;
|
||||
|
||||
mutex_lock(&list_mutex);
|
||||
list_for_each_entry_safe(ref, _ref, &substream_ref_list, node) {
|
||||
if (ref->substream == substream) {
|
||||
list_del(&ref->node);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&list_mutex);
|
||||
|
||||
if (found)
|
||||
kfree(ref);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool fifo_bigger_than_stall(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai,
|
||||
int fifo_word)
|
||||
{
|
||||
unsigned int rate = params_rate(params);
|
||||
unsigned int channels = params_channels(params);
|
||||
int width = params_physical_width(params);
|
||||
int fifo_time, stall_time, data_word;
|
||||
|
||||
dev_dbg(dai->dev, "stream[%d]: %px, rate: %u, channels: %u, width: %d\n",
|
||||
substream->stream, substream, rate, channels, width);
|
||||
|
||||
stall_time = rockchip_dmcfreq_get_stall_time_ns() / 1000;
|
||||
if (!stall_time)
|
||||
stall_time = DMC_STALL_TIME_US_DEFAULT;
|
||||
|
||||
stall_time += TIME_MARGIN_US;
|
||||
|
||||
data_word = rate * channels * width / 32;
|
||||
|
||||
if (!fifo_word || !data_word)
|
||||
return true;
|
||||
|
||||
fifo_time = 1000000 * fifo_word / data_word;
|
||||
|
||||
dev_dbg(dai->dev, "data: %d, fifo: %d, fifo time: %d us, stall time: %d us\n",
|
||||
data_word, fifo_word, fifo_time, stall_time);
|
||||
|
||||
return (fifo_time > stall_time);
|
||||
}
|
||||
|
||||
void rockchip_utils_get_performance(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai,
|
||||
int fifo_word)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (fifo_bigger_than_stall(substream, params, dai, fifo_word))
|
||||
return;
|
||||
|
||||
if (substream_ref_new(substream))
|
||||
return;
|
||||
|
||||
dev_dbg(dai->dev, "%s: stream[%d]: %px\n",
|
||||
__func__, substream->stream, substream);
|
||||
|
||||
rockchip_set_system_status(SYS_STATUS_PERFORMANCE);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_utils_get_performance);
|
||||
|
||||
void rockchip_utils_put_performance(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (!substream_ref_found(substream))
|
||||
return;
|
||||
|
||||
dev_dbg(dai->dev, "%s: stream[%d]: %px\n",
|
||||
__func__, substream->stream, substream);
|
||||
|
||||
rockchip_clear_system_status(SYS_STATUS_PERFORMANCE);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_utils_put_performance);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Rockchip Utils API
|
||||
*
|
||||
* Copyright (c) 2023 Rockchip Electronics Co. Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _ROCKCHIP_UTILS_H
|
||||
#define _ROCKCHIP_UTILS_H
|
||||
|
||||
void rockchip_utils_get_performance(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai,
|
||||
int fifo_word);
|
||||
void rockchip_utils_put_performance(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai);
|
||||
|
||||
#endif /* _ROCKCHIP_UTILS_H */
|
||||
Reference in New Issue
Block a user