mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-07 05:45:24 +00:00

In commit32c9c06adb
("ASoC: mediatek: disable buffer pre-allocation") buffer pre-allocation was disabled to accommodate newer platforms that have a limited reserved memory region for the audio frontend. Turns out disabling pre-allocation across the board impacts platforms that don't have this reserved memory region. Buffer allocation failures have been observed on MT8173 and MT8183 based Chromebooks under low memory conditions, which results in no audio playback for the user. Since some MediaTek platforms already have dedicated reserved memory pools for the audio frontend, the plan is to enable this for all of them. This requires device tree changes. As a fallback, reinstate the original policy of pre-allocating audio buffers at probe time of the reserved memory pool cannot be found or used. This patch covers the MT8173, MT8183, MT8186 and MT8192 platforms for now, the reason being that existing MediaTek platform drivers that supported reserved memory were all platforms that mainly supported ChromeOS, and is also the set of devices that I can verify. Fixes:32c9c06adb
("ASoC: mediatek: disable buffer pre-allocation") Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Signed-off-by: Chen-Yu Tsai <wenst@chromium.org> Link: https://patch.msgid.link/20250612074901.4023253-7-wenst@chromium.org Signed-off-by: Mark Brown <broonie@kernel.org>
160 lines
4.3 KiB
C
160 lines
4.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* mtk-afe-platform-driver.c -- Mediatek afe platform driver
|
|
*
|
|
* Copyright (c) 2016 MediaTek Inc.
|
|
* Author: Garlic Tseng <garlic.tseng@mediatek.com>
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <sound/soc.h>
|
|
|
|
#include "mtk-afe-platform-driver.h"
|
|
#include "mtk-base-afe.h"
|
|
|
|
int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe)
|
|
{
|
|
struct mtk_base_afe_dai *dai;
|
|
size_t num_dai_drivers = 0, dai_idx = 0;
|
|
|
|
/* calcualte total dai driver size */
|
|
list_for_each_entry(dai, &afe->sub_dais, list) {
|
|
num_dai_drivers += dai->num_dai_drivers;
|
|
}
|
|
|
|
dev_info(afe->dev, "%s(), num of dai %zd\n", __func__, num_dai_drivers);
|
|
|
|
/* combine sub_dais */
|
|
afe->num_dai_drivers = num_dai_drivers;
|
|
afe->dai_drivers = devm_kcalloc(afe->dev,
|
|
num_dai_drivers,
|
|
sizeof(struct snd_soc_dai_driver),
|
|
GFP_KERNEL);
|
|
if (!afe->dai_drivers)
|
|
return -ENOMEM;
|
|
|
|
list_for_each_entry(dai, &afe->sub_dais, list) {
|
|
/* dai driver */
|
|
memcpy(&afe->dai_drivers[dai_idx],
|
|
dai->dai_drivers,
|
|
dai->num_dai_drivers *
|
|
sizeof(struct snd_soc_dai_driver));
|
|
dai_idx += dai->num_dai_drivers;
|
|
}
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai);
|
|
|
|
int mtk_afe_add_sub_dai_control(struct snd_soc_component *component)
|
|
{
|
|
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
|
|
struct mtk_base_afe_dai *dai;
|
|
|
|
list_for_each_entry(dai, &afe->sub_dais, list) {
|
|
if (dai->controls)
|
|
snd_soc_add_component_controls(component,
|
|
dai->controls,
|
|
dai->num_controls);
|
|
|
|
if (dai->dapm_widgets)
|
|
snd_soc_dapm_new_controls(&component->dapm,
|
|
dai->dapm_widgets,
|
|
dai->num_dapm_widgets);
|
|
}
|
|
/* add routes after all widgets are added */
|
|
list_for_each_entry(dai, &afe->sub_dais, list) {
|
|
if (dai->dapm_routes)
|
|
snd_soc_dapm_add_routes(&component->dapm,
|
|
dai->dapm_routes,
|
|
dai->num_dapm_routes);
|
|
}
|
|
|
|
snd_soc_dapm_new_widgets(component->dapm.card);
|
|
|
|
return 0;
|
|
|
|
}
|
|
EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control);
|
|
|
|
snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component,
|
|
struct snd_pcm_substream *substream)
|
|
{
|
|
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
|
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
|
|
struct mtk_base_afe_memif *memif = &afe->memif[snd_soc_rtd_to_cpu(rtd, 0)->id];
|
|
const struct mtk_base_memif_data *memif_data = memif->data;
|
|
struct regmap *regmap = afe->regmap;
|
|
struct device *dev = afe->dev;
|
|
int reg_ofs_base = memif_data->reg_ofs_base;
|
|
int reg_ofs_cur = memif_data->reg_ofs_cur;
|
|
unsigned int hw_ptr = 0, hw_base = 0;
|
|
int ret, pcm_ptr_bytes;
|
|
|
|
ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr);
|
|
if (ret || hw_ptr == 0) {
|
|
dev_err(dev, "%s hw_ptr err\n", __func__);
|
|
pcm_ptr_bytes = 0;
|
|
goto POINTER_RETURN_FRAMES;
|
|
}
|
|
|
|
ret = regmap_read(regmap, reg_ofs_base, &hw_base);
|
|
if (ret || hw_base == 0) {
|
|
dev_err(dev, "%s hw_ptr err\n", __func__);
|
|
pcm_ptr_bytes = 0;
|
|
goto POINTER_RETURN_FRAMES;
|
|
}
|
|
|
|
pcm_ptr_bytes = hw_ptr - hw_base;
|
|
|
|
POINTER_RETURN_FRAMES:
|
|
return bytes_to_frames(substream->runtime, pcm_ptr_bytes);
|
|
}
|
|
EXPORT_SYMBOL_GPL(mtk_afe_pcm_pointer);
|
|
|
|
int mtk_afe_pcm_new(struct snd_soc_component *component,
|
|
struct snd_soc_pcm_runtime *rtd)
|
|
{
|
|
size_t size;
|
|
struct snd_pcm *pcm = rtd->pcm;
|
|
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
|
|
|
|
size = afe->mtk_afe_hardware->buffer_bytes_max;
|
|
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, afe->dev,
|
|
afe->preallocate_buffers ? size : 0,
|
|
size);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(mtk_afe_pcm_new);
|
|
|
|
static int mtk_afe_component_probe(struct snd_soc_component *component)
|
|
{
|
|
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
|
|
int ret;
|
|
|
|
snd_soc_component_init_regmap(component, afe->regmap);
|
|
|
|
/* If the list was never initialized there are no sub-DAIs */
|
|
if (afe->sub_dais.next && afe->sub_dais.prev) {
|
|
ret = mtk_afe_add_sub_dai_control(component);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
const struct snd_soc_component_driver mtk_afe_pcm_platform = {
|
|
.name = AFE_PCM_NAME,
|
|
.pointer = mtk_afe_pcm_pointer,
|
|
.pcm_construct = mtk_afe_pcm_new,
|
|
.probe = mtk_afe_component_probe,
|
|
};
|
|
EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform);
|
|
|
|
MODULE_DESCRIPTION("Mediatek simple platform driver");
|
|
MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
|
|
MODULE_LICENSE("GPL v2");
|
|
|