kernel-brax3-ubuntu-touch/sound/soc/mediatek/audio_scp/mtk-scp-audio-mem-control.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

359 lines
9.6 KiB
C

// SPDX-License-Identifier: GPL-2.0
//
// mtk-scp-audio-mem-control.c -- Mediatek scp audio memory control
//
// Copyright (c) 2018 MediaTek Inc.
// Author: Zhixiong <Zhixiong.Wang@mediatek.com>
/* platform related header file*/
#include "scp.h"
#include "mtk-scp-audio-mem-control.h"
#include "mtk-scp-audio-pcm.h"
static DEFINE_MUTEX(scp_audio_control_mutex);
static DEFINE_MUTEX(scp_audio_mutex_request_dram);
/*
* gen_pool_create - create a new special memory pool
* @min_alloc_order: log base 2 of number of bytes each bitmap bit represents
* @nid: node id of the node the pool structure should be allocated on, or -1
*/
int scp_aud_gen_pool_create(int min_alloc_order, int nid)
{
int ret = 0;
unsigned long va_start;
size_t va_chunk;
struct gen_pool *genpool;
struct mtk_scp_audio_base *scp_audio = get_scp_audio_base();
struct scp_audio_reserve_mem *scp_audio_rsv_mem = &scp_audio->rsv_mem;
if (min_alloc_order <= 0)
return -1;
genpool = gen_pool_create(MIN_SCP_AUD_SHIFT, -1);
if (!genpool)
return -ENOMEM;
va_start = scp_audio_rsv_mem->va_addr;
va_chunk = scp_audio_rsv_mem->size;
if ((!va_start) || (!va_chunk)) {
ret = -1;
return ret;
}
if (gen_pool_add_virt(genpool, (unsigned long)va_start,
scp_audio_rsv_mem->phy_addr, va_chunk,
-1)) {
pr_warn(
"%s failed to add chunk va_start= 0x%lx va_chunk = %zu\n",
__func__, va_start, va_chunk);
}
scp_audio->genpool = genpool;
pr_info(
"%s success to add chunk va_start= 0x%lx va_chunk = %zu genpool = %p\n",
__func__, va_start, va_chunk, genpool);
//TODO dump_mtk_adsp_gen_pool();
return ret;
}
int mtk_scp_audio_init_mem(void)
{
struct mtk_scp_audio_base *scp_audio = get_scp_audio_base();
struct scp_audio_reserve_mem *scp_audio_rsv_mem = &scp_audio->rsv_mem;
struct scp_aud_task_base *task_base;
unsigned long vaddr;
dma_addr_t paddr;
scp_audio_rsv_mem->phy_addr =
scp_get_reserve_mem_phys(SCP_SPK_MEM_ID);
scp_audio_rsv_mem->va_addr = (unsigned long long)
scp_get_reserve_mem_virt(SCP_SPK_MEM_ID);
scp_audio_rsv_mem->vir_addr =
(unsigned char *)scp_get_reserve_mem_virt(SCP_SPK_MEM_ID);
scp_audio_rsv_mem->size =
scp_get_reserve_mem_size(SCP_SPK_MEM_ID);
if (!scp_audio_rsv_mem->phy_addr) {
pr_err("%s(), scp audio rsv mem phy_addr error\n", __func__);
return -1;
}
if (!scp_audio_rsv_mem->vir_addr) {
pr_err("%s(), scp audio rsv mem vir_addr error\n", __func__);
return -1;
}
if (!scp_audio_rsv_mem->size) {
pr_err("%s(), scp audio rsv mem size error\n", __func__);
return -1;
}
memset_io((void *)scp_audio_rsv_mem->vir_addr, 0, scp_audio_rsv_mem->size);
scp_aud_gen_pool_create(MIN_SCP_AUD_SHIFT, -1);
//init A2D/D2A share mem
task_base = get_taskbase_by_daiid(SCP_AUD_TASK_SPK_PROCESS_ID);
vaddr = gen_pool_alloc(scp_audio->genpool, A2D_SHAREMEM_SIZE);
if (!vaddr) {
pr_err("%s(), alloc ATOD mem vaddr Fail!!!\n", __func__);
return -1;
}
paddr = gen_pool_virt_to_phys(scp_audio->genpool, vaddr);
if (paddr == ((dma_addr_t)-1)) {
pr_err("%s(), alloc ATOD mem paddr Fail!!!\n", __func__);
return -1;
}
task_base->msg_atod_share_buf.phy_addr = paddr;
task_base->msg_atod_share_buf.va_addr = vaddr;
task_base->msg_atod_share_buf.vir_addr = (char *)vaddr;
task_base->msg_atod_share_buf.size = A2D_SHAREMEM_SIZE;
dev_info(scp_audio->dev,
"%s(), a2d mem pa=0x%llx, va=0x%llx, size=0x%llx\n",
__func__,
paddr,
vaddr,
task_base->msg_atod_share_buf.size);
vaddr = gen_pool_alloc(scp_audio->genpool, D2A_SHAREMEM_SIZE);
if (!vaddr) {
pr_err("%s(), alloc DTOA mem vaddr Fail!!!\n", __func__);
return -1;
}
paddr = gen_pool_virt_to_phys(scp_audio->genpool, vaddr);
if (paddr == ((dma_addr_t)-1)) {
pr_err("%s(), alloc DTOA mem paddr Fail!!!\n", __func__);
return -1;
}
task_base->msg_dtoa_share_buf.phy_addr = paddr;
task_base->msg_dtoa_share_buf.va_addr = vaddr;
task_base->msg_dtoa_share_buf.vir_addr = (char *)vaddr;
task_base->msg_dtoa_share_buf.size = D2A_SHAREMEM_SIZE;
dev_info(scp_audio->dev,
"%s(), d2a mem pa=0x%llx, va=0x%llx, size=0x%llx\n",
__func__,
paddr,
vaddr,
task_base->msg_dtoa_share_buf.size);
dev_info(scp_audio->dev,
"%s(), scp reserve mem pa=0x%llx, va=0x%llx, size=0x%llx\n",
__func__,
scp_audio_rsv_mem->phy_addr,
scp_audio_rsv_mem->vir_addr,
scp_audio_rsv_mem->size);
return 0;
}
EXPORT_SYMBOL_GPL(mtk_scp_audio_init_mem);
bool is_scp_genpool_addr_valid(struct snd_pcm_substream *substream)
{
struct mtk_scp_audio_base *scp_audio = get_scp_audio_base();
struct gen_pool *genpool;
if (scp_audio == NULL)
return false;
genpool = scp_audio->genpool;
if (genpool == NULL) {
pr_debug("%s genpool == NULL\n", __func__);
return false;
}
return gen_pool_has_addr(genpool,
(unsigned long)substream->runtime->dma_area,
substream->runtime->dma_bytes);
}
EXPORT_SYMBOL(is_scp_genpool_addr_valid);
int scp_audio_allocate_sharemem_ring(struct scp_aud_task_base *taskbase,
unsigned int size,
struct gen_pool *genpool)
{
struct ringbuf_bridge *buf_bridge;
struct RingBuf *ring_buf;
unsigned long vaddr;
dma_addr_t paddr;
if (genpool == NULL) {
pr_warn("%s genpool == NULL\n", __func__);
return -1;
}
buf_bridge = &(taskbase->share_hw_buf.aud_buffer.buf_bridge);
ring_buf = &taskbase->ring_buf;
/* allocate VA with gen pool */
vaddr = gen_pool_alloc(genpool, size);
if (!vaddr) {
pr_err("%s(), alloc pcm mem vaddr Fail!!!\n", __func__);
return -1;
}
paddr = gen_pool_virt_to_phys(genpool, vaddr);
if (paddr == ((dma_addr_t)-1)) {
pr_err("%s(), alloc pcm mem paddr Fail!!!\n", __func__);
return -1;
}
taskbase->ring_share_buf.phy_addr = paddr;
taskbase->ring_share_buf.va_addr = vaddr;
taskbase->ring_share_buf.vir_addr = (char *)vaddr;
taskbase->ring_share_buf.size = size;
init_ring_buf(ring_buf, (char *)vaddr, size);
init_ring_buf_bridge(buf_bridge, (unsigned long long)paddr, size);
return 0;
}
EXPORT_SYMBOL(scp_audio_allocate_sharemem_ring);
int scp_audio_free_sharemem_ring(struct scp_aud_task_base *taskbase,
struct gen_pool *genpool)
{
struct ringbuf_bridge *buf_bridge;
struct RingBuf *ring_buf;
if (genpool == NULL) {
pr_warn("%s genpool == NULL\n", __func__);
return -1;
}
buf_bridge = &(taskbase->share_hw_buf.aud_buffer.buf_bridge);
ring_buf = &taskbase->ring_buf;
if (ring_buf->pBufBase != NULL) {
gen_pool_free(genpool, (unsigned long)ring_buf->pBufBase,
ring_buf->bufLen);
RingBuf_Bridge_Clear(buf_bridge);
RingBuf_Clear(ring_buf);
} else
pr_info("%s ring_buf->pBufBase = null\n", __func__);
return 0;
}
EXPORT_SYMBOL(scp_audio_free_sharemem_ring);
int mtk_scp_allocate_mem(struct snd_pcm_substream *substream, unsigned int size)
{
struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
int id = asoc_rtd_to_cpu(rtd, 0)->id;
struct mtk_scp_audio_base *scp_audio = get_scp_audio_base();
//struct scp_audio_reserve_mem *scp_audio_rsv_mem = &scp_audio->rsv_mem;
//int buf_offset;
unsigned long vaddr;
dma_addr_t paddr;
if (scp_audio == NULL)
return -1;
if (id != scp_audio->dl_memif &&
id != scp_audio->ul_memif &&
id != scp_audio->ref_memif) {
pr_err("%s(), not match scp audio memif\n", __func__);
return -1;
}
//if (!scp_audio_rsv_mem->phy_addr ||
// !scp_audio_rsv_mem->vir_addr ||
// !scp_audio_rsv_mem->size) {
// pr_err("%s(), scp audio rsv mem error\n");
// return -1;
//}
vaddr = gen_pool_alloc(scp_audio->genpool, size);
if (!vaddr) {
pr_err("%s(), alloc afe mem vaddr Fail!!!\n", __func__);
return -1;
}
paddr = gen_pool_virt_to_phys(scp_audio->genpool, vaddr);
if (paddr == ((dma_addr_t)-1)) {
pr_err("%s(), alloc afe mem paddr Fail!!!\n", __func__);
return -1;
}
dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
dma_buf->dev.dev = substream->pcm->card->dev;
dma_buf->private_data = NULL;
dma_buf->bytes = size;
dma_buf->addr = paddr;
dma_buf->area = (char *)vaddr;
substream->runtime->dma_addr = dma_buf->addr;
substream->runtime->dma_area = dma_buf->area;
dev_info(scp_audio->dev,
"%s(), scp audio VA:0x%p,PA:0x%lx,size:%d,using_sram=0\n",
__func__,
dma_buf->area,
dma_buf->addr,
dma_buf->bytes);
return 0;
}
EXPORT_SYMBOL_GPL(mtk_scp_allocate_mem);
int mtk_scp_free_mem(struct snd_pcm_substream *substream)
{
struct mtk_scp_audio_base *scp_audio = get_scp_audio_base();
unsigned char **vaddr = &substream->runtime->dma_area;
size_t *size = &substream->runtime->dma_bytes;
struct gen_pool *genpool;
if (scp_audio == NULL)
return -1;
genpool = scp_audio->genpool;
if (genpool == NULL) {
pr_warn("%s() genpool == NULL\n", __func__);
return -1;
}
if (!vaddr || !size)
return -EINVAL;
if (!gen_pool_has_addr(genpool, (unsigned long)*vaddr, *size)) {
pr_warn("%s() vaddr is not in genpool\n", __func__);
return -EFAULT;
}
/* allocate VA with gen pool */
if (*vaddr) {
gen_pool_free(genpool, (unsigned long)*vaddr, *size);
*vaddr = NULL;
*size = 0;
}
return 0;
}
EXPORT_SYMBOL_GPL(mtk_scp_free_mem);
/* todo dram ?*/
int scp_audio_dram_request(struct device *dev)
{
struct mtk_scp_audio_base *scp_audio = dev_get_drvdata(dev);
mutex_lock(&scp_audio_mutex_request_dram);
scp_audio->dram_resource_counter++;
mutex_unlock(&scp_audio_mutex_request_dram);
return 0;
}
int scp_audio_dram_release(struct device *dev)
{
struct mtk_scp_audio_base *scp_audio = dev_get_drvdata(dev);
mutex_lock(&scp_audio_mutex_request_dram);
scp_audio->dram_resource_counter--;
if (scp_audio->dram_resource_counter < 0) {
dev_info(dev, "%s(), scp_audio_dram_resource_counter %d\n",
__func__, scp_audio->dram_resource_counter);
scp_audio->dram_resource_counter = 0;
}
mutex_unlock(&scp_audio_mutex_request_dram);
return 0;
}