mirror of
https://github.com/hardkernel/kernel_common_drivers.git
synced 2026-06-25 12:03:48 +09:00
aa19568bc4
PD#SWPL-114902 Problem: 1.AudioBridge module needs to be added to kernel 5.15. Solution: 1.Makefiles, Kconfig, and code need to be adjusted in AudioBridge. Verify: A113L AD403 Board Change-Id: I47ef1f7c50836c6617969dc2c37d8d340fc15f19 Signed-off-by: wenlong.zhu <wenlong.zhu@amlogic.com>
355 lines
9.0 KiB
C
355 lines
9.0 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/amlogic/scpi_protocol.h>
|
|
#include <linux/dev_printk.h>
|
|
#include "dsp_client_api.h"
|
|
|
|
int Mbox_invoke(struct device *dev, u32 dspid, int cmd, void *data, u32 len)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = mbox_message_send_data_sync(dev, cmd, data, len, dspid);
|
|
if (ret < 0)
|
|
dev_err(dev, "Mbox invoke write error: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
static u32 pcm_client_format_to_bytes(enum DSP_PCM_FORMAT format)
|
|
{
|
|
switch (format) {
|
|
case DSP_PCM_FORMAT_S32_LE:
|
|
case DSP_PCM_FORMAT_S32_BE:
|
|
case DSP_PCM_FORMAT_S24_LE:
|
|
case DSP_PCM_FORMAT_S24_BE:
|
|
return 32 >> 3; /*4 Bytes*/
|
|
case DSP_PCM_FORMAT_S24_3LE:
|
|
case DSP_PCM_FORMAT_S24_3BE:
|
|
return 24 >> 3; /*3 Bytes*/
|
|
default:
|
|
case DSP_PCM_FORMAT_S16_LE:
|
|
case DSP_PCM_FORMAT_S16_BE:
|
|
return 16 >> 3; /*2 Bytes*/
|
|
case DSP_PCM_FORMAT_S8:
|
|
return 8 >> 3; /*1 Bytes*/
|
|
};
|
|
}
|
|
|
|
u32 pcm_client_frame_to_bytes(void *hdl, u32 frame)
|
|
{
|
|
struct aml_pcm_ctx *p_aml_pcm_ctx = (struct aml_pcm_ctx *)hdl;
|
|
int bytes_per_sample = pcm_client_format_to_bytes(p_aml_pcm_ctx->config.format);
|
|
|
|
return (frame * bytes_per_sample * (p_aml_pcm_ctx->config.channels));
|
|
}
|
|
|
|
void *pcm_client_open(u32 card, u32 device, u32 flags, struct rpc_pcm_config *config,
|
|
struct device *dev, u32 dspid)
|
|
{
|
|
struct pcm_open_st arg;
|
|
struct aml_pcm_ctx *p_aml_pcm_ctx = kmalloc(sizeof(*p_aml_pcm_ctx), GFP_KERNEL);
|
|
|
|
memset(p_aml_pcm_ctx, 0, sizeof(struct aml_pcm_ctx));
|
|
memset(&arg, 0, sizeof(arg));
|
|
arg.card = card;
|
|
arg.device = device;
|
|
arg.flags = flags;
|
|
memcpy(&arg.pcm_config, config, sizeof(struct rpc_pcm_config));
|
|
arg.out_pcm = 0;
|
|
|
|
Mbox_invoke(dev, dspid, MBX_TINYALSA_OPEN, &arg, sizeof(arg));
|
|
if (!arg.out_pcm) {
|
|
kfree(p_aml_pcm_ctx);
|
|
return NULL;
|
|
}
|
|
p_aml_pcm_ctx->pcm_srv_hdl = arg.out_pcm;
|
|
memcpy(&p_aml_pcm_ctx->config, config, sizeof(struct rpc_pcm_config));
|
|
return p_aml_pcm_ctx;
|
|
}
|
|
|
|
int pcm_client_close(void *hdl, struct device *dev, u32 dspid)
|
|
{
|
|
struct pcm_close_st arg;
|
|
struct aml_pcm_ctx *p_aml_pcm_ctx = (struct aml_pcm_ctx *)hdl;
|
|
|
|
memset(&arg, 0, sizeof(arg));
|
|
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
|
|
arg.out_ret = -EINVAL;
|
|
|
|
Mbox_invoke(dev, dspid, MBX_TINYALSA_CLOSE, &arg, sizeof(arg));
|
|
|
|
kfree(p_aml_pcm_ctx);
|
|
return arg.out_ret;
|
|
}
|
|
|
|
int pcm_client_writei(void *hdl, const phys_addr_t data, u32 count,
|
|
struct device *dev, u32 dspid)
|
|
{
|
|
struct pcm_io_st arg;
|
|
struct aml_pcm_ctx *p_aml_pcm_ctx = (struct aml_pcm_ctx *)hdl;
|
|
|
|
memset(&arg, 0, sizeof(arg));
|
|
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
|
|
arg.data = (u64)data;
|
|
arg.count = count;
|
|
arg.out_ret = 0;
|
|
|
|
Mbox_invoke(dev, dspid, MBX_TINYALSA_WRITEI, &arg, sizeof(arg));
|
|
|
|
return arg.out_ret;
|
|
}
|
|
|
|
int pcm_process_client_writei_to_speaker(void *hdl, const phys_addr_t data, u32 count,
|
|
u32 bypass, struct device *dev, u32 dspid)
|
|
{
|
|
struct pcm_process_io_st arg;
|
|
struct aml_pcm_ctx *p_aml_pcm_ctx = (struct aml_pcm_ctx *)hdl;
|
|
|
|
memset(&arg, 0, sizeof(arg));
|
|
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
|
|
arg.data = (u64)data;
|
|
arg.count = count;
|
|
arg.out_ret = 0;
|
|
arg.id = bypass;
|
|
|
|
Mbox_invoke(dev, dspid, MBX_CMD_APROCESS_WRITE_SPEAKER, &arg, sizeof(arg));
|
|
|
|
return arg.out_ret;
|
|
}
|
|
|
|
int pcm_client_readi(void *hdl, const phys_addr_t data, u32 count,
|
|
struct device *dev, u32 dspid)
|
|
{
|
|
struct pcm_io_st arg;
|
|
struct aml_pcm_ctx *p_aml_pcm_ctx = (struct aml_pcm_ctx *)hdl;
|
|
|
|
memset(&arg, 0, sizeof(arg));
|
|
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
|
|
arg.data = (u64)data;
|
|
arg.count = count;
|
|
arg.out_ret = 0;
|
|
|
|
Mbox_invoke(dev, dspid, MBX_TINYALSA_READI, &arg, sizeof(arg));
|
|
|
|
return arg.out_ret;
|
|
}
|
|
|
|
void *pcm_process_client_open(u32 card, u32 device, u32 flags,
|
|
struct rpc_pcm_config *config, struct device *dev, u32 dspid)
|
|
{
|
|
struct pcm_process_open_st arg;
|
|
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = kmalloc(sizeof(*p_aml_pcm_ctx), GFP_KERNEL);
|
|
|
|
memset(p_aml_pcm_ctx, 0, sizeof(struct aml_pro_pcm_ctx));
|
|
memset(&arg, 0, sizeof(arg));
|
|
arg.card = card;
|
|
arg.device = device;
|
|
arg.flags = flags;
|
|
memcpy(&arg.pcm_config, config, sizeof(struct rpc_pcm_config));
|
|
arg.out_pcm = 0;
|
|
|
|
Mbox_invoke(dev, dspid, MBX_CMD_APROCESS_OPEN, &arg, sizeof(arg));
|
|
if (!arg.out_pcm) {
|
|
kfree(p_aml_pcm_ctx);
|
|
return NULL;
|
|
}
|
|
p_aml_pcm_ctx->pcm_srv_hdl = arg.out_pcm;
|
|
memcpy(&p_aml_pcm_ctx->config, config, sizeof(struct rpc_pcm_config));
|
|
return p_aml_pcm_ctx;
|
|
}
|
|
|
|
int pcm_process_client_close(void *hdl, struct device *dev, u32 dspid)
|
|
{
|
|
struct pcm_process_close_st arg;
|
|
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = (struct aml_pro_pcm_ctx *)hdl;
|
|
|
|
memset(&arg, 0, sizeof(arg));
|
|
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
|
|
arg.out_ret = -EINVAL;
|
|
|
|
Mbox_invoke(dev, dspid, MBX_CMD_APROCESS_CLOSE, &arg, sizeof(arg));
|
|
|
|
kfree(p_aml_pcm_ctx);
|
|
return arg.out_ret;
|
|
}
|
|
|
|
int pcm_process_client_start(void *hdl, struct device *dev, u32 dspid)
|
|
{
|
|
struct pcm_process_io_st arg;
|
|
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = (struct aml_pro_pcm_ctx *)hdl;
|
|
|
|
memset(&arg, 0, sizeof(arg));
|
|
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
|
|
arg.out_ret = -EINVAL;
|
|
|
|
Mbox_invoke(dev, dspid, MBX_CMD_APROCESS_START, &arg, sizeof(arg));
|
|
|
|
return arg.out_ret;
|
|
}
|
|
|
|
int pcm_process_client_stop(void *hdl, struct device *dev, u32 dspid)
|
|
{
|
|
struct pcm_process_io_st arg;
|
|
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = (struct aml_pro_pcm_ctx *)hdl;
|
|
|
|
memset(&arg, 0, sizeof(arg));
|
|
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
|
|
arg.out_ret = -EINVAL;
|
|
|
|
Mbox_invoke(dev, dspid, MBX_CMD_APROCESS_STOP, &arg, sizeof(arg));
|
|
|
|
return arg.out_ret;
|
|
}
|
|
|
|
int pcm_process_client_dqbuf(void *hdl, struct buf_info *buf, struct buf_info *release_buf,
|
|
u32 type, struct device *dev, u32 dspid)
|
|
{
|
|
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = (struct aml_pro_pcm_ctx *)hdl;
|
|
struct pcm_process_buf_st arg;
|
|
|
|
if (type == PROCESSBUF)
|
|
arg.id = 0;
|
|
else
|
|
arg.id = 1;
|
|
|
|
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
|
|
arg.buf_handle = 0;
|
|
arg.data = 0;
|
|
arg.count = 0;
|
|
arg.out_ret = -EINVAL;
|
|
if (release_buf && release_buf->handle &&
|
|
release_buf->phyaddr && release_buf->viraddr &&
|
|
release_buf->size &&
|
|
release_buf->viraddr == __va((phys_addr_t)release_buf->phyaddr))
|
|
arg.release_buf_handle = release_buf->handle;
|
|
else
|
|
arg.release_buf_handle = 0;
|
|
|
|
Mbox_invoke(dev, dspid, CMD_APROCESS_DQBUF, &arg, sizeof(arg));
|
|
|
|
buf->handle = arg.buf_handle;
|
|
buf->phyaddr = arg.data;
|
|
buf->size = arg.count;
|
|
|
|
if (arg.buf_handle)
|
|
buf->viraddr = __va((phys_addr_t)buf->phyaddr);
|
|
|
|
return arg.out_ret;
|
|
}
|
|
|
|
int pcm_process_client_qbuf(void *hdl, struct buf_info *buf, u32 type,
|
|
struct device *dev, u32 dspid)
|
|
{
|
|
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = (struct aml_pro_pcm_ctx *)hdl;
|
|
struct pcm_process_buf_st arg;
|
|
|
|
if (!buf->handle)
|
|
return 0;
|
|
if (type == PROCESSBUF)
|
|
arg.id = 0;
|
|
else
|
|
arg.id = 1;
|
|
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
|
|
arg.buf_handle = buf->handle;
|
|
arg.data = buf->phyaddr;
|
|
arg.count = 0;
|
|
arg.out_ret = -EINVAL;
|
|
|
|
Mbox_invoke(dev, dspid, CMD_APROCESS_QBUF, &arg, sizeof(arg));
|
|
|
|
return arg.out_ret;
|
|
}
|
|
|
|
int pcm_process_client_get_volume_gain(void *hdl, int *gain,
|
|
int is_out, struct device *dev, u32 dspid)
|
|
{
|
|
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = (struct aml_pro_pcm_ctx *)hdl;
|
|
struct pcm_process_gain_st arg;
|
|
|
|
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
|
|
arg.gain = 0;
|
|
arg.is_out = is_out;
|
|
arg.out_ret = -EINVAL;
|
|
|
|
Mbox_invoke(dev, dspid, CMD_APROCESS_GET_GAIN, &arg, sizeof(arg));
|
|
|
|
if (!arg.out_ret)
|
|
*gain = arg.gain;
|
|
return arg.out_ret;
|
|
}
|
|
|
|
int pcm_process_client_set_volume_gain(void *hdl, int gain,
|
|
int is_out, struct device *dev, u32 dspid)
|
|
{
|
|
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = (struct aml_pro_pcm_ctx *)hdl;
|
|
struct pcm_process_gain_st arg;
|
|
|
|
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
|
|
arg.gain = gain;
|
|
arg.is_out = is_out;
|
|
arg.out_ret = -EINVAL;
|
|
|
|
Mbox_invoke(dev, dspid, CMD_APROCESS_SET_GAIN, &arg, sizeof(arg));
|
|
|
|
return arg.out_ret;
|
|
}
|
|
|
|
void *aml_dsp_mem_allocate(phys_addr_t *phy, size_t size,
|
|
struct device *dev, u32 dspid)
|
|
{
|
|
struct acodec_shm_alloc_st arg;
|
|
|
|
arg.size = size;
|
|
arg.pid = 0;
|
|
arg.phy = 0;
|
|
|
|
Mbox_invoke(dev, dspid, MBX_CMD_SHM_ALLOC, &arg, sizeof(arg));
|
|
if (!arg.phy)
|
|
return NULL;
|
|
*phy = (phys_addr_t)arg.phy;
|
|
return __va((phys_addr_t)arg.phy);
|
|
}
|
|
|
|
void aml_dsp_mem_free(phys_addr_t phy, struct device *dev, u32 dspid)
|
|
{
|
|
struct acodec_shm_free_st arg;
|
|
|
|
arg.phy = (u64)phy;
|
|
|
|
Mbox_invoke(dev, dspid, MBX_CMD_SHM_FREE, &arg, sizeof(arg));
|
|
}
|
|
|
|
void *audio_device_open(u32 card, u32 device, u32 flags,
|
|
struct rpc_pcm_config *config, struct device *dev, u32 dspid)
|
|
{
|
|
void *phandle = NULL;
|
|
|
|
if (flags & PCM_IN) {
|
|
config->period_count = 4;
|
|
config->start_threshold = 0;
|
|
config->silence_threshold = 0;
|
|
config->stop_threshold = 0;
|
|
phandle = pcm_process_client_open(card, device, PCM_IN, config, dev, dspid);
|
|
if (!phandle) {
|
|
pr_err("pcm client open fail\n");
|
|
return NULL;
|
|
}
|
|
} else {
|
|
config->period_count = 4;
|
|
config->start_threshold = 0;
|
|
config->silence_threshold = 0;
|
|
config->stop_threshold = 0;
|
|
phandle = pcm_client_open(card, device, PCM_OUT, config, dev, dspid);
|
|
if (!phandle) {
|
|
pr_err("pcm client open fail\n");
|
|
return NULL;
|
|
}
|
|
}
|
|
return phandle;
|
|
}
|