audiobridge: adapt audiobridge to kernel6.12 [1/1]

PD#SWPL-255895

Problem:
The dsp and mailbox interfaces and some kernel api
in kernel6.12 have changed and need to be re-adapted.

Solution:
Merge from kernel5.15 and adapt to kernel6.6 API.

Verify:
A113X2 AV400 Boards.

Change-Id: I43973edb0b14e4f13bfac5ea257185cda48fb2b7
Signed-off-by: shuai.liu <shuai.liu@amlogic.com>
This commit is contained in:
shuai.liu
2026-02-10 14:31:05 +08:00
committed by gerrit autosubmit
parent 42f5a0bbb7
commit 4b842e4cd3
24 changed files with 613 additions and 243 deletions
@@ -475,6 +475,56 @@
mask = <4>;
};
};
audiobridge {
compatible = "amlogic, audio-bridge";
status = "disabled";
mboxes = <&mbox_fifo A5_REE2DSPA_AUDIO_BRIDGE>;
aml-audio-line,link@0 {
auto-running = <1>;
def-volume = <50>;
isolated = <1>;
src {
/* 0-arm,1-dsp,2-uac */
core = <1>;
/* 0-none,1-tdma,2-tdmb,3-spdif,
* 4-loopback,5-pdmin,6-process
*/
sound-card = <6>;
channels = <4>;
sample-rate = <48000>;
/* 0-s8,1-s16le,7-s32le */
format = <1>;
create-vir-card = <1>;
};
dst {
core = <2>;
sound-card = <0>;
channels = <2>;
sample-rate = <16000>;
format = <1>;
};
};
aml-audio-line,link@1 {
auto-running = <1>;
def-volume = <100>;
isolated = <1>;
src {
core = <2>;
sound-card = <0>;
channels = <2>;
sample-rate = <48000>;
format = <1>;
};
dst {
core = <1>;
sound-card = <2>;
channels = <2>;
sample-rate = <48000>;
format = <1>;
create-vir-card = <1>;
};
};
};
};
&audiobus {
@@ -463,6 +463,56 @@
mask = <4>;
};
};
audiobridge {
compatible = "amlogic, audio-bridge";
status = "disabled";
mboxes = <&mbox_fifo A5_REE2DSPA_AUDIO_BRIDGE>;
aml-audio-line,link@0 {
auto-running = <1>;
def-volume = <50>;
isolated = <1>;
src {
/* 0-arm,1-dsp,2-uac */
core = <1>;
/* 0-none,1-tdma,2-tdmb,3-spdif,
* 4-loopback,5-pdmin,6-process
*/
sound-card = <6>;
channels = <4>;
sample-rate = <48000>;
/* 0-s8,1-s16le,7-s32le */
format = <1>;
create-vir-card = <1>;
};
dst {
core = <2>;
sound-card = <0>;
channels = <2>;
sample-rate = <16000>;
format = <1>;
};
};
aml-audio-line,link@1 {
auto-running = <1>;
def-volume = <100>;
isolated = <1>;
src {
core = <2>;
sound-card = <0>;
channels = <2>;
sample-rate = <48000>;
format = <1>;
};
dst {
core = <1>;
sound-card = <2>;
channels = <2>;
sample-rate = <48000>;
format = <1>;
create-vir-card = <1>;
};
};
};
};
&audiobus {
@@ -475,6 +475,56 @@
mask = <4>;
};
};
audiobridge {
compatible = "amlogic, audio-bridge";
status = "disabled";
mboxes = <&mbox_fifo A5_REE2DSPA_AUDIO_BRIDGE>;
aml-audio-line,link@0 {
auto-running = <1>;
def-volume = <50>;
isolated = <1>;
src {
/* 0-arm,1-dsp,2-uac */
core = <1>;
/* 0-none,1-tdma,2-tdmb,3-spdif,
* 4-loopback,5-pdmin,6-process
*/
sound-card = <6>;
channels = <4>;
sample-rate = <48000>;
/* 0-s8,1-s16le,7-s32le */
format = <1>;
create-vir-card = <1>;
};
dst {
core = <2>;
sound-card = <0>;
channels = <2>;
sample-rate = <16000>;
format = <1>;
};
};
aml-audio-line,link@1 {
auto-running = <1>;
def-volume = <100>;
isolated = <1>;
src {
core = <2>;
sound-card = <0>;
channels = <2>;
sample-rate = <48000>;
format = <1>;
};
dst {
core = <1>;
sound-card = <2>;
channels = <2>;
sample-rate = <48000>;
format = <1>;
create-vir-card = <1>;
};
};
};
};
&audiobus {
@@ -481,6 +481,56 @@
mask = <4>;
};
};
audiobridge {
compatible = "amlogic, audio-bridge";
status = "disabled";
mboxes = <&mbox_fifo A5_REE2DSPA_AUDIO_BRIDGE>;
aml-audio-line,link@0 {
auto-running = <1>;
def-volume = <50>;
isolated = <1>;
src {
/* 0-arm,1-dsp,2-uac */
core = <1>;
/* 0-none,1-tdma,2-tdmb,3-spdif,
* 4-loopback,5-pdmin,6-process
*/
sound-card = <6>;
channels = <4>;
sample-rate = <48000>;
/* 0-s8,1-s16le,7-s32le */
format = <1>;
create-vir-card = <1>;
};
dst {
core = <2>;
sound-card = <0>;
channels = <2>;
sample-rate = <16000>;
format = <1>;
};
};
aml-audio-line,link@1 {
auto-running = <1>;
def-volume = <100>;
isolated = <1>;
src {
core = <2>;
sound-card = <0>;
channels = <2>;
sample-rate = <48000>;
format = <1>;
};
dst {
core = <1>;
sound-card = <2>;
channels = <2>;
sample-rate = <48000>;
format = <1>;
create-vir-card = <1>;
};
};
};
};
&i2c3 {
+1 -1
View File
@@ -390,7 +390,7 @@
hifidsp0: hifidsp0 {
compatible = "amlogic, hifidsp0";
status = "okay";
startup-position = /bits/ 8 <PURE_SRAM>; /*host dsp start mode : DDR*/
startup-position = /bits/ 8 <PURE_DDR>; /*host dsp start mode : DDR*/
memory-region = <&dsp_fw_reserved>;
reg-names = "base-reg",
"health-reg",
+2 -1
View File
@@ -34,11 +34,12 @@ config AMLOGIC_BRIDGE_HID
config AMLOGIC_BRIDGE_DSP
bool "audio DSP bridge support"
depends on AMLOGIC_AUDIO_BRIDGE && AMLOGIC_HIFI4DSP
depends on AMLOGIC_BREAK_GKI && AMLOGIC_AUDIO_BRIDGE
default n
help
This is the Amlogic.
add dsp audio on bridge.
kernel bridge dsp driver.
support the amlogic dsp bridge.
#endmenu
+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
+2 -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.
*/
#include <linux/init.h>
@@ -22,7 +22,7 @@
#include <linux/of_platform.h>
#include <linux/printk.h>
#include <linux/string.h>
#include <linux/amlogic/arm-smccc.h>
#include <linux/arm-smccc.h>
#include <linux/psci.h>
#include <linux/workqueue.h>
#include <linux/mutex.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
+79 -22
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>
@@ -22,7 +22,7 @@
#include <linux/of_platform.h>
#include <linux/printk.h>
#include <linux/string.h>
#include <linux/amlogic/arm-smccc.h>
#include <linux/arm-smccc.h>
#include <linux/psci.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
@@ -38,13 +38,13 @@
#include <linux/delay.h>
#include <linux/fs.h>
#include "bridge_common.h"
#include "bridge_ringbuffer.h"
#include "ringbuffer.h"
#include "bridge_pcm_hal.h"
#include <linux/amlogic/aml_mbox.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 +108,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 +146,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 * PERIOD_COUNT;
}
static struct audio_pcm_function_t *aml_bridge_parse_of(struct device *dev,
struct device_node *node, char *name)
{
@@ -177,6 +218,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 +226,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)
@@ -301,6 +343,7 @@ static void bridge_control_work(struct work_struct *data)
static int aml_bridge_init(struct device *dev, struct device_node *node, int idx)
{
static struct mbox_chan *mbox_chan;
int ret = 0;
u32 value;
struct audio_pcm_bridge_t *bridge;
@@ -311,27 +354,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;
@@ -345,6 +390,18 @@ static int aml_bridge_init(struct device *dev, struct device_node *node, int idx
ret = -EINVAL;
goto err_init4;
}
if (!mbox_chan)
mbox_chan = aml_mbox_request_channel_byidx(dev, idx);
if (IS_ERR_OR_NULL(mbox_chan)) {
dev_err(dev, "Not find mailbox channel\n");
ret = -EINVAL;
goto err_init4;
}
bridge->audio_cap->mbox_chan = mbox_chan;
bridge->audio_play->mbox_chan = mbox_chan;
ret = of_property_read_u32(node, "isolated", &value);
if (ret >= 0 && value)
bridge->isolated_enable = true;
@@ -383,11 +440,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 +479,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);
@@ -510,10 +567,10 @@ err_probe1:
return ret;
}
static int audio_bridge_remove(struct platform_device *pdev)
static void audio_bridge_remove(struct platform_device *pdev)
{
aml_bridge_free();
return 0;
return;
}
static const struct of_device_id audio_bridge_of_match[] = {
+13 -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 (4096)
#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;
@@ -82,6 +93,7 @@ struct audio_pcm_function_t {
struct kobject *kobj;
struct audio_pcm_function_t *opposite;
struct audio_pcm_bridge_t *audio_bridge;
struct mbox_chan *mbox_chan;
};
struct audio_pcm_bridge_t {
+16 -28
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,
@@ -274,7 +262,7 @@ struct aml_aprocess *aml_aprocess_init(struct device *dev, const char *pcm_name,
sprintf(card->longname, "%s %i", card_name, card->dev->id);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX);
NULL, 0, BUFF_SIZE_MAX);
err = snd_card_register(card);
if (err < 0)
+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_
+167 -73
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>
@@ -22,7 +22,7 @@
#include <linux/of_platform.h>
#include <linux/printk.h>
#include <linux/string.h>
#include <linux/amlogic/arm-smccc.h>
#include <linux/arm-smccc.h>
#include <linux/psci.h>
#include <linux/workqueue.h>
#include <linux/mutex.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 "../host/host.h"
#include "bridge_common.h"
#include <linux/kthread.h>
@@ -43,22 +43,24 @@
#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 SCPI_DSPA 0
#define COREID SCPI_DSPA
#define MBOX_SYNC 2
#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 +74,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 +141,7 @@ 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 (!host_firmware_ready(COREID))
return 0;
if (!cap_pcm || !cap_pcm->private_data) {
@@ -154,7 +157,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->mbox_chan, MBOX_SYNC);
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 +174,7 @@ 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 (!host_firmware_ready(COREID))
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->mbox_chan, MBOX_SYNC);
mutex_unlock(&dsp_pcm->lock);
return len;
@@ -231,8 +233,7 @@ 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 (!host_firmware_ready(COREID))
return 0;
if (!play_pcm || !play_pcm->private_data) {
@@ -258,8 +259,7 @@ 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 (!host_firmware_ready(COREID))
return len;
if (!play_pcm || !play_pcm->private_data) {
@@ -278,6 +278,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,52 +342,67 @@ static int thread_capture(void *data)
unsigned int size;
struct rpc_pcm_config pconfig;
struct buf_info buf;
struct device *dev;
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 (!host_firmware_ready(COREID)) {
if (!dsp_pcm->run_flag || kthread_should_stop())
return -EINVAL;
msleep(100);
}
msleep(100);
dev = host_to_device(COREID);
if (!dev)
return -EINVAL;
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;
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->mbox_chan, MBOX_SYNC);
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->mbox_chan, MBOX_SYNC);
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->mbox_chan, MBOX_SYNC);
if (buf.size) {
dma_sync_single_for_device
(hifi4dsp_p[COERID]->dsp->dev,
(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 && bridge->isolated_enable) {
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->mbox_chan, MBOX_SYNC);
dsp_pcm->run_flag = 0;
return 0;
}
@@ -341,68 +412,78 @@ 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;
struct device *dev;
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 (!host_firmware_ready(COREID)) {
if (!dsp_pcm->run_flag || kthread_should_stop())
return -EINVAL;
msleep(100);
}
msleep(100);
dev = host_to_device(COREID);
if (!dev)
return -EINVAL;
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->mbox_chan, MBOX_SYNC);
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->mbox_chan, MBOX_SYNC);
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, info->mbox_chan, MBOX_SYNC);
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,
(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->mbox_chan, MBOX_SYNC);
}
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->mbox_chan, MBOX_SYNC);
dsp_pcm->run_flag = 0;
return 0;
}
@@ -411,6 +492,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 +513,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 +551,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 +592,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 +680,13 @@ 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 (!host_firmware_ready(COREID))
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, audio_pcm->mbox_chan, MBOX_SYNC);
mutex_unlock(&dsp_pcm->lock);
}
@@ -615,8 +709,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 +729,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);
+2 -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.
*/
#include <linux/init.h>
@@ -22,7 +22,7 @@
#include <linux/of_platform.h>
#include <linux/printk.h>
#include <linux/string.h>
#include <linux/amlogic/arm-smccc.h>
#include <linux/arm-smccc.h>
#include <linux/psci.h>
#include <linux/workqueue.h>
#include <linux/mutex.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
+10 -7
View File
@@ -22,7 +22,7 @@
#include <linux/of_platform.h>
#include <linux/printk.h>
#include <linux/string.h>
#include <linux/amlogic/arm-smccc.h>
#include <linux/arm-smccc.h>
#include <linux/psci.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
@@ -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 {
@@ -187,7 +187,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)
@@ -202,7 +202,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)
@@ -220,7 +220,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)
@@ -238,7 +238,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)
@@ -350,9 +350,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
+50 -44
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,18 +9,21 @@
#include <linux/amlogic/scpi_protocol.h>
#include <linux/dev_printk.h>
#include "dsp_client_api.h"
#include "bridge_common.h"
#include <linux/amlogic/aml_mbox.h>
int Mbox_invoke(struct device *dev, u32 dspid, int cmd, void *data, u32 len)
int Mbox_invoke(struct mbox_chan *chan, u32 sync, int cmd, void *data, u32 len)
{
int ret = 0;
ret = mbox_message_send_data_sync(dev, cmd, data, len, dspid);
ret = aml_mbox_transfer_data(chan, cmd, data, len, data, len, sync);
if (ret < 0)
dev_err(dev, "Mbox invoke write error: %d\n", ret);
pr_err("Mbox invoke write error: %d\n", ret);
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:
@@ -49,7 +52,7 @@ 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)
struct mbox_chan *chan, u32 sync)
{
struct pcm_open_st arg;
struct aml_pcm_ctx *p_aml_pcm_ctx = kmalloc(sizeof(*p_aml_pcm_ctx), GFP_KERNEL);
@@ -62,7 +65,7 @@ void *pcm_client_open(u32 card, u32 device, u32 flags, struct rpc_pcm_config *co
memcpy(&arg.pcm_config, config, sizeof(struct rpc_pcm_config));
arg.out_pcm = 0;
Mbox_invoke(dev, dspid, MBX_TINYALSA_OPEN, &arg, sizeof(arg));
Mbox_invoke(chan, sync, MBX_TINYALSA_OPEN, &arg, sizeof(arg));
if (!arg.out_pcm) {
kfree(p_aml_pcm_ctx);
return NULL;
@@ -72,7 +75,7 @@ void *pcm_client_open(u32 card, u32 device, u32 flags, struct rpc_pcm_config *co
return p_aml_pcm_ctx;
}
int pcm_client_close(void *hdl, struct device *dev, u32 dspid)
int pcm_client_close(void *hdl, struct mbox_chan *chan, u32 sync)
{
struct pcm_close_st arg;
struct aml_pcm_ctx *p_aml_pcm_ctx = (struct aml_pcm_ctx *)hdl;
@@ -81,14 +84,14 @@ int pcm_client_close(void *hdl, struct device *dev, u32 dspid)
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
arg.out_ret = -EINVAL;
Mbox_invoke(dev, dspid, MBX_TINYALSA_CLOSE, &arg, sizeof(arg));
Mbox_invoke(chan, sync, 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 mbox_chan *chan, u32 sync)
{
struct pcm_io_st arg;
struct aml_pcm_ctx *p_aml_pcm_ctx = (struct aml_pcm_ctx *)hdl;
@@ -99,13 +102,13 @@ int pcm_client_writei(void *hdl, const phys_addr_t data, u32 count,
arg.count = count;
arg.out_ret = 0;
Mbox_invoke(dev, dspid, MBX_TINYALSA_WRITEI, &arg, sizeof(arg));
Mbox_invoke(chan, sync, 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)
u32 bypass, struct mbox_chan *chan, u32 sync)
{
struct pcm_process_io_st arg;
struct aml_pcm_ctx *p_aml_pcm_ctx = (struct aml_pcm_ctx *)hdl;
@@ -117,13 +120,13 @@ int pcm_process_client_writei_to_speaker(void *hdl, const phys_addr_t data, u32
arg.out_ret = 0;
arg.id = bypass;
Mbox_invoke(dev, dspid, MBX_CMD_APROCESS_WRITE_SPEAKER, &arg, sizeof(arg));
Mbox_invoke(chan, sync, 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 mbox_chan *chan, u32 sync)
{
struct pcm_io_st arg;
struct aml_pcm_ctx *p_aml_pcm_ctx = (struct aml_pcm_ctx *)hdl;
@@ -134,13 +137,13 @@ int pcm_client_readi(void *hdl, const phys_addr_t data, u32 count,
arg.count = count;
arg.out_ret = 0;
Mbox_invoke(dev, dspid, MBX_TINYALSA_READI, &arg, sizeof(arg));
Mbox_invoke(chan, sync, 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 rpc_pcm_config *config, struct mbox_chan *chan, u32 sync)
{
struct pcm_process_open_st arg;
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = kmalloc(sizeof(*p_aml_pcm_ctx), GFP_KERNEL);
@@ -153,7 +156,7 @@ void *pcm_process_client_open(u32 card, u32 device, u32 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));
Mbox_invoke(chan, sync, MBX_CMD_APROCESS_OPEN, &arg, sizeof(arg));
if (!arg.out_pcm) {
kfree(p_aml_pcm_ctx);
return NULL;
@@ -163,7 +166,7 @@ void *pcm_process_client_open(u32 card, u32 device, u32 flags,
return p_aml_pcm_ctx;
}
int pcm_process_client_close(void *hdl, struct device *dev, u32 dspid)
int pcm_process_client_close(void *hdl, struct mbox_chan *chan, u32 sync)
{
struct pcm_process_close_st arg;
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = (struct aml_pro_pcm_ctx *)hdl;
@@ -172,13 +175,13 @@ int pcm_process_client_close(void *hdl, struct device *dev, u32 dspid)
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
arg.out_ret = -EINVAL;
Mbox_invoke(dev, dspid, MBX_CMD_APROCESS_CLOSE, &arg, sizeof(arg));
Mbox_invoke(chan, sync, 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)
int pcm_process_client_start(void *hdl, struct mbox_chan *chan, u32 sync)
{
struct pcm_process_io_st arg;
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = (struct aml_pro_pcm_ctx *)hdl;
@@ -187,12 +190,12 @@ int pcm_process_client_start(void *hdl, struct device *dev, u32 dspid)
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
arg.out_ret = -EINVAL;
Mbox_invoke(dev, dspid, MBX_CMD_APROCESS_START, &arg, sizeof(arg));
Mbox_invoke(chan, sync, MBX_CMD_APROCESS_START, &arg, sizeof(arg));
return arg.out_ret;
}
int pcm_process_client_stop(void *hdl, struct device *dev, u32 dspid)
int pcm_process_client_stop(void *hdl, struct mbox_chan *chan, u32 sync)
{
struct pcm_process_io_st arg;
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = (struct aml_pro_pcm_ctx *)hdl;
@@ -201,13 +204,13 @@ int pcm_process_client_stop(void *hdl, struct device *dev, u32 dspid)
arg.pcm = p_aml_pcm_ctx->pcm_srv_hdl;
arg.out_ret = -EINVAL;
Mbox_invoke(dev, dspid, MBX_CMD_APROCESS_STOP, &arg, sizeof(arg));
Mbox_invoke(chan, sync, 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)
u32 type, struct mbox_chan *chan, u32 sync)
{
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = (struct aml_pro_pcm_ctx *)hdl;
struct pcm_process_buf_st arg;
@@ -220,7 +223,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 &&
@@ -230,7 +233,7 @@ int pcm_process_client_dqbuf(void *hdl, struct buf_info *buf, struct buf_info *r
else
arg.release_buf_handle = 0;
Mbox_invoke(dev, dspid, CMD_APROCESS_DQBUF, &arg, sizeof(arg));
Mbox_invoke(chan, sync, CMD_APROCESS_DQBUF, &arg, sizeof(arg));
buf->handle = arg.buf_handle;
buf->phyaddr = arg.data;
@@ -243,13 +246,11 @@ int pcm_process_client_dqbuf(void *hdl, struct buf_info *buf, struct buf_info *r
}
int pcm_process_client_qbuf(void *hdl, struct buf_info *buf, u32 type,
struct device *dev, u32 dspid)
struct mbox_chan *chan, u32 sync)
{
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,16 +258,23 @@ 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));
Mbox_invoke(chan, sync, 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;
}
int pcm_process_client_get_volume_gain(void *hdl, int *gain,
int is_out, struct device *dev, u32 dspid)
int is_out, struct mbox_chan *chan, u32 sync)
{
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = (struct aml_pro_pcm_ctx *)hdl;
struct pcm_process_gain_st arg;
@@ -276,7 +284,7 @@ int pcm_process_client_get_volume_gain(void *hdl, int *gain,
arg.is_out = is_out;
arg.out_ret = -EINVAL;
Mbox_invoke(dev, dspid, CMD_APROCESS_GET_GAIN, &arg, sizeof(arg));
Mbox_invoke(chan, sync, CMD_APROCESS_GET_GAIN, &arg, sizeof(arg));
if (!arg.out_ret)
*gain = arg.gain;
@@ -284,7 +292,7 @@ int pcm_process_client_get_volume_gain(void *hdl, int *gain,
}
int pcm_process_client_set_volume_gain(void *hdl, int gain,
int is_out, struct device *dev, u32 dspid)
int is_out, struct mbox_chan *chan, u32 sync)
{
struct aml_pro_pcm_ctx *p_aml_pcm_ctx = (struct aml_pro_pcm_ctx *)hdl;
struct pcm_process_gain_st arg;
@@ -294,13 +302,13 @@ int pcm_process_client_set_volume_gain(void *hdl, int gain,
arg.is_out = is_out;
arg.out_ret = -EINVAL;
Mbox_invoke(dev, dspid, CMD_APROCESS_SET_GAIN, &arg, sizeof(arg));
Mbox_invoke(chan, sync, 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 mbox_chan *chan, u32 sync)
{
struct acodec_shm_alloc_st arg;
@@ -308,43 +316,41 @@ void *aml_dsp_mem_allocate(phys_addr_t *phy, size_t size,
arg.pid = 0;
arg.phy = 0;
Mbox_invoke(dev, dspid, MBX_CMD_SHM_ALLOC, &arg, sizeof(arg));
Mbox_invoke(chan, sync, 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)
void aml_dsp_mem_free(phys_addr_t phy, struct mbox_chan *chan, u32 sync)
{
struct acodec_shm_free_st arg;
arg.phy = (u64)phy;
Mbox_invoke(dev, dspid, MBX_CMD_SHM_FREE, &arg, sizeof(arg));
Mbox_invoke(chan, sync, 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)
struct rpc_pcm_config *config, struct mbox_chan *chan, u32 sync)
{
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);
phandle = pcm_process_client_open(card, device, PCM_IN, config, chan, sync);
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);
phandle = pcm_process_client_open(card, device, PCM_OUT, config, chan, sync);
if (!phandle) {
pr_err("pcm client open fail\n");
return NULL;
+23 -18
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)
@@ -172,6 +174,8 @@ enum LOOPBACK_BUF {
RAWBUF,
};
struct mbox_chan;
struct rpc_pcm_config {
/** The number of channels in a frame */
u32 channels;
@@ -317,33 +321,34 @@ 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);
int pcm_client_close(void *hdl, struct device *dev, u32 dspid);
struct rpc_pcm_config *config, struct mbox_chan *chan, u32 sync);
int pcm_client_close(void *hdl, struct mbox_chan *chan, u32 sync);
int pcm_client_writei(void *hdl, const phys_addr_t data, u32 count,
struct device *dev, u32 dspid);
struct mbox_chan *chan, u32 sync);
int pcm_client_readi(void *hdl, const phys_addr_t data, u32 count,
struct device *dev, u32 dspid);
struct mbox_chan *chan, u32 sync);
int pcm_process_client_writei_to_speaker(void *hdl, const phys_addr_t data, u32 count,
u32 bypass, struct device *dev, u32 dspid);
u32 bypass, struct mbox_chan *chan, u32 sync);
void *pcm_process_client_open(u32 card, u32 device, u32 flags,
struct rpc_pcm_config *config, struct device *dev, u32 dspid);
int pcm_process_client_close(void *hdl, struct device *dev, u32 dspid);
int pcm_process_client_start(void *hdl, struct device *dev, u32 dspid);
int pcm_process_client_stop(void *hdl, struct device *dev, u32 dspid);
struct rpc_pcm_config *config, struct mbox_chan *chan, u32 sync);
int pcm_process_client_close(void *hdl, struct mbox_chan *chan, u32 sync);
int pcm_process_client_start(void *hdl, struct mbox_chan *chan, u32 sync);
int pcm_process_client_stop(void *hdl, struct mbox_chan *chan, u32 sync);
int pcm_process_client_dqbuf(void *hdl, struct buf_info *buf, struct buf_info *release_buf,
u32 type, struct device *dev, u32 dspid);
u32 type, struct mbox_chan *chan, u32 sync);
int pcm_process_client_qbuf(void *hdl, struct buf_info *buf, u32 type,
struct device *dev, u32 dspid);
struct mbox_chan *chan, u32 sync);
int pcm_process_client_get_volume_gain(void *hdl, int *gain,
int is_out, struct device *dev, u32 dspid);
int is_out, struct mbox_chan *chan, u32 sync);
int pcm_process_client_set_volume_gain(void *hdl, int gain,
int is_out, struct device *dev, u32 dspid);
void *aml_dsp_mem_allocate(phys_addr_t *phy, size_t size, struct device *dev, u32 dspid);
void aml_dsp_mem_free(phys_addr_t phy, struct device *dev, u32 dspid);
int is_out, struct mbox_chan *chan, u32 sync);
void *aml_dsp_mem_allocate(phys_addr_t *phy, size_t size, struct mbox_chan *chan, u32 sync);
void aml_dsp_mem_free(phys_addr_t phy, struct mbox_chan *chan, u32 sync);
void *audio_device_open(u32 card, u32 device, u32 flags,
struct rpc_pcm_config *config, struct device *dev, u32 dspid);
struct rpc_pcm_config *config, struct mbox_chan *chan, u32 sync);
#endif /*_DSP_CLIENT_API_H*/
@@ -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