pcm: introduce pcm_sink

move target-specific pcm operations into builtin_pcm_sink.
in subsequent commits, another pcm_sink is added, and it becomes
possible to switch between them.

Change-Id: I8f8b9661e01d6e6472f34224ddc3760856778457
This commit is contained in:
mojyack 2025-12-17 16:19:07 +09:00
parent 9931781185
commit dfa33c246b
29 changed files with 846 additions and 424 deletions

View file

@ -647,6 +647,7 @@ static const struct plugin_api rockbox_api = {
pcm_apply_settings,
pcm_play_lock,
pcm_play_unlock,
pcm_current_sink_caps,
beep_play,
#ifdef HAVE_RECORDING
&rec_freq_sampr[0],

View file

@ -93,6 +93,7 @@ int plugin_open(const char *plugin, const char *parameter);
#include "misc.h"
#include "pathfuncs.h"
#include "pcm_mixer.h"
#include "pcm_sink.h"
#include "dsp-util.h"
#include "dsp_core.h"
#include "dsp_proc_settings.h"
@ -745,6 +746,7 @@ struct plugin_api {
void (*pcm_apply_settings)(void);
void (*pcm_play_lock)(void);
void (*pcm_play_unlock)(void);
const struct pcm_sink_caps* (*pcm_current_sink_caps)(void);
void (*beep_play)(unsigned int frequency, unsigned int duration,
unsigned int amplitude);
#ifdef HAVE_RECORDING

View file

@ -1783,6 +1783,10 @@ void pcm_play_unlock(void)
\group sound
\description
const struct pcm_sink_caps* pcm_current_sink_caps(enum pcm_sink_ids sink)
\group sound
\description
void pcm_record_data(pcm_rec_callback_type more_ready, pcm_status_callback_type status_cb, void *start, size_t size)
\group sound
\conditions (defined(HAVE_RECORDING))

View file

@ -22,7 +22,11 @@
#ifndef PCM_INTERNAL_H
#define PCM_INTERNAL_H
#include <stdbool.h>
#include "config.h"
#include "pcm.h"
#include "pcm_sink.h"
#include "gcc_extensions.h" /* for FORCE_INLINE */
#ifdef HAVE_SW_VOLUME_CONTROL
@ -129,24 +133,12 @@ void pcm_play_stop_int(void);
bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
const void **addr, size_t *size);
extern unsigned long pcm_curr_sampr;
extern unsigned long pcm_sampr;
extern int pcm_fsel;
#ifdef HAVE_PCM_DMA_ADDRESS
void * pcm_dma_addr(void *addr);
#endif
extern volatile bool pcm_playing;
void pcm_play_dma_lock(void);
void pcm_play_dma_unlock(void);
void pcm_play_dma_init(void) INIT_ATTR;
void pcm_play_dma_postinit(void);
void pcm_play_dma_start(const void *addr, size_t size);
void pcm_play_dma_stop(void);
void pcm_dma_apply_settings(void);
struct pcm_sink* pcm_get_current_sink(void);
#ifdef HAVE_RECORDING

View file

@ -71,6 +71,12 @@ void pcm_init(void) INIT_ATTR;
void pcm_postinit(void);
bool pcm_is_initialized(void);
enum pcm_sink_ids pcm_current_sink(void);
const struct pcm_sink_caps* pcm_sink_caps(enum pcm_sink_ids sink);
/* shortcut for plugins */
const struct pcm_sink_caps* pcm_current_sink_caps(void);
/* This is for playing "raw" PCM data */
void pcm_play_data(pcm_play_callback_type get_more,
pcm_status_callback_type status_cb,

View file

@ -0,0 +1,57 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2025 by Sho Tanimoto
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#pragma once
#include <stddef.h>
#include <stdint.h>
struct pcm_sink_caps {
const unsigned long* samprs;
uint16_t num_samprs;
uint16_t default_freq;
};
struct pcm_sink_ops {
void (*init)(void);
void (*postinit)(void);
void (*set_freq)(uint16_t freq);
void (*lock)(void);
void (*unlock)(void);
void (*play)(const void* addr, size_t size);
void (*stop)(void);
};
struct pcm_sink {
/* characteristics */
const struct pcm_sink_caps caps;
/* operations */
const struct pcm_sink_ops ops;
/* runtime states */
unsigned long pending_freq;
unsigned long configured_freq;
};
enum pcm_sink_ids {
PCM_SINK_BUILTIN = 0,
};
/* defined in each platform pcm source */
extern struct pcm_sink builtin_pcm_sink;

View file

@ -42,21 +42,19 @@
* Semi-private -
* pcm_play_dma_complete_callback
* pcm_play_dma_status_callback
* pcm_play_dma_init
* pcm_play_dma_postinit
* pcm_play_dma_start
* pcm_play_dma_stop
* pcm_get_current_sink
* pcm_sink.init
* pcm_sink.postinit
* pcm_sink.play
* pcm_sink.stop
* Data Read/Written within TSP -
* pcm_sampr (R)
* pcm_fsel (R)
* pcm_curr_sampr (R)
* pcm_playing (R)
*
* ==Playback/Recording==
* Public -
* pcm_dma_addr
* Semi-private -
* pcm_dma_apply_settings
* pcm_sink.set_freq
*
* ==Recording==
* Public -
@ -81,6 +79,12 @@
/* 'true' when all stages of pcm initialization have completed */
static bool pcm_is_ready = false;
static struct pcm_sink* sinks[1] = {
[PCM_SINK_BUILTIN] = &builtin_pcm_sink,
};
static enum pcm_sink_ids cur_sink = PCM_SINK_BUILTIN;
static struct mutex sink_mutex; /* protects sinks and cur_sink */
/* The registered callback function to ask for more mp3 data */
volatile pcm_play_callback_type
pcm_callback_for_more SHAREDBSS_ATTR = NULL;
@ -89,16 +93,14 @@ volatile pcm_status_callback_type
pcm_play_status_callback SHAREDBSS_ATTR = NULL;
/* PCM playback state */
volatile bool pcm_playing SHAREDBSS_ATTR = false;
/* samplerate of currently playing audio - undefined if stopped */
unsigned long pcm_curr_sampr SHAREDBSS_ATTR = 0;
/* samplerate waiting to be set */
unsigned long pcm_sampr SHAREDBSS_ATTR = HW_SAMPR_DEFAULT;
/* samplerate frequency selection index */
int pcm_fsel SHAREDBSS_ATTR = HW_FREQ_DEFAULT;
static void pcm_play_data_start_int(const void *addr, size_t size);
void pcm_play_stop_int(void);
struct pcm_sink* pcm_get_current_sink(void)
{
return sinks[cur_sink];
}
#if !defined(HAVE_SW_VOLUME_CONTROL) || defined(PCM_SW_VOLUME_UNBUFFERED)
/** Standard hw volume/unbuffered control functions - otherwise, see
** pcm_sw_volume.c **/
@ -108,12 +110,12 @@ static inline void pcm_play_dma_start_int(const void *addr, size_t size)
/* Smoothed transition might not have happened so sync now */
pcm_sync_pcm_factors();
#endif
pcm_play_dma_start(addr, size);
sinks[cur_sink]->ops.play(addr, size);
}
static inline void pcm_play_dma_stop_int(void)
{
pcm_play_dma_stop();
sinks[cur_sink]->ops.stop();
}
bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
@ -123,8 +125,9 @@ bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
if (status < PCM_DMAST_OK)
status = pcm_play_dma_status_callback(status);
if (status >= PCM_DMAST_OK && pcm_get_more_int(addr, size))
if (status >= PCM_DMAST_OK && pcm_get_more_int(addr, size)) {
return true;
}
/* Error, callback missing or no more DMA to do */
pcm_play_stop_int();
@ -132,25 +135,6 @@ bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
}
#endif /* !HAVE_SW_VOLUME_CONTROL || PCM_SW_VOLUME_UNBUFFERED */
static void pcm_play_data_start_int(const void *addr, size_t size)
{
ALIGN_AUDIOBUF(addr, size);
if ((addr && size) || pcm_get_more_int(&addr, &size))
{
pcm_apply_settings();
logf(" pcm_play_dma_start_int");
pcm_play_dma_start_int(addr, size);
pcm_playing = true;
}
else
{
/* Force a stop */
logf(" pcm_play_stop_int");
pcm_play_stop_int();
}
}
void pcm_play_stop_int(void)
{
pcm_play_dma_stop_int();
@ -223,7 +207,15 @@ void pcm_do_peak_calculation(struct pcm_peaks *peaks, bool active,
if (active)
{
int framecount = peaks->period*pcm_curr_sampr / HZ;
struct pcm_sink* sink = sinks[cur_sink];
if (sink->configured_freq == -1UL)
{
logf("not configured yet");
return;
}
unsigned long sampr = sink->caps.samprs[sink->configured_freq];
int framecount = peaks->period * sampr / HZ;
count = MIN(framecount, count);
if (count > 0)
@ -247,16 +239,29 @@ bool pcm_is_playing(void)
* interface
*/
void pcm_play_lock(void) {
mutex_lock(&sink_mutex);
sinks[cur_sink]->ops.lock();
/* hold sink_mutex until pcm_play_unlock() */
}
void pcm_play_unlock(void) {
sinks[cur_sink]->ops.unlock();
mutex_unlock(&sink_mutex);
}
/* This should only be called at startup before any audio playback or
recording is attempted */
void pcm_init(void)
{
logf("pcm_init");
pcm_set_frequency(HW_SAMPR_DEFAULT);
logf(" pcm_play_dma_init");
pcm_play_dma_init();
mutex_init(&sink_mutex);
for(size_t i = 0; i < ARRAYLEN(sinks); i += 1) {
sinks[i]->pending_freq = sinks[i]->caps.default_freq;
sinks[i]->configured_freq = -1UL;
sinks[i]->ops.init();
}
}
/* Finish delayed init */
@ -264,9 +269,9 @@ void pcm_postinit(void)
{
logf("pcm_postinit");
logf(" pcm_play_dma_postinit");
pcm_play_dma_postinit();
for(size_t i = 0; i < ARRAYLEN(sinks); i += 1) {
sinks[i]->ops.postinit();
}
pcm_is_ready = true;
}
@ -276,6 +281,21 @@ bool pcm_is_initialized(void)
return pcm_is_ready;
}
enum pcm_sink_ids pcm_current_sink(void)
{
return cur_sink;
}
const struct pcm_sink_caps* pcm_sink_caps(enum pcm_sink_ids sink)
{
return &sinks[sink]->caps;
}
const struct pcm_sink_caps* pcm_current_sink_caps(void)
{
return pcm_sink_caps(pcm_current_sink());
}
void pcm_play_data(pcm_play_callback_type get_more,
pcm_status_callback_type status_cb,
const void *start, size_t size)
@ -287,8 +307,20 @@ void pcm_play_data(pcm_play_callback_type get_more,
pcm_callback_for_more = get_more;
pcm_play_status_callback = status_cb;
logf(" pcm_play_data_start_int");
pcm_play_data_start_int(start, size);
ALIGN_AUDIOBUF(start, size);
if ((start && size) || pcm_get_more_int(&start, &size))
{
pcm_apply_settings();
logf(" pcm_play_dma_start_int");
pcm_play_dma_start_int(start, size);
pcm_playing = true;
}
else
{
/* Force a stop */
logf(" pcm_play_stop_int");
pcm_play_stop_int();
}
pcm_play_unlock();
}
@ -329,20 +361,22 @@ void pcm_set_frequency(unsigned int samplerate)
samplerate = pcm_sampr_to_hw_sampr(samplerate, type);
#endif /* CONFIG_SAMPR_TYPES */
index = round_value_to_list32(samplerate, hw_freq_sampr,
HW_NUM_FREQ, false);
mutex_lock(&sink_mutex);
struct pcm_sink* sink = sinks[cur_sink];
index = round_value_to_list32(samplerate, sink->caps.samprs, sink->caps.num_samprs, false);
if (samplerate != hw_freq_sampr[index])
index = HW_FREQ_DEFAULT; /* Invalid = default */
if (samplerate != sink->caps.samprs[index])
index = sink->caps.default_freq; /* Invalid = default */
pcm_sampr = hw_freq_sampr[index];
pcm_fsel = index;
sink->pending_freq = index;
mutex_unlock(&sink_mutex);
}
/* return last-set frequency */
unsigned int pcm_get_frequency(void)
{
return pcm_sampr;
struct pcm_sink* sink = sinks[cur_sink];
return sink->caps.samprs[sink->pending_freq];
}
/* apply pcm settings to the hardware */
@ -352,12 +386,14 @@ void pcm_apply_settings(void)
pcm_wait_for_init();
if (pcm_sampr != pcm_curr_sampr)
{
logf(" pcm_dma_apply_settings");
pcm_dma_apply_settings();
pcm_curr_sampr = pcm_sampr;
mutex_lock(&sink_mutex);
struct pcm_sink* sink = sinks[cur_sink];
if(sink->pending_freq != sink->configured_freq) {
logf(" sink->set_freq");
sink->ops.set_freq(sink->pending_freq);
sink->configured_freq = sink->pending_freq;
}
mutex_unlock(&sink_mutex);
}
#ifdef HAVE_RECORDING

View file

@ -325,7 +325,7 @@ static void start_pcm(bool reframe)
pcm_play_dma_status_callback(PCM_DMAST_STARTED);
pcm_play_dma_status_callback(PCM_DMAST_STARTED);
pcm_play_dma_start(pcm_dbl_buf[1], pcm_dbl_buf_size[1]);
pcm_get_current_sink()->ops.play(pcm_dbl_buf[1], pcm_dbl_buf_size[1]);
}
void pcm_play_dma_start_int(const void *addr, size_t size)
@ -338,7 +338,7 @@ void pcm_play_dma_start_int(const void *addr, size_t size)
void pcm_play_dma_stop_int(void)
{
pcm_play_dma_stop();
pcm_get_current_sink()->ops.stop();
src_buf_addr = NULL;
src_buf_rem = 0;
}

View file

@ -31,6 +31,7 @@
#include "mmu-arm.h"
#include "cpucache-arm.h"
#include "pcm-internal.h"
#include "pcm_sink.h"
#define MAX_TRANSFER (4*((1<<11)-1)) /* maximum data we can transfer via DMA
* i.e. 32 bits at once (size of I2SO_DATA)
@ -53,13 +54,13 @@ static bool volatile is_recording = false;
#endif
/* Mask the DMA interrupt */
void pcm_play_lock(void)
static void sink_lock(void)
{
++locked;
}
/* Unmask the DMA interrupt if enabled */
void pcm_play_unlock(void)
static void sink_unlock(void)
{
if(--locked == 0 && is_playing)
{
@ -119,7 +120,7 @@ static void dma_callback(void)
}
}
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
is_playing = true;
@ -136,7 +137,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
play_start_pcm();
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
is_playing = false;
@ -153,20 +154,6 @@ void pcm_play_dma_stop(void)
play_callback_pending = false;
}
void pcm_play_dma_init(void)
{
bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE);
I2SOUT_CONTROL = (1<<6) | (1<<3); /* enable dma, stereo */
audiohw_preinit();
pcm_dma_apply_settings();
}
void pcm_play_dma_postinit(void)
{
audiohw_postinit();
}
/* divider is 9 bits but the highest one (for 8kHz) fit in 8 bits */
static const unsigned char divider[SAMPR_NUM_FREQ] = {
[HW_FREQ_96] = ((AS3525_MCLK_FREQ/128 + SAMPR_96/2) / SAMPR_96) - 1,
@ -183,12 +170,7 @@ static const unsigned char divider[SAMPR_NUM_FREQ] = {
[HW_FREQ_8 ] = ((AS3525_MCLK_FREQ/128 + SAMPR_8 /2) / SAMPR_8 ) - 1,
};
static inline unsigned char mclk_divider(void)
{
return divider[pcm_fsel];
}
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
bitmod32(&CGU_AUDIO,
(0<<24) | /* I2SI_MCLK2PAD_EN = disabled */
@ -196,11 +178,20 @@ void pcm_dma_apply_settings(void)
(0<<14) | /* I2SI_MCLK_DIV_SEL = unused */
(0<<12) | /* I2SI_MCLK_SEL = clk_main */
(1<<11) | /* I2SO_MCLK_EN */
(mclk_divider() << 2) | /* I2SO_MCLK_DIV_SEL */
(divider[freq] << 2) | /* I2SO_MCLK_DIV_SEL */
(AS3525_MCLK_SEL << 0), /* I2SO_MCLK_SEL */
0x01ffffff);
}
static void sink_dma_init(void)
{
bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE);
I2SOUT_CONTROL = (1<<6) | (1<<3); /* enable dma, stereo */
audiohw_preinit();
sink_set_freq(HW_SAMPR_DEFAULT);
}
#ifdef HAVE_PCM_DMA_ADDRESS
void * pcm_dma_addr(void *addr)
{
@ -210,6 +201,22 @@ void * pcm_dma_addr(void *addr)
}
#endif
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
/****************************************************************************
** Recording DMA transfer

View file

@ -25,6 +25,8 @@
#include "dma-imx233.h"
#include "pcm-internal.h"
#include "audioout-imx233.h"
#include "pcm_sampr.h"
#include "pcm_sink.h"
struct pcm_dma_command_t
{
@ -47,7 +49,7 @@ static const void *dac_buf; /* current buffer */
static size_t dac_size; /* remaining size */
/* for both recording and playback: maximum transfer size, see
* pcm_dma_apply_settings */
* sink_set_sampr */
static size_t dma_max_size = CACHEALIGN_UP(1600);
enum
@ -110,33 +112,33 @@ void INT_DAC_ERROR(void)
imx233_dma_clear_channel_interrupt(APB_AUDIO_DAC);
}
void pcm_play_lock(void)
static void sink_lock(void)
{
if(dac_locked++ == 0)
imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, false);
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
if(--dac_locked == 0)
imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, true);
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
/* do not interrupt the current transaction because resetting the dma
* would halt the DAC and clearing RUN causes sound havoc so simply
* wait for the end of transfer */
pcm_play_lock();
sink_lock();
dac_buf = NULL;
dac_size = 0;
dac_state = DAC_STOP_PENDING;
pcm_play_unlock();
sink_unlock();
}
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
pcm_play_lock();
sink_lock();
/* update pending buffer */
dac_buf = addr;
dac_size = size;
@ -145,15 +147,10 @@ void pcm_play_dma_start(const void *addr, size_t size)
play();
else
dac_state = DAC_PLAYING;
pcm_play_unlock();
sink_unlock();
}
void pcm_play_dma_init(void)
{
audiohw_preinit();
}
void pcm_play_dma_postinit(void)
static void sink_dma_postinit(void)
{
audiohw_postinit();
imx233_icoll_enable_interrupt(INT_SRC_DAC_DMA, true);
@ -162,18 +159,35 @@ void pcm_play_dma_postinit(void)
imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, true);
}
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
pcm_play_lock();
sink_lock();
/* update frequency */
audiohw_set_frequency(pcm_fsel);
audiohw_set_frequency(freq);
/* compute maximum transfer size: aim at ~1/100s stop time maximum, make sure
* the resulting value is a multiple of cache line. At sample rate F we
* transfer two samples (2 x 2 bytes) F times per second = 4F b/s */
dma_max_size = CACHEALIGN_UP(4 * pcm_sampr / 100);
pcm_play_unlock();
dma_max_size = CACHEALIGN_UP(4 * hw_freq_sampr[freq] / 100);
sink_unlock();
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = audiohw_preinit,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
/*
* Recording
*/

View file

@ -26,6 +26,7 @@
#include "sdma-imx31.h"
#include "mmu-imx31.h"
#include "pcm-internal.h"
#include "pcm_sink.h"
#define DMA_PLAY_CH_NUM 2
#define DMA_REC_CH_NUM 1
@ -112,12 +113,12 @@ static void play_dma_callback(void)
}
}
void pcm_play_lock(void)
static void sink_lock(void)
{
++dma_play_data.locked;
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
if (--dma_play_data.locked == 0 && dma_play_data.state != 0)
{
@ -131,12 +132,12 @@ void pcm_play_unlock(void)
}
}
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
audiohw_set_frequency(pcm_fsel);
audiohw_set_frequency(freq);
}
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
/* Init DMA channel information */
sdma_channel_init(DMA_PLAY_CH_NUM, &dma_play_cd, &dma_play_bd);
@ -146,11 +147,6 @@ void pcm_play_dma_init(void)
audiohw_init();
}
void pcm_play_dma_postinit(void)
{
audiohw_postinit();
}
static void play_start_pcm(void)
{
/* Stop transmission (if in progress) */
@ -200,7 +196,7 @@ static void play_stop_pcm(void)
dma_play_data.callback_pending = 0;
}
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
sdma_channel_stop(DMA_PLAY_CH_NUM);
@ -218,7 +214,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
play_start_dma(addr, size);
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
sdma_channel_stop(DMA_PLAY_CH_NUM);
play_stop_pcm();
@ -229,6 +225,23 @@ void * pcm_dma_addr(void *addr)
return (void *)addr_virt_to_phys((unsigned long)addr);
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
#ifdef HAVE_RECORDING
static struct buffer_descriptor dma_rec_bd NOCACHEBSS_ATTR;

View file

@ -28,6 +28,7 @@
#include "i2s.h"
#include "pcm.h"
#include "pcm-internal.h"
#include "pcm_sink.h"
struct dma_data
{
@ -62,7 +63,7 @@ struct dma_data dma_play_data SHAREDBSS_ATTR =
.state = 0
};
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
DAVC = 0x0; /* Digital Volume = max */
#ifdef COWON_D2
@ -89,12 +90,7 @@ void pcm_play_dma_init(void)
#endif
}
void pcm_play_dma_postinit(void)
{
audiohw_postinit();
}
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
}
@ -125,7 +121,7 @@ static void play_stop_pcm(void)
dma_play_data.state = 0;
}
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
dma_play_data.p_r = addr;
dma_play_data.size = size;
@ -140,7 +136,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
play_start_pcm();
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
play_stop_pcm();
dma_play_data.size = 0;
@ -149,7 +145,7 @@ void pcm_play_dma_stop(void)
#endif
}
void pcm_play_lock(void)
static void sink_lock(void)
{
int status = disable_fiq_save();
@ -161,7 +157,7 @@ void pcm_play_lock(void)
restore_fiq(status);
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
int status = disable_fiq_save();
@ -173,6 +169,23 @@ void pcm_play_unlock(void)
restore_fiq(status);
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
#ifdef HAVE_RECORDING
/* TODO: implement */
void pcm_rec_dma_init(void)

View file

@ -27,6 +27,7 @@
#include "pcm.h"
#include "pcm_sampr.h"
#include "pcm-internal.h"
#include "pcm_sink.h"
/** DMA **/
@ -89,10 +90,12 @@ static struct dma_data dma_play_data IBSS_ATTR =
.state = 0
};
void pcm_dma_apply_settings(void)
{
audiohw_set_frequency(pcm_fsel);
}
/* DMA status cannot be viewed from outside code in control because that can
* clear the interrupt from outside the handler and prevent the handler from
* from being called. Split up transfers to a reasonable size that is good as
* a timer and peaking yet still keeps the FIQ count low.
*/
static uint16_t max_dma_chunk_size;
#if defined(CPU_PP502x)
/* 16-bit, L-R packed into 32 bits with left in the least significant halfword */
@ -102,12 +105,6 @@ void pcm_dma_apply_settings(void)
#define DMA_PLAY_CONFIG ((DMA_REQ_IIS << DMA_CMD_REQ_ID_POS) | \
DMA_CMD_RAM_TO_PER | DMA_CMD_SINGLE | \
DMA_CMD_WAIT_REQ | DMA_CMD_INTR)
/* DMA status cannot be viewed from outside code in control because that can
* clear the interrupt from outside the handler and prevent the handler from
* from being called. Split up transfers to a reasonable size that is good as
* a timer and peaking yet still keeps the FIQ count low.
*/
#define MAX_DMA_CHUNK_SIZE (pcm_curr_sampr >> 6) /* ~1/256 seconds */
static inline void dma_tx_init(void)
{
@ -145,9 +142,9 @@ static inline unsigned long dma_tx_buf_prepare(const void *addr)
static inline void dma_tx_start(bool begin)
{
size_t size = MAX_DMA_CHUNK_SIZE;
size_t size = max_dma_chunk_size;
/* Not at least MAX_DMA_CHUNK_SIZE left or there would be less
/* Not at least max_dma_chunk_size left or there would be less
* than a FIFO's worth of data after this transfer? */
if (size + 16*4 > dma_play_data.size)
size = dma_play_data.size;
@ -430,10 +427,15 @@ void fiq_playback(void)
#endif /* ASM / C selection */
#endif /* CPU_PP502x */
static void sink_set_freq(uint16_t freq) {
max_dma_chunk_size = hw_freq_sampr[freq] >> 6;
audiohw_set_frequency(freq);
}
/* For the locks, FIQ must be disabled because the handler manipulates
IISCONFIG and the operation is not atomic - dual core support
will require other measures */
void pcm_play_lock(void)
static void sink_lock(void)
{
int status = disable_fiq_save();
@ -444,7 +446,7 @@ void pcm_play_lock(void)
restore_fiq(status);
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
int status = disable_fiq_save();
@ -455,14 +457,14 @@ void pcm_play_unlock(void)
restore_fiq(status);
}
static void play_start_pcm(void)
static void sink_start_pcm(void)
{
fiq_function = fiq_playback;
dma_play_data.state = 1;
dma_tx_start(true);
}
static void play_stop_pcm(void)
static void sink_stop_pcm(void)
{
dma_tx_stop();
@ -472,9 +474,11 @@ static void play_stop_pcm(void)
dma_play_data.state = 0;
}
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_stop(void);
static void sink_dma_start(const void *addr, size_t size)
{
pcm_play_dma_stop();
sink_dma_stop();
#if NUM_CORES > 1
/* This will become more important later - and different ! */
@ -485,13 +489,13 @@ void pcm_play_dma_start(const void *addr, size_t size)
dma_play_data.addr = dma_tx_buf_prepare(addr);
dma_play_data.size = size;
play_start_pcm();
sink_start_pcm();
}
/* Stops the DMA transfer and interrupt */
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
play_stop_pcm();
sink_stop_pcm();
dma_play_data.addr = 0;
dma_play_data.size = 0;
#if NUM_CORES > 1
@ -499,7 +503,7 @@ void pcm_play_dma_stop(void)
#endif
}
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
/* Initialize default register values. */
audiohw_init();
@ -509,10 +513,22 @@ void pcm_play_dma_init(void)
IISCONFIG |= IIS_TXFIFOEN;
}
void pcm_play_dma_postinit(void)
{
audiohw_postinit();
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
/****************************************************************************
** Recording DMA transfer

View file

@ -28,11 +28,12 @@
#include "audiohw.h"
#include "sound.h"
#include "pcm-internal.h"
#include "pcm_sink.h"
static int locked = 0;
/* Mask the DMA interrupt */
void pcm_play_lock(void)
static void sink_lock(void)
{
if (++locked == 1)
{
@ -43,7 +44,7 @@ void pcm_play_lock(void)
}
/* Unmask the DMA interrupt if enabled */
void pcm_play_unlock(void)
static void sink_unlock(void)
{
if(--locked == 0)
{
@ -53,7 +54,7 @@ void pcm_play_unlock(void)
}
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
HDMA_CON0 = 0x00;
HDMA_ISR = 0x00;
@ -105,10 +106,10 @@ static void hdma_i2s_transfer(const void *addr, size_t size)
(1<<0)); /* hardware trigger DMA mode */
}
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
/* Stop any DMA in progress */
pcm_play_dma_stop();
sink_dma_stop();
/* kick in DMA transfer */
hdma_i2s_transfer(addr, size);
@ -225,7 +226,7 @@ static void set_codec_freq(unsigned int freq)
}
#endif
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
/* unmask HDMA interrupt in INTC */
INTC_IMR |= IRQ_ARM_HDMA;
@ -236,18 +237,13 @@ void pcm_play_dma_init(void)
i2s_init();
}
void pcm_play_dma_postinit(void)
{
audiohw_postinit();
}
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
#ifdef CODEC_SLAVE
set_codec_freq(pcm_fsel);
set_codec_freq(freq);
#endif
audiohw_set_frequency(pcm_fsel);
audiohw_set_frequency(freq);
}
/* audio DMA ISR called when chunk from callers buffer has been transfered */
@ -263,6 +259,23 @@ void INT_HDMA(void)
}
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
/****************************************************************************
** Recording DMA transfer
**/

View file

@ -26,6 +26,7 @@
#include "sound.h"
#include "file.h"
#include "pcm-internal.h"
#include "pcm_sink.h"
/* PCM interrupt routine lockout */
static struct
@ -48,20 +49,20 @@ static struct
void fiq_handler(void) __attribute__((interrupt ("FIQ")));
/* Mask the DMA interrupt */
void pcm_play_lock(void)
static void sink_lock(void)
{
if (++dma_play_lock.locked == 1)
bitset32(&INTMSK, DMA2_MASK);
}
/* Unmask the DMA interrupt if enabled */
void pcm_play_unlock(void)
static void sink_unlock(void)
{
if (--dma_play_lock.locked == 0)
bitclr32(&INTMSK, dma_play_lock.state);
}
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
/* There seem to be problems when changing the IIS interface configuration
* when a clock is not present.
@ -94,14 +95,9 @@ void pcm_play_dma_init(void)
bitset32(&INTMOD, DMA2_MASK);
}
void pcm_play_dma_postinit(void)
static void sink_set_freq(uint16_t freq)
{
audiohw_postinit();
}
void pcm_dma_apply_settings(void)
{
audiohw_set_frequency(pcm_fsel);
audiohw_set_frequency(freq);
}
/* Connect the DMA and start filling the FIFO */
@ -158,7 +154,7 @@ static void play_stop_pcm(void)
IISCON &= ~(1<<0);
}
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
/* Enable the IIS clock */
bitset32(&CLKCON, 1<<17);
@ -187,7 +183,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
}
/* Promptly stop DMA transfers and stop IIS */
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
play_stop_pcm();
@ -219,3 +215,20 @@ void fiq_handler(void)
pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};

View file

@ -32,11 +32,12 @@
#include "dma-target.h"
#include "mmu-arm.h"
#include "cpucache-arm.h"
#include "pcm_sink.h"
/* Driver for the IIS/PCM part of the s5l8700 using DMA
Notes:
- pcm_play_dma_stop is untested, not sure if implemented the right way
- sink_dma_stop is untested, not sure if implemented the right way
- recording is not implemented
*/
@ -83,7 +84,7 @@ static const struct div_entry {
};
/* Mask the DMA interrupt */
void pcm_play_lock(void)
static void sink_lock(void)
{
if (locked++ == 0) {
INTMSK &= ~(1 << 10);
@ -91,7 +92,7 @@ void pcm_play_lock(void)
}
/* Unmask the DMA interrupt if enabled */
void pcm_play_unlock(void)
static void sink_unlock(void)
{
if (--locked == 0) {
INTMSK |= (1 << 10);
@ -141,7 +142,7 @@ void INT_DMA(void)
}
void pcm_play_dma_start(const void* addr, size_t size)
static void sink_dma_start(const void* addr, size_t size)
{
/* DMA channel on */
nextbuf = addr;
@ -161,7 +162,7 @@ void pcm_play_dma_start(const void* addr, size_t size)
(0 << 0); /* 0 = LRCK on */
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
/* DMA channel off */
DMACOM0 = 5;
@ -195,7 +196,7 @@ static void pcm_dma_set_freq(enum hw_freq_indexes idx)
(div.cdiv - 1); /* MCLK_DIV_VAL */
}
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
/* configure IIS pins */
#ifdef IPOD_NANO2G
@ -252,15 +253,10 @@ void pcm_play_dma_init(void)
audiohw_preinit();
}
void pcm_play_dma_postinit(void)
{
audiohw_postinit();
}
/* set the configured PCM frequency */
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
pcm_dma_set_freq(pcm_fsel);
pcm_dma_set_freq(hw_freq_sampr[freq]);
}
#ifdef HAVE_PCM_DMA_ADDRESS
@ -272,6 +268,22 @@ void * pcm_dma_addr(void *addr)
}
#endif
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
/****************************************************************************
** Recording DMA transfer

View file

@ -31,6 +31,7 @@
#include "pcm_sampr.h"
#include "pcm-target.h"
#include "dma-s5l8702.h"
#include "pcm_sink.h"
/* DMA configuration */
@ -86,14 +87,14 @@ static int active_dblbuf;
size_t pcm_remaining;
/* Mask the DMA interrupt */
void pcm_play_lock(void)
static void sink_lock(void)
{
if (locked++ == 0)
dmac_ch_lock_int(&dma_play_ch);
}
/* Unmask the DMA interrupt if enabled */
void pcm_play_unlock(void)
static void sink_unlock(void)
{
if (--locked == 0)
dmac_ch_unlock_int(&dma_play_ch);
@ -141,30 +142,29 @@ static void dma_play_callback(void *cb_data)
pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
void pcm_play_dma_start(const void* addr, size_t size)
static void sink_dma_stop(void)
{
pcm_play_dma_stop();
dmac_ch_stop(&dma_play_ch);
I2STXCOM = 0xa;
}
static void sink_dma_start(const void* addr, size_t size)
{
sink_dma_stop();
pcm_remaining = size;
I2STXCOM = 0xe;
dma_play_callback((void*)addr);
}
void pcm_play_dma_stop(void)
{
dmac_ch_stop(&dma_play_ch);
I2STXCOM = 0xa;
}
/* MCLK = 12MHz (MCLKDIV2=1), [CS42L55 DS, s4.8] */
#define MCLK_FREQ 12000000
/* set the configured PCM frequency */
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
static uint16_t last_clkcon3l = 0;
uint16_t clkcon3l;
int fsel;
/* For unknown reasons, s5l8702 I2S controller does not synchronize
* with CS42L55 at 32000 Hz. To fix it, the CODEC is configured with
@ -172,12 +172,11 @@ void pcm_dma_apply_settings(void)
* obtaining 32 KHz in LRCK controller input and 8 MHz in SCLK input.
* OF uses this trick.
*/
if (pcm_fsel == HW_FREQ_32) {
fsel = HW_FREQ_48;
if (freq == HW_FREQ_32) {
freq = HW_FREQ_48;
clkcon3l = 0x3028; /* PLL2 / 3 / 9 -> 8 MHz */
}
else {
fsel = pcm_fsel;
clkcon3l = 0; /* OSC0 -> 12 MHz */
}
@ -192,12 +191,12 @@ void pcm_dma_apply_settings(void)
}
/* configure I2S clock ratio */
I2SCLKDIV = MCLK_FREQ / hw_freq_sampr[fsel];
I2SCLKDIV = MCLK_FREQ / hw_freq_sampr[freq];
/* select CS42L55 sample rate */
audiohw_set_frequency(fsel);
audiohw_set_frequency(freq);
}
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
PWRCON(1) &= ~(1 << 7);
@ -207,12 +206,7 @@ void pcm_play_dma_init(void)
I2SCLKCON = 1;
audiohw_preinit();
pcm_dma_apply_settings();
}
void pcm_play_dma_postinit(void)
{
audiohw_postinit();
sink_set_freq(HW_FREQ_DEFAULT);
}
#ifdef HAVE_PCM_DMA_ADDRESS
@ -222,6 +216,22 @@ void * pcm_dma_addr(void *addr)
}
#endif
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
/****************************************************************************
** Recording DMA transfer

View file

@ -20,37 +20,57 @@
****************************************************************************/
#include "pcm.h"
#include "pcm-internal.h"
#include "pcm_sampr.h"
#include "pcm_sink.h"
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
(void)freq;
}
static void sink_dma_init(void)
{
}
void pcm_play_dma_init(void)
static void sink_dma_postinit(void)
{
}
void pcm_play_dma_postinit(void)
{
}
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
(void)addr;
(void)size;
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
}
void pcm_play_lock(void)
static void sink_lock(void)
{
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
#ifdef HAVE_RECORDING
void pcm_rec_dma_init(void)
{

View file

@ -28,13 +28,14 @@
#include "dsp-target.h"
#include "dsp/ipc.h"
#include "pcm-internal.h"
#include "pcm_sink.h"
/* This is global to save some latency when pcm_play_dma_get_peak_buffer is
* called.
*/
static const void *start;
void pcm_play_dma_postinit(void)
static void sink_dma_postinit(void)
{
/* Configure clock divider */
tsc2100_writereg(CONTROL_PAGE2, TSPP1_ADDRESS, 0x1120);
@ -45,7 +46,7 @@ void pcm_play_dma_postinit(void)
audiohw_postinit();
}
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
IO_INTC_IRQ0 = INTR_IRQ0_IMGBUF;
bitset16(&IO_INTC_EINT0, INTR_EINT0_IMGBUF);
@ -67,15 +68,15 @@ void pcm_play_dma_init(void)
dsp_wake();
}
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
audiohw_set_frequency(pcm_fsel);
audiohw_set_frequency(freq);
}
/* Note that size is actually limited to the size of a short right now due to
* the implementation on the DSP side (and the way that we access it)
*/
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
unsigned long sdem_addr=(unsigned long)addr - CONFIG_SDRAM_START;
/* Initialize codec. */
@ -87,18 +88,18 @@ void pcm_play_dma_start(const void *addr, size_t size)
dsp_wake();
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
DSP_(_dma0_stopped)=1;
dsp_wake();
}
void pcm_play_lock(void)
static void sink_lock(void)
{
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
}
@ -157,3 +158,19 @@ void DSPHINT(void)
DEBUGF("DSP: %s", buffer);
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};

View file

@ -29,6 +29,7 @@
#include "dsp/ipc.h"
#include "pcm-internal.h"
#include "dma-target.h"
#include "pcm_sink.h"
/* This is global to save some latency when pcm_play_dma_get_peak_buffer is
* called.
@ -36,12 +37,7 @@
static const void *start;
static int dma_channel;
void pcm_play_dma_postinit(void)
{
audiohw_postinit();
}
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
/* GIO16 is DSP/AIC3X CLK */
IO_GIO_FSEL0 &= 0x3FFF;
@ -74,15 +70,15 @@ void pcm_play_dma_init(void)
dsp_wake();
}
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
audiohw_set_frequency(pcm_fsel);
audiohw_set_frequency(freq);
}
/* Note that size is actually limited to the size of a short right now due to
* the implementation on the DSP side (and the way that we access it)
*/
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
unsigned long sdem_addr=(unsigned long)addr - CONFIG_SDRAM_START;
/* Initialize codec. */
@ -94,18 +90,18 @@ void pcm_play_dma_start(const void *addr, size_t size)
dsp_wake();
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
DSP_(_dma0_stopped)=1;
dsp_wake();
}
void pcm_play_lock(void)
static void sink_lock(void)
{
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
}
@ -164,3 +160,19 @@ void DSPHINT(void)
DEBUGF("DSP: %s", buffer);
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};

View file

@ -29,6 +29,7 @@
#include "spdif.h"
#endif
#include "pcm-internal.h"
#include "pcm_sink.h"
#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
(IIS_PLAY & (7 << 8)) | \
@ -142,12 +143,12 @@ static void iis_play_reset_if_playback(bool if_playback)
/* This clears the reset bit to enable monitoring immediately if monitoring
recording sources or always if playback is in progress - we might be
switching samplerates on the fly */
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
int level = set_irq_level(DMA_IRQ_LEVEL);
/* remember table entry */
freq_ent = pcm_freq_parms[pcm_fsel];
freq_ent = pcm_freq_parms[freq];
/* Reprogramming bits 15-12 requires FIFO to be in a reset
condition - Users Manual 17-8, Note 11 */
@ -159,7 +160,7 @@ void pcm_dma_apply_settings(void)
IIS_PLAY = IIS_PLAY_DEFPARM | IIS_FIFO_RESET;
restore_irq(level);
audiohw_set_frequency(pcm_fsel);
audiohw_set_frequency(freq);
coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
level = set_irq_level(DMA_IRQ_LEVEL);
@ -170,11 +171,11 @@ void pcm_dma_apply_settings(void)
PDOR3 = 0; /* Kick FIFO out of reset by writing to it */
restore_irq(level);
} /* pcm_dma_apply_settings */
} /* sink_set_sampr */
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
freq_ent = pcm_freq_parms[pcm_fsel];
freq_ent = pcm_freq_parms[HW_FREQ_DEFAULT];
AUDIOGLOB = AUDIOGLOB_DEFPARM;
DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
@ -195,15 +196,15 @@ void pcm_play_dma_init(void)
audio_input_mux(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
audiohw_set_frequency(pcm_fsel);
audiohw_set_frequency(HW_FREQ_DEFAULT);
coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT)
spdif_init();
#endif
} /* pcm_play_dma_init */
} /* sink_dma_init */
void pcm_play_dma_postinit(void)
void sink_dma_postinit(void)
{
audiohw_postinit();
iis_play_reset();
@ -223,23 +224,35 @@ static struct dma_lock dma_play_lock =
.state = (1 << 14) /* bit 14 is DMA0 */
};
void pcm_play_lock(void)
static void sink_lock(void)
{
if (++dma_play_lock.locked == 1)
coldfire_imr_mod(1 << 14, 1 << 14);
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
if (--dma_play_lock.locked == 0)
coldfire_imr_mod(dma_play_lock.state, 1 << 14);
}
/* Stops the DMA transfer and interrupt */
static void sink_dma_stop(void)
{
and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
BCR0 = 0; /* No bytes remaining */
DSR0 = 1; /* Clear interrupt, errors, stop transfer */
iis_play_reset_if_playback(true);
dma_play_lock.state = (1 << 14);
} /* sink_dma_stop */
/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
/* Stop any DMA in progress */
pcm_play_dma_stop();
sink_dma_stop();
/* Set up DMA transfer */
SAR0 = (unsigned long)addr; /* Source address */
@ -250,19 +263,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
DMA_SSIZE(DMA_SIZE_LINE) | DMA_START;
dma_play_lock.state = (0 << 14);
} /* pcm_play_dma_start */
/* Stops the DMA transfer and interrupt */
void pcm_play_dma_stop(void)
{
and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
BCR0 = 0; /* No bytes remaining */
DSR0 = 1; /* Clear interrupt, errors, stop transfer */
iis_play_reset_if_playback(true);
dma_play_lock.state = (1 << 14);
} /* pcm_play_dma_stop */
} /* sink_dma_start */
/* DMA0 Interrupt is called when the DMA has finished transfering a chunk
from the caller's buffer */
@ -301,6 +302,23 @@ void DMA0(void)
/* else inished playing */
} /* DMA0 */
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
#ifdef HAVE_RECORDING
/****************************************************************************
** Recording DMA transfer

View file

@ -28,6 +28,8 @@
#include "debug.h"
#include "pcm.h"
#include "pcm-internal.h"
#include "pcm_sampr.h"
#include "pcm_sink.h"
extern JNIEnv *env_ptr;
@ -133,23 +135,24 @@ Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this,
return max_size - left;
}
void pcm_play_lock(void)
static void sink_lock(void)
{
if (++audio_locked == 1)
lock_audio();
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
if (--audio_locked == 0)
unlock_audio();
}
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
(void)freq;
}
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
pcm_data_start = addr;
pcm_data_size = size;
@ -160,7 +163,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
0);
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
/* NOTE: due to how pcm_play_dma_complete_callback() works, this is
* possibly called from nativeWrite(), i.e. another (host) thread
@ -171,7 +174,7 @@ void pcm_play_dma_stop(void)
stop_method);
}
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
/* in order to have background music playing after leaving the activity,
* we need to allocate the PCM object from the Rockbox thread (the Activity
@ -194,7 +197,7 @@ void pcm_play_dma_init(void)
write_method = e->GetMethodID(env_ptr, RockboxPCM_class, "write", "([BII)I");
}
void pcm_play_dma_postinit(void)
static void sink_dma_postinit(void)
{
}
@ -213,6 +216,23 @@ void pcm_shutdown(void)
pthread_mutex_destroy(&audio_lock_mutex);
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
JNIEXPORT void JNICALL
Java_org_rockbox_RockboxPCM_postVolumeChangedEvent(JNIEnv *env,
jobject this,

View file

@ -45,6 +45,7 @@
#include "pcm-internal.h"
#include "pcm_sampr.h"
#include "pcm_mixer.h"
#include "pcm_sink.h"
#include <3ds/ndsp/ndsp.h>
#include <3ds/ndsp/channel.h>
@ -102,14 +103,14 @@ static inline bool is_in_audio_thread(int audio_thread_id)
return false;
}
void pcm_play_lock(void)
static void sink_lock(void)
{
if (!is_in_audio_thread(_pcm_thread_id)) {
RecursiveLock_Lock(&_pcm_lock_mtx);
}
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
if (!is_in_audio_thread(_pcm_thread_id)) {
RecursiveLock_Unlock(&_pcm_lock_mtx);
@ -188,13 +189,13 @@ void dsp_callback(void *const nul_) {
LightEvent_Signal(&_dsp_callback_event);
}
static void pcm_dma_apply_settings_nolock(void)
static void sink_set_freq_nolock(uint16_t freq)
{
ndspChnReset(0);
ndspSetOutputMode(NDSP_OUTPUT_STEREO);
ndspChnSetRate(0, pcm_sampr);
ndspChnSetRate(0, hw_freq_sampr[freq]);
ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16);
/* ndspChnSetInterp(0, NDSP_INTERP_POLYPHASE); */
/* ndspChnSetInterp(0, NDSP_INTERP_NONE); */
@ -235,7 +236,7 @@ static void pcm_dma_apply_settings_nolock(void)
-1, /* run on any core */ false);
}
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
_pcm_buffer = addr;
_pcm_buffer_size = size;
@ -245,7 +246,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
RecursiveLock_Unlock(&_pcm_lock_mtx);
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
RecursiveLock_Lock(&_pcm_lock_mtx);
ndspChnSetPaused(0, true);
@ -303,7 +304,7 @@ unsigned long spdif_measure_frequency(void)
#endif /* HAVE_RECORDING */
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
Result ndsp_init_res = ndspInit();
if (R_FAILED(ndsp_init_res)) {
@ -319,15 +320,15 @@ void pcm_play_dma_init(void)
LightEvent_Init(&_dsp_callback_event, RESET_ONESHOT);
}
void pcm_play_dma_postinit(void)
static void sink_dma_postinit(void)
{
}
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
pcm_play_lock();
pcm_dma_apply_settings_nolock();
pcm_play_unlock();
sink_lock();
sink_set_freq_nolock(freq);
sink_unlock();
}
void pcm_close_device(void)
@ -357,3 +358,20 @@ void audiohw_close(void)
{
pcm_close_device();
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};

View file

@ -31,6 +31,8 @@
#include "panic.h"
#include "pcm.h"
#include "pcm-internal.h"
#include "pcm_sampr.h"
#include "pcm_sink.h"
#include "sound/asound.h"
#include "tinyalsa/asoundlib.h"
@ -187,26 +189,26 @@ static const unsigned int DEVICE = 0;
static struct pcm_config _config;
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
TRACE;
#ifdef DEBUG
/*
DEBUG pcm_play_dma_init: Access: 0x000009
DEBUG pcm_play_dma_init: Format[0]: 0x000044
DEBUG pcm_play_dma_init: Format[1]: 0x000010
DEBUG pcm_play_dma_init: Format: S16_LE
DEBUG pcm_play_dma_init: Format: S24_LE
DEBUG pcm_play_dma_init: Format: S20_3LE
DEBUG pcm_play_dma_init: Subformat: 0x000001
DEBUG pcm_play_dma_init: Rate: min = 8000Hz, max = 192000Hz
DEBUG pcm_play_dma_init: Channels: min = 2, max = 2
DEBUG pcm_play_dma_init: Sample bits: min=16, max=32
DEBUG pcm_play_dma_init: Period size: min=8, max=10922
DEBUG pcm_play_dma_init: Period count: min=3, max=128
DEBUG pcm_play_dma_init: 0 mixer controls.
DEBUG sink_dma_init: Access: 0x000009
DEBUG sink_dma_init: Format[0]: 0x000044
DEBUG sink_dma_init: Format[1]: 0x000010
DEBUG sink_dma_init: Format: S16_LE
DEBUG sink_dma_init: Format: S24_LE
DEBUG sink_dma_init: Format: S20_3LE
DEBUG sink_dma_init: Subformat: 0x000001
DEBUG sink_dma_init: Rate: min = 8000Hz, max = 192000Hz
DEBUG sink_dma_init: Channels: min = 2, max = 2
DEBUG sink_dma_init: Sample bits: min=16, max=32
DEBUG sink_dma_init: Period size: min=8, max=10922
DEBUG sink_dma_init: Period count: min=3, max=128
DEBUG sink_dma_init: 0 mixer controls.
*/
struct pcm_params* params = pcm_params_get(CARD, DEVICE, PCM_OUT);
@ -310,7 +312,7 @@ void pcm_play_dma_init(void)
pcm_thread_run relies on this size match. See pcm_mixer.h.
*/
_config.channels = 2;
_config.rate = pcm_sampr;
_config.rate = hw_freq_sampr[HW_FREQ_DEFAULT];
_config.period_size = 256;
_config.period_count = 4;
_config.format = PCM_FORMAT_S16_LE;
@ -337,7 +339,7 @@ void pcm_play_dma_init(void)
}
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
TRACE;
@ -364,7 +366,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
pthread_mutex_unlock(&_dma_suspended_mtx);
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
TRACE;
@ -375,11 +377,11 @@ void pcm_play_dma_stop(void)
}
/* Unessecary play locks before pcm_play_dma_postinit. */
/* Unessecary play locks before sink_dma_postinit. */
static int _play_lock_recursion_count = -10000;
void pcm_play_dma_postinit(void)
static void sink_dma_postinit(void)
{
TRACE;
@ -387,7 +389,7 @@ void pcm_play_dma_postinit(void)
}
void pcm_play_lock(void)
static void sink_lock(void)
{
TRACE;
@ -402,7 +404,7 @@ void pcm_play_lock(void)
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
TRACE;
@ -418,9 +420,9 @@ void pcm_play_unlock(void)
}
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
unsigned int rate = pcm_get_frequency();
unsigned int rate = hw_freq_sampr[freq];
DEBUGF("DEBUG %s: Current sample rate: %u, next sampe rate: %u.", __func__, _config.rate, rate);
@ -450,3 +452,20 @@ void pcm_close_device(void)
pcm_close(_alsa_handle);
_alsa_handle = NULL;
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};

View file

@ -48,6 +48,7 @@
#include "pcm-internal.h"
#include "pcm_mixer.h"
#include "pcm_sampr.h"
#include "pcm_sink.h"
#include "audiohw.h"
#include "pcm-alsa.h"
#include "fixedpoint.h"
@ -122,7 +123,7 @@ void pcm_alsa_set_capture_device(const char *device)
}
#endif
static int set_hwparams(snd_pcm_t *handle)
static int set_hwparams(snd_pcm_t *handle, unsigned long sampr)
{
int err;
unsigned int srate;
@ -136,10 +137,10 @@ static int set_hwparams(snd_pcm_t *handle)
Note these are in FRAMES, and are sized to be about 8.5ms
for the buffer and 2.1ms for the period
*/
if (pcm_sampr > SAMPR_96) {
if (sampr > SAMPR_96) {
buffer_size = MIX_FRAME_SAMPLES * 4 * 4;
period_size = MIX_FRAME_SAMPLES * 4;
} else if (pcm_sampr > SAMPR_48) {
} else if (sampr > SAMPR_48) {
buffer_size = MIX_FRAME_SAMPLES * 2 * 4;
period_size = MIX_FRAME_SAMPLES * 2;
} else {
@ -176,17 +177,17 @@ static int set_hwparams(snd_pcm_t *handle)
goto error;
}
/* set the stream rate */
srate = pcm_sampr;
srate = sampr;
err = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0);
if (err < 0)
{
logf("Rate %luHz not available for playback: %s", pcm_sampr, snd_strerror(err));
logf("Rate %luHz not available for playback: %s", sampr, snd_strerror(err));
goto error;
}
real_sample_rate = srate;
if (real_sample_rate != pcm_sampr)
if (real_sample_rate != sampr)
{
logf("Rate doesn't match (requested %luHz, get %dHz)", pcm_sampr, real_sample_rate);
logf("Rate doesn't match (requested %luHz, get %dHz)", sampr, real_sample_rate);
err = -EINVAL;
goto error;
}
@ -595,7 +596,7 @@ static void open_hwdev(const char *device, snd_pcm_stream_t mode)
atexit(alsadev_cleanup);
}
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
logf("PCM DMA Init");
@ -606,48 +607,50 @@ void pcm_play_dma_init(void)
return;
}
void pcm_play_lock(void)
static void sink_lock(void)
{
pthread_mutex_lock(&pcm_mtx);
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
pthread_mutex_unlock(&pcm_mtx);
}
static void pcm_dma_apply_settings_nolock(void)
static void sink_set_freq_nolock(uint16_t freq)
{
logf("PCM DMA Settings %d %lu", last_sample_rate, pcm_sampr);
unsigned int sampr = hw_freq_sampr[freq];
if (last_sample_rate != pcm_sampr)
logf("PCM DMA Settings %d %lu", last_sample_rate, sampr);
if (last_sample_rate != sampr)
{
last_sample_rate = pcm_sampr;
last_sample_rate = sampr;
#ifdef AUDIOHW_MUTE_ON_SRATE_CHANGE
audiohw_mute(true);
#endif
snd_pcm_drop(handle);
set_hwparams(handle); // FIXME: check return code?
set_hwparams(handle, sampr); // FIXME: check return code?
set_swparams(handle); // FIXME: check return code?
#if defined(HAVE_NWZ_LINUX_CODEC)
/* Sony NWZ linux driver uses a nonstandard mecanism to set the sampling rate */
audiohw_set_frequency(pcm_sampr);
audiohw_set_frequency(sampr);
#endif
/* (Will be unmuted by pcm resuming) */
}
}
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
pcm_play_lock();
pcm_dma_apply_settings_nolock();
pcm_play_unlock();
sink_lock();
sink_set_freq_nolock(freq);
sink_unlock();
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
logf("PCM DMA stop (%d)", snd_pcm_state(handle));
@ -660,10 +663,9 @@ void pcm_play_dma_stop(void)
#endif
}
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
logf("PCM DMA start (%p %d)", addr, size);
pcm_dma_apply_settings_nolock();
pcm_data = addr;
pcm_size = size;
@ -749,7 +751,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
}
}
void pcm_play_dma_postinit(void)
static void sink_dma_postinit(void)
{
audiohw_postinit();
@ -768,15 +770,32 @@ unsigned int pcm_alsa_get_xruns(void)
return xruns;
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
#ifdef HAVE_RECORDING
void pcm_rec_lock(void)
{
pcm_play_lock();
sink_lock();
}
void pcm_rec_unlock(void)
{
pcm_play_unlock();
sink_unlock();
}
void pcm_rec_dma_init(void)
@ -796,7 +815,6 @@ void pcm_rec_dma_close(void)
void pcm_rec_dma_start(void *start, size_t size)
{
logf("PCM REC DMA start (%p %d)", start, size);
pcm_dma_apply_settings_nolock();
pcm_data_rec = start;
pcm_size = size;

View file

@ -44,6 +44,7 @@
#include "pcm-internal.h"
#include "pcm_sampr.h"
#include "pcm_mixer.h"
#include "pcm_sink.h"
/*#define LOGF_ENABLE*/
#include "logf.h"
@ -57,6 +58,8 @@ extern const char *audiodev;
static int cvt_status = -1;
static unsigned long pcm_sampr;
static const void *pcm_data;
static size_t pcm_data_size;
static size_t pcm_sample_bytes;
@ -80,13 +83,13 @@ static SDL_AudioCVT cvt;
static int audio_locked = 0;
static SDL_mutex *audio_lock;
void pcm_play_lock(void)
static void sink_lock(void)
{
if (++audio_locked == 1)
SDL_LockMutex(audio_lock);
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
if (--audio_locked == 0)
SDL_UnlockMutex(audio_lock);
@ -97,8 +100,11 @@ void pcm_play_unlock(void)
#endif
static void sdl_audio_callback(void *handle, Uint8 *stream, int len);
static void pcm_dma_apply_settings_nolock(void)
static void sink_set_freq_nolock(uint16_t freq)
{
pcm_sampr = hw_freq_sampr[freq];
SDL_AudioSpec wanted_spec;
wanted_spec.freq = pcm_sampr;
wanted_spec.format = AUDIO_S16SYS;
@ -161,14 +167,14 @@ static void pcm_dma_apply_settings_nolock(void)
}
}
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
pcm_play_lock();
pcm_dma_apply_settings_nolock();
pcm_play_unlock();
sink_lock();
sink_set_freq_nolock(freq);
sink_unlock();
}
void pcm_play_dma_start(const void *addr, size_t size)
static void sink_dma_start(const void *addr, size_t size)
{
pcm_data = addr;
pcm_data_size = size;
@ -180,7 +186,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
#endif
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
#if SDL_MAJOR_VERSION > 1
SDL_PauseAudioDevice(pcm_devid, 1);
@ -397,7 +403,7 @@ unsigned long spdif_measure_frequency(void)
#endif /* HAVE_RECORDING */
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
if (SDL_InitSubSystem(SDL_INIT_AUDIO))
{
@ -435,6 +441,23 @@ void pcm_play_dma_init(void)
#endif
}
void pcm_play_dma_postinit(void)
static void sink_dma_postinit(void)
{
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};

View file

@ -26,14 +26,14 @@
#include "sound.h"
#include "pcm.h"
#include "pcm-internal.h"
#include "pcm_sink.h"
#include "jz4740.h"
/****************************************************************************
** Playback DMA transfer
**/
void pcm_play_dma_postinit(void)
static void sink_dma_postinit(void)
{
audiohw_postinit();
@ -47,7 +47,7 @@ void pcm_play_dma_postinit(void)
__aic_flush_fifo();
}
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
/* TODO */
@ -57,10 +57,10 @@ void pcm_play_dma_init(void)
audiohw_init();
}
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
/* TODO */
audiohw_set_frequency(pcm_sampr);
audiohw_set_frequency(freq);
}
static const void* playback_address;
@ -135,21 +135,7 @@ void DMA_CALLBACK(DMA_AIC_TX_CHANNEL)(void)
}
}
void pcm_play_dma_start(const void *addr, size_t size)
{
pcm_play_dma_stop();
dma_enable();
set_dma(addr, size);
__aic_enable_transmit_dma();
__aic_enable_replay();
REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN;
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
int flags = disable_irq_save();
@ -163,8 +149,22 @@ void pcm_play_dma_stop(void)
restore_irq(flags);
}
static void sink_dma_start(const void *addr, size_t size)
{
sink_dma_stop();
dma_enable();
set_dma(addr, size);
__aic_enable_transmit_dma();
__aic_enable_replay();
REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN;
}
static unsigned int play_lock = 0;
void pcm_play_lock(void)
static void sink_lock(void)
{
int flags = disable_irq_save();
@ -174,7 +174,7 @@ void pcm_play_lock(void)
restore_irq(flags);
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
int flags = disable_irq_save();
@ -189,6 +189,23 @@ void audiohw_close(void)
/* TODO: prevent pop */
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
#ifdef HAVE_RECORDING
/* TODO */
void pcm_rec_dma_init(void)

View file

@ -26,13 +26,14 @@
#include "sound.h"
#include "pcm.h"
#include "pcm-internal.h"
#include "pcm_sink.h"
#include "cpu.h"
/****************************************************************************
** Playback DMA transfer
**/
void pcm_play_dma_postinit(void)
static void sink_dma_postinit(void)
{
audiohw_postinit();
@ -40,7 +41,7 @@ void pcm_play_dma_postinit(void)
__aic_flush_tfifo();
}
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
system_enable_irq(DMA_IRQ(DMA_AIC_TX_CHANNEL));
@ -48,9 +49,9 @@ void pcm_play_dma_init(void)
audiohw_init();
}
void pcm_dma_apply_settings(void)
static void sink_set_freq(uint16_t freq)
{
audiohw_set_frequency(pcm_fsel);
audiohw_set_frequency(freq);
}
static const void* playback_address;
@ -126,20 +127,7 @@ void DMA_CALLBACK(DMA_AIC_TX_CHANNEL)(void)
}
}
void pcm_play_dma_start(const void *addr, size_t size)
{
pcm_play_dma_stop();
__dmac_channel_enable_clk(DMA_AIC_TX_CHANNEL);
set_dma(addr, size);
__aic_enable_replay();
__dmac_channel_enable_irq(DMA_AIC_TX_CHANNEL);
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
int flags = disable_irq_save();
@ -152,8 +140,21 @@ void pcm_play_dma_stop(void)
restore_irq(flags);
}
static void sink_dma_start(const void *addr, size_t size)
{
sink_dma_stop();
__dmac_channel_enable_clk(DMA_AIC_TX_CHANNEL);
set_dma(addr, size);
__aic_enable_replay();
__dmac_channel_enable_irq(DMA_AIC_TX_CHANNEL);
}
static unsigned int play_lock = 0;
void pcm_play_lock(void)
static void sink_lock(void)
{
int flags = disable_irq_save();
@ -163,7 +164,7 @@ void pcm_play_lock(void)
restore_irq(flags);
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
int flags = disable_irq_save();
@ -172,3 +173,20 @@ void pcm_play_unlock(void)
restore_irq(flags);
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};

View file

@ -25,6 +25,7 @@
#include "audiohw.h"
#include "pcm.h"
#include "pcm-internal.h"
#include "pcm_sink.h"
#include "panic.h"
#include "dma-x1000.h"
#include "irq-x1000.h"
@ -53,7 +54,7 @@ static dma_desc rec_dma_desc;
static void pcm_rec_dma_int_cb(int event);
#endif
void pcm_play_dma_init(void)
static void sink_dma_init(void)
{
/* Ungate clock */
jz_writef(CPM_CLKGR, AIC(0));
@ -99,14 +100,9 @@ void pcm_play_dma_init(void)
system_enable_irq(IRQ_AIC);
}
void pcm_play_dma_postinit(void)
static void sink_set_freq(uint16_t freq)
{
audiohw_postinit();
}
void pcm_dma_apply_settings(void)
{
audiohw_set_frequency(pcm_fsel);
audiohw_set_frequency(freq);
}
static void play_dma_start(const void* addr, size_t size)
@ -157,7 +153,7 @@ static void pcm_play_dma_int_cb(int event)
}
}
void pcm_play_dma_start(const void* addr, size_t size)
static void sink_dma_start(const void* addr, size_t size)
{
play_dma_pending_event = DMA_EVENT_NONE;
aic_state |= AIC_STATE_PLAYING;
@ -166,7 +162,7 @@ void pcm_play_dma_start(const void* addr, size_t size)
jz_writef(AIC_CCR, TDMS(1), ETUR(1), ERPL(1));
}
void pcm_play_dma_stop(void)
static void sink_dma_stop(void)
{
/* disable DMA and underrun interrupts */
jz_writef(AIC_CCR, TDMS(0), ETUR(0));
@ -180,7 +176,7 @@ void pcm_play_dma_stop(void)
if (jz_readf(AIC_I2SCR, STPBK) == 0) {
while(jz_readf(AIC_SR, TFL) != 0);
} else {
panicf("pcm_play_dma_stop: No bit clock running!");
panicf("sink_dma_stop: No bit clock running!");
}
/* disable playback */
@ -190,14 +186,14 @@ void pcm_play_dma_stop(void)
aic_state &= ~AIC_STATE_PLAYING;
}
void pcm_play_lock(void)
static void sink_lock(void)
{
int irq = disable_irq_save();
++play_lock;
restore_irq(irq);
}
void pcm_play_unlock(void)
static void sink_unlock(void)
{
int irq = disable_irq_save();
if(--play_lock == 0 && (aic_state & AIC_STATE_PLAYING)) {
@ -208,6 +204,23 @@ void pcm_play_unlock(void)
restore_irq(irq);
}
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
#ifdef HAVE_RECORDING
/*
* Recording