audiobridge: merge from kernel5.4 [1/2]

PD#SWPL-162204

Problem:
The hifi dsp code has been updated, and kernel5.15 needs
to be equipped with a new dsp implementation interface.

Solution:
Merge kernel5.4's audiobridge implementation.

Verify:
A113L AD403 Board.

Change-Id: Ia0e6eb882b0f8b40b1762deb42b641fbf25a4ee8
Signed-off-by: shuai.liu <shuai.liu@amlogic.com>
This commit is contained in:
shuai.liu
2024-03-22 07:06:59 +00:00
committed by gerrit autosubmit
parent 99cc4f1e75
commit a49f76fd0e
18 changed files with 328 additions and 182 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ MODULE_NAME = amlogic-audiobridge
obj-$(CONFIG_AMLOGIC_AUDIO_BRIDGE) = $(MODULE_NAME).o
$(MODULE_NAME)-y += bridge_audio.o \
bridge_ringbuffer.o \
ringbuffer.o \
bridge_pcm_hal.o \
bridge_arm_pcm.o
+1 -1
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#include <linux/init.h>
+1 -1
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#ifndef _BRIDGE_ARM_PCM_H
+62 -19
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#include <linux/init.h>
@@ -38,13 +38,12 @@
#include <linux/delay.h>
#include <linux/fs.h>
#include "bridge_common.h"
#include "bridge_ringbuffer.h"
#include "ringbuffer.h"
#include "bridge_pcm_hal.h"
#define DRIVER_NAME "audio-bridge"
#define PREFIX "aml-audio-line,"
#define RING_BUFFER_SIZE (1024 * 10)
static struct list_head bridge_devs = LIST_HEAD_INIT(bridge_devs);
static ssize_t bridge_enable_show(struct kobject *kobj,
@@ -108,8 +107,8 @@ static ssize_t bridge_ringbuf_show(struct kobject *kobj,
container_of(attr, struct audio_pcm_bridge_t, ringbuf_attr);
if (!bridge)
return sprintf(buf, "%s err\n", attr->attr.name);
return sprintf(buf, "size:%d, use:%d free:%d\n", bridge_ring_buffer_len(bridge->rb),
bridge_ring_buffer_used_len(bridge->rb), bridge_ring_buffer_free_len(bridge->rb));
return sprintf(buf, "size:%d, use:%d free:%d\n", ring_buffer_len(bridge->rb),
ring_buffer_used_len(bridge->rb), ring_buffer_free_len(bridge->rb));
}
static ssize_t bridge_isolated_show(struct kobject *kobj,
@@ -146,6 +145,47 @@ static ssize_t bridge_isolated_store(struct kobject *kobj,
return len;
}
static int aml_bridge_pcm_format2bytes(enum PCM_FORMAT format)
{
int format_bytes = 0;
switch (format) {
case PCM_FORMAT_S8:
format_bytes = 1;
break;
case PCM_FORMAT_S16_LE:
case PCM_FORMAT_S16_BE:
format_bytes = 2;
break;
case PCM_FORMAT_S24_3LE:
case PCM_FORMAT_S24_3BE:
format_bytes = 3;
break;
case PCM_FORMAT_S24_LE:
case PCM_FORMAT_S24_BE:
case PCM_FORMAT_S32_LE:
case PCM_FORMAT_S32_BE:
format_bytes = 4;
break;
default:
format_bytes = 2;
}
return format_bytes;
}
static int aml_bridge_calculate_ring_buffer_size(struct audio_pcm_function_t *pcm_function)
{
int format_bytes = 0;
if (!pcm_function)
return -1;
format_bytes = aml_bridge_pcm_format2bytes(pcm_function->format);
return pcm_function->channels * format_bytes * PERIOD_SIZE_MAX;
}
static struct audio_pcm_function_t *aml_bridge_parse_of(struct device *dev,
struct device_node *node, char *name)
{
@@ -177,6 +217,7 @@ static struct audio_pcm_function_t *aml_bridge_parse_of(struct device *dev,
if (enable && audio_p->create_virtual_sound_card)
audio_p->create_virtual_sound_card(audio_p);
audio_p->enable_create_card = enable;
audio_p->ring_buffer_size = aml_bridge_calculate_ring_buffer_size(audio_p);
if (!audio_p->set_hw)
goto err_parse1;
@@ -184,9 +225,9 @@ static struct audio_pcm_function_t *aml_bridge_parse_of(struct device *dev,
if (ret < 0)
goto err_parse1;
pr_info("%s [core:%d card:%d] channels:%d rate:%d format:%d create-vir-card:%d\n",
pr_info("%s [core:%d card:%d] channels:%d rate:%d format:%d create virtual card:%d rb size:%d\n",
name, core, card, audio_p->channels,
audio_p->rate, audio_p->format, enable);
audio_p->rate, audio_p->format, enable, audio_p->ring_buffer_size);
return audio_p;
err_parse1:
if (enable && audio_p->destroy_virtual_sound_card)
@@ -311,27 +352,29 @@ static int aml_bridge_init(struct device *dev, struct device_node *node, int idx
goto err_init0;
}
bridge->id = idx;
bridge->rb = bridge_ring_buffer_init(RING_BUFFER_SIZE);
if (!bridge->rb) {
ret = -ENOMEM;
goto err_init1;
}
bridge->audio_cap = aml_bridge_parse_of(dev, node, "src");
if (!bridge->audio_cap) {
ret = -ENOMEM;
goto err_init2;
goto err_init1;
}
bridge->audio_play = aml_bridge_parse_of(dev, node, "dst");
if (!bridge->audio_play) {
ret = -ENOMEM;
goto err_init3;
goto err_init2;
}
if (!bridge->audio_cap->start || !bridge->audio_play->start) {
ret = -EINVAL;
goto err_init4;
goto err_init3;
}
bridge->rb = ring_buffer_init(bridge->audio_cap->ring_buffer_size);
if (!bridge->rb) {
ret = -ENOMEM;
goto err_init3;
}
bridge->audio_cap->rb = bridge->rb;
bridge->audio_play->rb = bridge->rb;
@@ -383,11 +426,11 @@ err_init6:
err_init5:
aml_bridge_destroy_attribute(bridge);
err_init4:
audio_pcm_free(bridge->audio_play);
ring_buffer_release(bridge->rb);
err_init3:
audio_pcm_free(bridge->audio_cap);
audio_pcm_free(bridge->audio_play);
err_init2:
bridge_ring_buffer_release(bridge->rb);
audio_pcm_free(bridge->audio_cap);
err_init1:
vfree(bridge);
err_init0:
@@ -422,7 +465,7 @@ static int aml_bridge_free(void)
cur->audio_play = NULL;
}
if (cur->rb) {
bridge_ring_buffer_release(cur->rb);
ring_buffer_release(cur->rb);
cur->rb = NULL;
}
vfree(cur);
+12 -1
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#ifndef _BRIDGE_COMMON_H
@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/kobject.h>
enum PCM_CORE {
PCM_ARM = 0,
@@ -56,8 +57,18 @@ enum PCM_CONTROL {
#define VOLUME_MAX 100
#define VOLUME_MIN 0
/* dsp use smaller period size for low latency but will cause mailbox will
* communicating too frequently so mailbox should use bigger period size
* arm period size = dsp period size * DSP_PERIOD_SIZE_TO_ARM_PERIOD_SIZE
*/
#define DSP_PERIOD_SIZE_TO_ARM_PERIOD_SIZE (1)
#define PERIOD_SIZE_MAX (2048)
#define PERIOD_COUNT (4)
#define DSP_PERIOD_SIZE (1024)
struct audio_pcm_function_t {
struct ring_buffer *rb;
u32 ring_buffer_size;
enum PCM_CORE coreid;
enum PCM_CARD cardid;
enum PCM_MODE modeid;
+15 -27
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#include <linux/module.h>
@@ -12,25 +12,26 @@
#include <sound/soc.h>
#include "bridge_dsp_card.h"
#define BUFF_SIZE_MAX (PAGE_SIZE * 64)
#define SOUND_CARD_ID 2
/*
* define pcm hardware buffer capability not real size
* support max period bytes size = 8channels * 4bytes * 2048(period size)
* max buffer size = max period size * period count, real size much smaller than this value
**/
#define PRD_SIZE_MAX (PAGE_SIZE * 64)
#define BUFF_SIZE_MAX (PRD_SIZE_MAX * 4)
#define SOUND_CARD_ID (2)
struct aml_aprocess_card *aprocess_card;
unsigned int dsp_pcm_num;
static struct snd_pcm_hardware aml_aprocess_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER
| SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
| SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rate_min = 16000,
.rate_max = 16000,
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.buffer_bytes_max = BUFF_SIZE_MAX,
.period_bytes_max = 1024,
.period_bytes_min = 1024,
.periods_min = 4,
.periods_max = 4,
.fifo_size = 0,
.period_bytes_max = PRD_SIZE_MAX,
.periods_min = BUFF_SIZE_MAX / PRD_SIZE_MAX,
.periods_max = BUFF_SIZE_MAX / PRD_SIZE_MAX,
};
void aml_aprocess_set_hw(struct aml_aprocess *p_aprocess, int channels,
@@ -41,7 +42,7 @@ void aml_aprocess_set_hw(struct aml_aprocess *p_aprocess, int channels,
p_aprocess->g_hw.rate_min = rate;
p_aprocess->g_hw.rate_max = rate;
p_aprocess->g_hw.channels_min = channels;
p_aprocess->g_hw.channels_min = channels;
p_aprocess->g_hw.channels_max = channels;
p_aprocess->g_hw.formats = format;
if (format == SNDRV_PCM_FMTBIT_S8)
p_aprocess->g_hw.period_bytes_min = channels * period;
@@ -51,11 +52,6 @@ void aml_aprocess_set_hw(struct aml_aprocess *p_aprocess, int channels,
p_aprocess->g_hw.period_bytes_min = 4 * channels * period;
else
p_aprocess->g_hw.period_bytes_min = 2 * channels * period;
p_aprocess->g_hw.period_bytes_max = p_aprocess->g_hw.period_bytes_min;
p_aprocess->g_hw.period_bytes_max = p_aprocess->g_hw.period_bytes_min;
p_aprocess->g_hw.buffer_bytes_max = 16 * p_aprocess->g_hw.period_bytes_max;
}
int aml_aprocess_complete(struct aml_aprocess *p_aprocess, char *out, int size)
@@ -90,10 +86,6 @@ int aml_aprocess_complete(struct aml_aprocess *p_aprocess, char *out, int size)
pending = runtime->dma_bytes - hw_ptr;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (!snd_pcm_playback_hw_avail(runtime)) {
snd_pcm_stream_unlock_irqrestore(substream, flags2);
goto fail;
}
if (unlikely(pending < size)) {
memcpy(out, runtime->dma_area + hw_ptr, pending);
memcpy(out + pending, runtime->dma_area,
@@ -103,10 +95,6 @@ int aml_aprocess_complete(struct aml_aprocess *p_aprocess, char *out, int size)
size);
}
} else {
if (!snd_pcm_capture_hw_avail(runtime)) {
snd_pcm_stream_unlock_irqrestore(substream, flags2);
goto fail;
}
if (unlikely(pending < size)) {
memcpy(runtime->dma_area + hw_ptr, out, pending);
memcpy(runtime->dma_area, out + pending,
+1 -1
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#ifndef _BRIDGE_DSP_CARD_H_
+162 -72
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#include <linux/init.h>
@@ -35,7 +35,7 @@
#include <linux/clk.h>
#include <asm/cacheflush.h>
#include <linux/amlogic/scpi_protocol.h>
#include "../hifi4dsp/hifi4dsp_priv.h"
//#include "../hifi4dsp/hifi4dsp_priv.h"
#include "bridge_common.h"
#include <linux/kthread.h>
@@ -43,22 +43,22 @@
#include <linux/delay.h>
#include <linux/fs.h>
#include <sound/pcm.h>
#include <uapi/linux/sched/types.h>
#include <linux/completion.h>
#include "bridge_ringbuffer.h"
#include "ringbuffer.h"
#include "dsp_client_api.h"
#include "bridge_pcm_hal.h"
#include "bridge_dsp_card.h"
#define COERID SCPI_DSPA
#define COREID SCPI_DSPA
#define DSP_PARAM_CARD 0
#define PCM_PARAM_PERIOD_SIZE 1024
#define LOOPBACK_CHANNELS (2)
#define DSP_PARAM_CARD 2
#define GAIN_MAX 0
#define GAIN_MIN -40
// extern struct hifi4dsp_priv *hifi4dsp_p[HIFI4DSP_MAX_CNT];
struct dsp_pcm_param {
u8 card;
u32 device;
@@ -72,8 +72,10 @@ struct dsp_pcm_t {
void *pcm_handle;
struct device *dev;
struct task_struct *thread_handle;
struct task_struct *aux_thread_handle;
struct dsp_pcm_param pcm_param;
struct mutex lock; /* lock to protect dsp bridge data*/
struct completion complete;
struct aml_aprocess *aprocess;
u8 speaker_process_flag;
u8 run_flag;
@@ -137,8 +139,8 @@ static ssize_t bridge_capture_volume_ctr_show(struct kobject *kobj,
{
struct dsp_pcm_t *dsp_pcm;
if (!hifi4dsp_p[COERID] ||
!hifi4dsp_p[COERID]->dsp || !hifi4dsp_p[COERID]->dsp->dspstarted)
if (!hifi4dsp_p[COREID] ||
!hifi4dsp_p[COREID]->dsp || !hifi4dsp_p[COREID]->dsp->dspstarted)
return 0;
if (!cap_pcm || !cap_pcm->private_data) {
@@ -154,7 +156,7 @@ static ssize_t bridge_capture_volume_ctr_show(struct kobject *kobj,
mutex_lock(&dsp_pcm->lock);
if (dsp_pcm->run_flag && dsp_pcm->pcm_handle)
pcm_process_client_get_volume_gain(dsp_pcm->pcm_handle, &dsp_pcm->db_gain,
PCM_CAPTURE, cap_pcm->dev, COERID);
PCM_CAPTURE, cap_pcm->dev, COREID);
mutex_unlock(&dsp_pcm->lock);
return sprintf(buf,
"Volume: %d\nMuteState: %d\n(Volume-Down:%ld, Volume-Up:%ld, Volume-Mute:%ld)\n",
@@ -171,8 +173,8 @@ static ssize_t bridge_capture_volume_ctr_store(struct kobject *kobj,
if (ret < 0)
pr_err("%s err!", __func__);
if (!hifi4dsp_p[COERID] ||
!hifi4dsp_p[COERID]->dsp || !hifi4dsp_p[COERID]->dsp->dspstarted)
if (!hifi4dsp_p[COREID] ||
!hifi4dsp_p[COREID]->dsp || !hifi4dsp_p[COREID]->dsp->dspstarted)
return len;
if (!cap_pcm || !cap_pcm->private_data) {
@@ -218,7 +220,7 @@ static ssize_t bridge_capture_volume_ctr_store(struct kobject *kobj,
mutex_lock(&dsp_pcm->lock);
if (dsp_pcm->run_flag && dsp_pcm->pcm_handle)
pcm_process_client_set_volume_gain(dsp_pcm->pcm_handle, dsp_pcm->db_gain,
PCM_CAPTURE, cap_pcm->dev, COERID);
PCM_CAPTURE, cap_pcm->dev, COREID);
mutex_unlock(&dsp_pcm->lock);
return len;
@@ -231,8 +233,8 @@ static ssize_t bridge_playback_process_ctr_show(struct kobject *kobj,
{
struct dsp_pcm_t *dsp_pcm;
if (!hifi4dsp_p[COERID] ||
!hifi4dsp_p[COERID]->dsp || !hifi4dsp_p[COERID]->dsp->dspstarted)
if (!hifi4dsp_p[COREID] ||
!hifi4dsp_p[COREID]->dsp || !hifi4dsp_p[COREID]->dsp->dspstarted)
return 0;
if (!play_pcm || !play_pcm->private_data) {
@@ -258,8 +260,8 @@ static ssize_t bridge_playback_process_ctr_store(struct kobject *kobj,
if (ret < 0)
pr_err("%s err!", __func__);
if (!hifi4dsp_p[COERID] ||
!hifi4dsp_p[COERID]->dsp || !hifi4dsp_p[COERID]->dsp->dspstarted)
if (!hifi4dsp_p[COREID] ||
!hifi4dsp_p[COREID]->dsp || !hifi4dsp_p[COREID]->dsp->dspstarted)
return len;
if (!play_pcm || !play_pcm->private_data) {
@@ -278,6 +280,62 @@ static ssize_t bridge_playback_process_ctr_store(struct kobject *kobj,
static struct kobj_attribute attr_bridge_playback_process_ctr =
__ATTR_RW(bridge_playback_process_ctr);
static int thread_capture_complete(void *data)
{
struct audio_pcm_function_t *info = data;
struct dsp_pcm_t *dsp_pcm = (struct dsp_pcm_t *)info->private_data;
struct rpc_pcm_config pconfig;
u32 read_size = 0, expected_sleep_us = 0, real_sleep_us = 0;
u32 wait_timeout = 0;
char *buf = NULL;
pconfig.channels = dsp_pcm->pcm_param.channels;
pconfig.rate = dsp_pcm->pcm_param.rate;
pconfig.format = dsp_pcm->pcm_param.format;
pconfig.period_size = DSP_PERIOD_SIZE;
expected_sleep_us = 1000 * 1000 * pconfig.period_size *
DSP_PERIOD_SIZE_TO_ARM_PERIOD_SIZE / pconfig.rate;
wait_timeout = expected_sleep_us * 5;
/*
* Ensure that the ringbuffer consumption
* speed is greater than the production speed
**/
if (pconfig.period_size < 1024)
real_sleep_us = expected_sleep_us - 300;
else
real_sleep_us = expected_sleep_us * 63 / 64;
read_size = pconfig.period_size * (pconfig.channels - LOOPBACK_CHANNELS) *
pcm_client_format_to_bytes(pconfig.format) *
DSP_PERIOD_SIZE_TO_ARM_PERIOD_SIZE;
buf = vmalloc(read_size);
if (!buf) {
vfree(buf);
pr_err("vmalloc failed\n");
return -1;
}
memset(buf, 0, read_size);
while (dsp_pcm->run_flag && !kthread_should_stop()) {
if (!wait_for_completion_timeout(&dsp_pcm->complete,
usecs_to_jiffies(wait_timeout)))
continue;
if (!no_thread_safe_ring_buffer_get(info->rb, buf, read_size)) {
usleep_range(expected_sleep_us / 2, expected_sleep_us);
} else {
aml_aprocess_complete(dsp_pcm->aprocess, buf, read_size);
usleep_range(real_sleep_us - 200, real_sleep_us);
}
}
vfree(buf);
return 0;
}
static int thread_capture(void *data)
{
struct audio_pcm_function_t *info = (struct audio_pcm_function_t *)data;
@@ -286,13 +344,14 @@ static int thread_capture(void *data)
unsigned int size;
struct rpc_pcm_config pconfig;
struct buf_info buf;
u32 read_size = 0, sleep_us = 0;
if (!info || !info->private_data)
return -EINVAL;
dsp_pcm = (struct dsp_pcm_t *)info->private_data;
while (!hifi4dsp_p[COERID] || !hifi4dsp_p[COERID]->dsp ||
!hifi4dsp_p[COERID]->dsp->dspstarted) {
while (!hifi4dsp_p[COREID] || !hifi4dsp_p[COREID]->dsp ||
!hifi4dsp_p[COREID]->dsp->dspstarted) {
if (!dsp_pcm->run_flag || kthread_should_stop())
return -EINVAL;
msleep(100);
@@ -302,36 +361,47 @@ static int thread_capture(void *data)
pconfig.channels = dsp_pcm->pcm_param.channels;
pconfig.rate = dsp_pcm->pcm_param.rate;
pconfig.format = dsp_pcm->pcm_param.format;
pconfig.period_size = dsp_pcm->pcm_param.period_size;
pconfig.period_size = DSP_PERIOD_SIZE;
pconfig.period_count = PERIOD_COUNT;
sleep_us = 1000 * 1000 * pconfig.period_size *
DSP_PERIOD_SIZE_TO_ARM_PERIOD_SIZE / pconfig.rate / 3;
read_size = pconfig.period_size * (pconfig.channels - LOOPBACK_CHANNELS) *
pcm_client_format_to_bytes(pconfig.format) *
DSP_PERIOD_SIZE_TO_ARM_PERIOD_SIZE;
dsp_pcm->pcm_handle = audio_device_open(dsp_pcm->pcm_param.card,
dsp_pcm->pcm_param.device,
PCM_IN, &pconfig, info->dev, COERID);
PCM_IN, &pconfig, info->dev, COREID);
if (!dsp_pcm->pcm_handle) {
pr_err("can't open lbpcm device!\n");
pr_err("can't open libpcm device!\n");
return -ENXIO;
}
pcm_process_client_set_volume_gain(dsp_pcm->pcm_handle, dsp_pcm->db_gain,
PCM_CAPTURE, info->dev, COERID);
PCM_CAPTURE, info->dev, COREID);
while (dsp_pcm->run_flag && !kthread_should_stop()) {
buf.size = read_size;
size = pcm_process_client_dqbuf(dsp_pcm->pcm_handle, &buf, &buf,
PROCESSBUF, info->dev, COERID);
PROCESSBUF, info->dev, COREID);
if (buf.size) {
dma_sync_single_for_device
(hifi4dsp_p[COERID]->dsp->dev,
(hifi4dsp_p[COREID]->dsp->dev,
(phys_addr_t)buf.phyaddr,
buf.size,
DMA_FROM_DEVICE);
aml_aprocess_complete(dsp_pcm->aprocess, buf.viraddr, buf.size);
if (dsp_pcm->aprocess->status) {
no_thread_safe_ring_buffer_put(info->rb, buf.viraddr, buf.size);
complete(&dsp_pcm->complete);
//aml_aprocess_complete(dsp_pcm->aprocess, buf.viraddr, buf.size);
}
if (!bridge->isolated_enable)
bridge_ring_buffer_put(info->rb, buf.viraddr, buf.size);
no_thread_safe_ring_buffer_put(info->rb, buf.viraddr, buf.size);
} else {
usleep_range(0, 5000);
usleep_range(sleep_us, sleep_us * 2);
}
}
pcm_process_client_close(dsp_pcm->pcm_handle, info->dev, COERID);
pcm_process_client_close(dsp_pcm->pcm_handle, info->dev, COREID);
dsp_pcm->run_flag = 0;
return 0;
}
@@ -341,68 +411,74 @@ static int thread_playback(void *data)
struct audio_pcm_function_t *info = (struct audio_pcm_function_t *)data;
struct audio_pcm_bridge_t *bridge = info->audio_bridge;
struct dsp_pcm_t *dsp_pcm;
u32 size_one_shot;
phys_addr_t shmm_phy = 0;
void *shmm_vir = NULL;
struct rpc_pcm_config pconfig;
struct buf_info buf;
u32 send_size = 0, sleep_us = 0;
if (!info || !info->private_data)
return -EINVAL;
dsp_pcm = (struct dsp_pcm_t *)info->private_data;
while (!hifi4dsp_p[COERID] || !hifi4dsp_p[COERID]->dsp ||
!hifi4dsp_p[COERID]->dsp->dspstarted) {
while (!hifi4dsp_p[COREID] || !hifi4dsp_p[COREID]->dsp ||
!hifi4dsp_p[COREID]->dsp->dspstarted) {
if (!dsp_pcm->run_flag || kthread_should_stop())
return -EINVAL;
msleep(100);
}
msleep(100);
memset(&buf, 0, sizeof(buf));
pconfig.channels = dsp_pcm->pcm_param.channels;
pconfig.rate = dsp_pcm->pcm_param.rate;
pconfig.format = dsp_pcm->pcm_param.format;
pconfig.period_size = dsp_pcm->pcm_param.period_size;
pconfig.period_size = DSP_PERIOD_SIZE;
pconfig.period_count = PERIOD_COUNT;
send_size = pconfig.period_size * pconfig.channels *
pcm_client_format_to_bytes(pconfig.format) * DSP_PERIOD_SIZE_TO_ARM_PERIOD_SIZE;
buf.size = send_size;
sleep_us = 1000 * 1000 * pconfig.period_size *
DSP_PERIOD_SIZE_TO_ARM_PERIOD_SIZE / pconfig.rate / 3;
pr_info("open playback device!\n");
dsp_pcm->pcm_handle = audio_device_open(dsp_pcm->pcm_param.card,
dsp_pcm->pcm_param.device,
PCM_OUT, &pconfig, info->dev, COERID);
PCM_OUT, &pconfig, info->dev, COREID);
if (!dsp_pcm->pcm_handle) {
pr_err("can't open playback device!\n");
return -ENXIO;
}
pr_info("malloc share mm!\n");
size_one_shot = pcm_client_frame_to_bytes(dsp_pcm->pcm_handle, pconfig.period_size);
shmm_vir = aml_dsp_mem_allocate(&shmm_phy, size_one_shot, info->dev, COERID);
if (!shmm_vir || !shmm_phy) {
pcm_client_close(dsp_pcm->pcm_handle, info->dev, COERID);
pr_err("can't malloc share memory---size:%d!\n", size_one_shot);
return -ENOMEM;
}
bridge_ring_buffer_go_empty(info->rb);
pr_info("get share mm!\n");
/* first call qbuf for get ready buffer address */
pcm_process_client_qbuf(dsp_pcm->pcm_handle, &buf,
RAWBUF, info->dev, COREID);
ring_buffer_go_empty(info->rb);
pcm_process_client_set_volume_gain(dsp_pcm->pcm_handle, dsp_pcm->db_gain,
PCM_PLAYBACK, dsp_pcm->dev, COERID);
PCM_PLAYBACK, dsp_pcm->dev, COREID);
while (dsp_pcm->run_flag && !kthread_should_stop()) {
if (bridge->isolated_enable) {
if (!aml_aprocess_complete(dsp_pcm->aprocess, shmm_vir, size_one_shot))
memset(shmm_vir, 0, size_one_shot);
if (!dsp_pcm->aprocess->status) {
usleep_range(sleep_us, sleep_us * 2);
continue;
}
if (!aml_aprocess_complete(dsp_pcm->aprocess, buf.viraddr, buf.size)) {
usleep_range(sleep_us, sleep_us * 2);
continue;
}
} else {
if (!bridge_ring_buffer_get(info->rb, shmm_vir, size_one_shot))
memset(shmm_vir, 0, size_one_shot);
if (!no_thread_safe_ring_buffer_get(info->rb, buf.viraddr, buf.size))
memset(buf.viraddr, 0, buf.size);
}
dma_sync_single_for_device
(hifi4dsp_p[COERID]->dsp->dev,
(phys_addr_t)shmm_phy,
size_one_shot,
(hifi4dsp_p[COREID]->dsp->dev,
(phys_addr_t)buf.phyaddr,
buf.size,
DMA_TO_DEVICE);
pcm_process_client_writei_to_speaker(dsp_pcm->pcm_handle, shmm_phy,
pconfig.period_size, !dsp_pcm->speaker_process_flag,
info->dev, COERID);
buf.size = send_size;
pcm_process_client_qbuf(dsp_pcm->pcm_handle, &buf,
RAWBUF, info->dev, COREID);
}
pcm_client_close(dsp_pcm->pcm_handle, info->dev, COERID);
aml_dsp_mem_free(shmm_phy, info->dev, COERID);
shmm_phy = 0;
shmm_vir = NULL;
pcm_process_client_close(dsp_pcm->pcm_handle, info->dev, COREID);
dsp_pcm->run_flag = 0;
return 0;
}
@@ -411,6 +487,7 @@ static int dsp_pcm_start(struct audio_pcm_function_t *audio_pcm)
{
int rc = 0;
struct dsp_pcm_t *dsp_pcm;
struct sched_param param = { .sched_priority = 99 };
if (!audio_pcm || !audio_pcm->private_data) {
pr_err("the bridge info is NULL!\n");
@@ -431,10 +508,18 @@ static int dsp_pcm_start(struct audio_pcm_function_t *audio_pcm)
}
dsp_pcm->run_flag = 1;
if (audio_pcm->modeid == PCM_CAPTURE)
if (audio_pcm->modeid == PCM_CAPTURE) {
dsp_pcm->thread_handle = kthread_run(thread_capture, audio_pcm, "dsp_cap");
else
dsp_pcm->aux_thread_handle = kthread_run(thread_capture_complete,
audio_pcm, "dsp_cap_complete");
sched_setscheduler(dsp_pcm->thread_handle, SCHED_FIFO, &param);
sched_setscheduler(dsp_pcm->aux_thread_handle, SCHED_FIFO, &param);
} else {
dsp_pcm->thread_handle = kthread_run(thread_playback, audio_pcm, "dsp_play");
dsp_pcm->aux_thread_handle = NULL;
sched_setscheduler(dsp_pcm->thread_handle, SCHED_FIFO, &param);
}
if (IS_ERR(dsp_pcm->thread_handle)) {
dsp_pcm->thread_handle = NULL;
dsp_pcm->run_flag = 0;
@@ -461,6 +546,10 @@ static int dsp_pcm_stop(struct audio_pcm_function_t *audio_pcm)
mutex_lock(&dsp_pcm->lock);
dsp_pcm->run_flag = 0;
if (dsp_pcm->aux_thread_handle) {
kthread_stop(dsp_pcm->aux_thread_handle);
dsp_pcm->aux_thread_handle = NULL;
}
if (dsp_pcm->thread_handle) {
kthread_stop(dsp_pcm->thread_handle);
dsp_pcm->thread_handle = NULL;
@@ -498,12 +587,13 @@ static int dsp_pcm_set_hw(struct audio_pcm_function_t *audio_pcm, u8 channels, u
alsa_format = SNDRV_PCM_FMTBIT_S16;
break;
}
if (audio_pcm->modeid == PCM_CAPTURE)
aml_aprocess_set_hw(dsp_pcm->aprocess, (channels - 2),
alsa_format, 16000, PCM_PARAM_PERIOD_SIZE);
aml_aprocess_set_hw(dsp_pcm->aprocess, (channels - LOOPBACK_CHANNELS),
alsa_format, rate, DSP_PERIOD_SIZE * DSP_PERIOD_SIZE_TO_ARM_PERIOD_SIZE);
else
aml_aprocess_set_hw(dsp_pcm->aprocess, channels,
alsa_format, rate, PCM_PARAM_PERIOD_SIZE);
alsa_format, rate, DSP_PERIOD_SIZE * DSP_PERIOD_SIZE_TO_ARM_PERIOD_SIZE);
return 0;
}
@@ -585,14 +675,14 @@ static void dsp_pcm_control(struct audio_pcm_function_t *audio_pcm, int cmd, int
dsp_pcm->db_gain = -48;
}
if (!hifi4dsp_p[COERID] ||
!hifi4dsp_p[COERID]->dsp || !hifi4dsp_p[COERID]->dsp->dspstarted)
if (!hifi4dsp_p[COREID] ||
!hifi4dsp_p[COREID]->dsp || !hifi4dsp_p[COREID]->dsp->dspstarted)
return;
mutex_lock(&dsp_pcm->lock);
if (dsp_pcm->run_flag && dsp_pcm->pcm_handle)
pcm_process_client_set_volume_gain(dsp_pcm->pcm_handle, dsp_pcm->db_gain,
audio_pcm->modeid, dsp_pcm->dev, COERID);
audio_pcm->modeid, dsp_pcm->dev, COREID);
mutex_unlock(&dsp_pcm->lock);
}
@@ -615,8 +705,7 @@ int dsp_pcm_init(struct audio_pcm_function_t *audio_pcm,
return -EINVAL;
}
dsp_pcm->dev = audio_pcm->dev;
dsp_pcm->pcm_param.card = DSP_PARAM_CARD;
dsp_pcm->pcm_param.period_size = PCM_PARAM_PERIOD_SIZE;
dsp_pcm->pcm_param.card = pcm_card;
dsp_pcm->volume = VOLUME_MAX;
dsp_pcm->mute = 0;
dsp_pcm->db_gain = dsp_pcm->volume * (GAIN_MAX - GAIN_MIN) /
@@ -636,6 +725,7 @@ int dsp_pcm_init(struct audio_pcm_function_t *audio_pcm,
else
play_pcm = audio_pcm;
mutex_init(&dsp_pcm->lock);
init_completion(&dsp_pcm->complete);
return 0;
}
+2 -2
View File
@@ -1,12 +1,12 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#ifndef _BRIDGE_DSP_PCM_H
#define _BRIDGE_DSP_PCM_H
#include "bridge_common.h"
#include "bridge_ringbuffer.h"
#include "ringbuffer.h"
int dsp_pcm_init(struct audio_pcm_function_t *audio_pcm,
enum PCM_CARD pcm_card, enum PCM_MODE mode);
+1 -1
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#include <linux/init.h>
+1 -1
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#ifndef _BRIDGE_PCM_HAL_H
-26
View File
@@ -1,26 +0,0 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#ifndef _USER_BRIDGE_RING_BUFFER_H
#define _USER_BRIDGE_RING_BUFFER_H
struct ring_buffer {
void *buffer;
u32 size;
u32 in;
u32 out;
u8 go_empty;
};
struct ring_buffer *bridge_ring_buffer_init(u32 size);
int bridge_ring_buffer_release(struct ring_buffer *ring_buf);
u32 bridge_ring_buffer_len(const struct ring_buffer *ring_buf);
u32 bridge_ring_buffer_used_len(const struct ring_buffer *ring_buf);
u32 bridge_ring_buffer_free_len(const struct ring_buffer *ring_buf);
u32 bridge_ring_buffer_get(struct ring_buffer *ring_buf, void *buffer, u32 size);
u32 bridge_ring_buffer_put(struct ring_buffer *ring_buf, void *buffer, u32 size);
u32 bridge_ring_buffer_go_empty(struct ring_buffer *ring_buf);
#endif
+9 -6
View File
@@ -42,7 +42,7 @@
#endif
#include "bridge_common.h"
#include "bridge_ringbuffer.h"
#include "ringbuffer.h"
#include "bridge_pcm_hal.h"
struct uac_pcm_t {
@@ -199,7 +199,7 @@ int uac_pcm_start_playback(void)
return 0;
uac_pcm->uac_status = 1;
return bridge_ring_buffer_go_empty(audio_pcm->rb);
return ring_buffer_go_empty(audio_pcm->rb);
}
int uac_pcm_stop_playback(void)
@@ -214,7 +214,7 @@ int uac_pcm_stop_playback(void)
return 0;
uac_pcm->uac_status = 0;
return bridge_ring_buffer_go_empty(audio_pcm->rb);
return ring_buffer_go_empty(audio_pcm->rb);
}
int uac_pcm_write_data(char *buf, unsigned int size)
@@ -232,7 +232,7 @@ int uac_pcm_write_data(char *buf, unsigned int size)
if (bridge->isolated_enable)
return 0;
else
return bridge_ring_buffer_put(audio_pcm->rb, buf, size);
return no_thread_safe_ring_buffer_put(audio_pcm->rb, buf, size);
}
int uac_pcm_read_data(char *buf, unsigned int size)
@@ -250,7 +250,7 @@ int uac_pcm_read_data(char *buf, unsigned int size)
if (bridge->isolated_enable)
return 0;
else
return bridge_ring_buffer_get(audio_pcm->rb, buf, size);
return no_thread_safe_ring_buffer_get(audio_pcm->rb, buf, size);
}
int uac_pcm_ctl_capture(int cmd, int value)
@@ -362,9 +362,12 @@ static int uac_pcm_set_hw(struct audio_pcm_function_t *audio_pcm,
static int uac_pcm_get_status(struct audio_pcm_function_t *audio_pcm)
{
struct uac_pcm_t *uac_pcm;
struct audio_pcm_bridge_t *bridge;
if (!audio_pcm || !audio_pcm->private_data)
bridge = audio_pcm->audio_bridge;
if (!audio_pcm || !audio_pcm->private_data || bridge->isolated_enable)
return 0;
uac_pcm = audio_pcm->private_data;
return uac_pcm->run_flag;
+1 -1
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#ifndef _BRIDGE_UAC_PCM_H
+13 -9
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#include <linux/types.h>
@@ -9,6 +9,7 @@
#include <linux/amlogic/scpi_protocol.h>
#include <linux/dev_printk.h>
#include "dsp_client_api.h"
#include "bridge_common.h"
int Mbox_invoke(struct device *dev, u32 dspid, int cmd, void *data, u32 len)
{
@@ -20,7 +21,7 @@ int Mbox_invoke(struct device *dev, u32 dspid, int cmd, void *data, u32 len)
return ret;
}
static u32 pcm_client_format_to_bytes(enum DSP_PCM_FORMAT format)
u32 pcm_client_format_to_bytes(enum DSP_PCM_FORMAT format)
{
switch (format) {
case DSP_PCM_FORMAT_S32_LE:
@@ -220,7 +221,7 @@ int pcm_process_client_dqbuf(void *hdl, struct buf_info *buf, struct buf_info *r
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
arg.buf_handle = 0;
arg.data = 0;
arg.count = 0;
arg.count = buf->size;
arg.out_ret = -EINVAL;
if (release_buf && release_buf->handle &&
release_buf->phyaddr && release_buf->viraddr &&
@@ -248,8 +249,6 @@ int pcm_process_client_qbuf(void *hdl, struct buf_info *buf, u32 type,
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
@@ -257,11 +256,18 @@ int pcm_process_client_qbuf(void *hdl, struct buf_info *buf, u32 type,
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
arg.buf_handle = buf->handle;
arg.data = buf->phyaddr;
arg.count = 0;
arg.count = buf->size;
arg.out_ret = -EINVAL;
Mbox_invoke(dev, dspid, CMD_APROCESS_QBUF, &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;
}
@@ -330,7 +336,6 @@ void *audio_device_open(u32 card, u32 device, u32 flags,
void *phandle = NULL;
if (flags & PCM_IN) {
config->period_count = 4;
config->start_threshold = 0;
config->silence_threshold = 0;
config->stop_threshold = 0;
@@ -340,11 +345,10 @@ void *audio_device_open(u32 card, u32 device, u32 flags,
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);
phandle = pcm_process_client_open(card, device, PCM_OUT, config, dev, dspid);
if (!phandle) {
pr_err("pcm client open fail\n");
return NULL;
+5 -2
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#ifndef _DSP_CLIENT_API_H
@@ -12,6 +12,8 @@
#define MBX_TINYALSA 0x2
#define MBX_PIPELINE 0x3
/* 0x20 ~ 0x3F reserved for Customer */
/*sys cmd*/
#define CMD_SHM_ALLOC 0x3
#define CMD_SHM_FREE 0x4
@@ -39,7 +41,7 @@
/*Message composition with module(6bits), function(10bits)*/
#define __MBX_COMPOSE_MSG(mod, func) (((mod) << 10) | ((func) & 0x3FF))
/*Mssage Composition*/
/*Mssage composition*/
#define MBX_CMD_SHM_ALLOC __MBX_COMPOSE_MSG(MBX_SYSTEM, CMD_SHM_ALLOC)
#define MBX_CMD_SHM_FREE __MBX_COMPOSE_MSG(MBX_SYSTEM, CMD_SHM_FREE)
@@ -317,6 +319,7 @@ struct buf_info {
u32 size;
};
u32 pcm_client_format_to_bytes(enum DSP_PCM_FORMAT format);
u32 pcm_client_frame_to_bytes(void *hdl, u32 frame);
void *pcm_client_open(u32 card, u32 device, u32 flags,
struct rpc_pcm_config *config, struct device *dev, u32 dspid);
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <linux/mutex.h>
#include <linux/log2.h>
#include "bridge_ringbuffer.h"
#include "ringbuffer.h"
static u32 roundup_power_of_2(unsigned int a)
{
@@ -23,7 +23,7 @@ static u32 roundup_power_of_2(unsigned int a)
return (u32)(1 << position);
}
struct ring_buffer *bridge_ring_buffer_init(u32 size)
struct ring_buffer *ring_buffer_init(u32 size)
{
char *buf = NULL;
struct ring_buffer *ring_buf = NULL;
@@ -53,7 +53,7 @@ struct ring_buffer *bridge_ring_buffer_init(u32 size)
return ring_buf;
}
int bridge_ring_buffer_release(struct ring_buffer *ring_buf)
int ring_buffer_release(struct ring_buffer *ring_buf)
{
if (ring_buf) {
vfree(ring_buf->buffer);
@@ -103,22 +103,22 @@ static u32 __ring_buffer_put(struct ring_buffer *ring_buf, void *buffer, u32 siz
return size;
}
u32 bridge_ring_buffer_len(const struct ring_buffer *ring_buf)
u32 ring_buffer_len(const struct ring_buffer *ring_buf)
{
return ring_buf->size;
}
u32 bridge_ring_buffer_used_len(const struct ring_buffer *ring_buf)
u32 ring_buffer_used_len(const struct ring_buffer *ring_buf)
{
return __ring_buffer_len(ring_buf);
}
u32 bridge_ring_buffer_free_len(const struct ring_buffer *ring_buf)
u32 ring_buffer_free_len(const struct ring_buffer *ring_buf)
{
return ring_buf->size - __ring_buffer_len(ring_buf);
}
u32 bridge_ring_buffer_get(struct ring_buffer *ring_buf, void *buffer, u32 size)
u32 no_thread_safe_ring_buffer_get(struct ring_buffer *ring_buf, void *buffer, u32 size)
{
u32 ret;
@@ -126,21 +126,25 @@ u32 bridge_ring_buffer_get(struct ring_buffer *ring_buf, void *buffer, u32 size)
ring_buf->go_empty = false;
ring_buf->out = ring_buf->in;
}
if (bridge_ring_buffer_used_len(ring_buf) < size)
if (ring_buffer_used_len(ring_buf) < size)
return 0;
ret = __ring_buffer_get(ring_buf, buffer, size);
return ret;
}
u32 bridge_ring_buffer_put(struct ring_buffer *ring_buf, void *buffer, u32 size)
u32 no_thread_safe_ring_buffer_put(struct ring_buffer *ring_buf, void *buffer, u32 size)
{
u32 ret;
if (ring_buf->go_empty) {
ring_buf->go_empty = false;
ring_buf->in = ring_buf->out;
}
ret = __ring_buffer_put(ring_buf, buffer, size);
return ret;
}
u32 bridge_ring_buffer_go_empty(struct ring_buffer *ring_buf)
u32 ring_buffer_go_empty(struct ring_buffer *ring_buf)
{
ring_buf->go_empty = true;
return 0;
+26
View File
@@ -0,0 +1,26 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2023 Amlogic, Inc. All rights reserved.
*/
#ifndef _USER_RING_BUFFER_H
#define _USER_RING_BUFFER_H
struct ring_buffer {
void *buffer;
u32 size;
u32 in;
u32 out;
u8 go_empty;
};
struct ring_buffer *ring_buffer_init(u32 size);
int ring_buffer_release(struct ring_buffer *ring_buf);
u32 ring_buffer_len(const struct ring_buffer *ring_buf);
u32 ring_buffer_used_len(const struct ring_buffer *ring_buf);
u32 ring_buffer_free_len(const struct ring_buffer *ring_buf);
u32 no_thread_safe_ring_buffer_get(struct ring_buffer *ring_buf, void *buffer, u32 size);
u32 no_thread_safe_ring_buffer_put(struct ring_buffer *ring_buf, void *buffer, u32 size);
u32 ring_buffer_go_empty(struct ring_buffer *ring_buf);
#endif