mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-10-10 08:03:04 -04:00
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:
parent
9931781185
commit
dfa33c246b
29 changed files with 846 additions and 424 deletions
|
|
@ -647,6 +647,7 @@ static const struct plugin_api rockbox_api = {
|
||||||
pcm_apply_settings,
|
pcm_apply_settings,
|
||||||
pcm_play_lock,
|
pcm_play_lock,
|
||||||
pcm_play_unlock,
|
pcm_play_unlock,
|
||||||
|
pcm_current_sink_caps,
|
||||||
beep_play,
|
beep_play,
|
||||||
#ifdef HAVE_RECORDING
|
#ifdef HAVE_RECORDING
|
||||||
&rec_freq_sampr[0],
|
&rec_freq_sampr[0],
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ int plugin_open(const char *plugin, const char *parameter);
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "pathfuncs.h"
|
#include "pathfuncs.h"
|
||||||
#include "pcm_mixer.h"
|
#include "pcm_mixer.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
#include "dsp-util.h"
|
#include "dsp-util.h"
|
||||||
#include "dsp_core.h"
|
#include "dsp_core.h"
|
||||||
#include "dsp_proc_settings.h"
|
#include "dsp_proc_settings.h"
|
||||||
|
|
@ -745,6 +746,7 @@ struct plugin_api {
|
||||||
void (*pcm_apply_settings)(void);
|
void (*pcm_apply_settings)(void);
|
||||||
void (*pcm_play_lock)(void);
|
void (*pcm_play_lock)(void);
|
||||||
void (*pcm_play_unlock)(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,
|
void (*beep_play)(unsigned int frequency, unsigned int duration,
|
||||||
unsigned int amplitude);
|
unsigned int amplitude);
|
||||||
#ifdef HAVE_RECORDING
|
#ifdef HAVE_RECORDING
|
||||||
|
|
|
||||||
|
|
@ -1783,6 +1783,10 @@ void pcm_play_unlock(void)
|
||||||
\group sound
|
\group sound
|
||||||
\description
|
\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)
|
void pcm_record_data(pcm_rec_callback_type more_ready, pcm_status_callback_type status_cb, void *start, size_t size)
|
||||||
\group sound
|
\group sound
|
||||||
\conditions (defined(HAVE_RECORDING))
|
\conditions (defined(HAVE_RECORDING))
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,11 @@
|
||||||
#ifndef PCM_INTERNAL_H
|
#ifndef PCM_INTERNAL_H
|
||||||
#define PCM_INTERNAL_H
|
#define PCM_INTERNAL_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "pcm.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
#include "gcc_extensions.h" /* for FORCE_INLINE */
|
#include "gcc_extensions.h" /* for FORCE_INLINE */
|
||||||
|
|
||||||
#ifdef HAVE_SW_VOLUME_CONTROL
|
#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,
|
bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
|
||||||
const void **addr, size_t *size);
|
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
|
#ifdef HAVE_PCM_DMA_ADDRESS
|
||||||
void * pcm_dma_addr(void *addr);
|
void * pcm_dma_addr(void *addr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern volatile bool pcm_playing;
|
extern volatile bool pcm_playing;
|
||||||
|
struct pcm_sink* pcm_get_current_sink(void);
|
||||||
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);
|
|
||||||
|
|
||||||
#ifdef HAVE_RECORDING
|
#ifdef HAVE_RECORDING
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,12 @@ void pcm_init(void) INIT_ATTR;
|
||||||
void pcm_postinit(void);
|
void pcm_postinit(void);
|
||||||
bool pcm_is_initialized(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 */
|
/* This is for playing "raw" PCM data */
|
||||||
void pcm_play_data(pcm_play_callback_type get_more,
|
void pcm_play_data(pcm_play_callback_type get_more,
|
||||||
pcm_status_callback_type status_cb,
|
pcm_status_callback_type status_cb,
|
||||||
|
|
|
||||||
57
firmware/export/pcm_sink.h
Normal file
57
firmware/export/pcm_sink.h
Normal 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;
|
||||||
154
firmware/pcm.c
154
firmware/pcm.c
|
|
@ -42,21 +42,19 @@
|
||||||
* Semi-private -
|
* Semi-private -
|
||||||
* pcm_play_dma_complete_callback
|
* pcm_play_dma_complete_callback
|
||||||
* pcm_play_dma_status_callback
|
* pcm_play_dma_status_callback
|
||||||
* pcm_play_dma_init
|
* pcm_get_current_sink
|
||||||
* pcm_play_dma_postinit
|
* pcm_sink.init
|
||||||
* pcm_play_dma_start
|
* pcm_sink.postinit
|
||||||
* pcm_play_dma_stop
|
* pcm_sink.play
|
||||||
|
* pcm_sink.stop
|
||||||
* Data Read/Written within TSP -
|
* Data Read/Written within TSP -
|
||||||
* pcm_sampr (R)
|
|
||||||
* pcm_fsel (R)
|
|
||||||
* pcm_curr_sampr (R)
|
|
||||||
* pcm_playing (R)
|
* pcm_playing (R)
|
||||||
*
|
*
|
||||||
* ==Playback/Recording==
|
* ==Playback/Recording==
|
||||||
* Public -
|
* Public -
|
||||||
* pcm_dma_addr
|
* pcm_dma_addr
|
||||||
* Semi-private -
|
* Semi-private -
|
||||||
* pcm_dma_apply_settings
|
* pcm_sink.set_freq
|
||||||
*
|
*
|
||||||
* ==Recording==
|
* ==Recording==
|
||||||
* Public -
|
* Public -
|
||||||
|
|
@ -81,6 +79,12 @@
|
||||||
/* 'true' when all stages of pcm initialization have completed */
|
/* 'true' when all stages of pcm initialization have completed */
|
||||||
static bool pcm_is_ready = false;
|
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 */
|
/* The registered callback function to ask for more mp3 data */
|
||||||
volatile pcm_play_callback_type
|
volatile pcm_play_callback_type
|
||||||
pcm_callback_for_more SHAREDBSS_ATTR = NULL;
|
pcm_callback_for_more SHAREDBSS_ATTR = NULL;
|
||||||
|
|
@ -89,16 +93,14 @@ volatile pcm_status_callback_type
|
||||||
pcm_play_status_callback SHAREDBSS_ATTR = NULL;
|
pcm_play_status_callback SHAREDBSS_ATTR = NULL;
|
||||||
/* PCM playback state */
|
/* PCM playback state */
|
||||||
volatile bool pcm_playing SHAREDBSS_ATTR = false;
|
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);
|
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)
|
#if !defined(HAVE_SW_VOLUME_CONTROL) || defined(PCM_SW_VOLUME_UNBUFFERED)
|
||||||
/** Standard hw volume/unbuffered control functions - otherwise, see
|
/** Standard hw volume/unbuffered control functions - otherwise, see
|
||||||
** pcm_sw_volume.c **/
|
** 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 */
|
/* Smoothed transition might not have happened so sync now */
|
||||||
pcm_sync_pcm_factors();
|
pcm_sync_pcm_factors();
|
||||||
#endif
|
#endif
|
||||||
pcm_play_dma_start(addr, size);
|
sinks[cur_sink]->ops.play(addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void pcm_play_dma_stop_int(void)
|
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,
|
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)
|
if (status < PCM_DMAST_OK)
|
||||||
status = pcm_play_dma_status_callback(status);
|
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;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Error, callback missing or no more DMA to do */
|
/* Error, callback missing or no more DMA to do */
|
||||||
pcm_play_stop_int();
|
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 */
|
#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)
|
void pcm_play_stop_int(void)
|
||||||
{
|
{
|
||||||
pcm_play_dma_stop_int();
|
pcm_play_dma_stop_int();
|
||||||
|
|
@ -223,7 +207,15 @@ void pcm_do_peak_calculation(struct pcm_peaks *peaks, bool active,
|
||||||
|
|
||||||
if (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);
|
count = MIN(framecount, count);
|
||||||
|
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
|
|
@ -247,16 +239,29 @@ bool pcm_is_playing(void)
|
||||||
* interface
|
* 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
|
/* This should only be called at startup before any audio playback or
|
||||||
recording is attempted */
|
recording is attempted */
|
||||||
void pcm_init(void)
|
void pcm_init(void)
|
||||||
{
|
{
|
||||||
logf("pcm_init");
|
logf("pcm_init");
|
||||||
|
|
||||||
pcm_set_frequency(HW_SAMPR_DEFAULT);
|
mutex_init(&sink_mutex);
|
||||||
|
for(size_t i = 0; i < ARRAYLEN(sinks); i += 1) {
|
||||||
logf(" pcm_play_dma_init");
|
sinks[i]->pending_freq = sinks[i]->caps.default_freq;
|
||||||
pcm_play_dma_init();
|
sinks[i]->configured_freq = -1UL;
|
||||||
|
sinks[i]->ops.init();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finish delayed init */
|
/* Finish delayed init */
|
||||||
|
|
@ -264,9 +269,9 @@ void pcm_postinit(void)
|
||||||
{
|
{
|
||||||
logf("pcm_postinit");
|
logf("pcm_postinit");
|
||||||
|
|
||||||
logf(" pcm_play_dma_postinit");
|
for(size_t i = 0; i < ARRAYLEN(sinks); i += 1) {
|
||||||
|
sinks[i]->ops.postinit();
|
||||||
pcm_play_dma_postinit();
|
}
|
||||||
|
|
||||||
pcm_is_ready = true;
|
pcm_is_ready = true;
|
||||||
}
|
}
|
||||||
|
|
@ -276,6 +281,21 @@ bool pcm_is_initialized(void)
|
||||||
return pcm_is_ready;
|
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,
|
void pcm_play_data(pcm_play_callback_type get_more,
|
||||||
pcm_status_callback_type status_cb,
|
pcm_status_callback_type status_cb,
|
||||||
const void *start, size_t size)
|
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_callback_for_more = get_more;
|
||||||
pcm_play_status_callback = status_cb;
|
pcm_play_status_callback = status_cb;
|
||||||
|
|
||||||
logf(" pcm_play_data_start_int");
|
ALIGN_AUDIOBUF(start, size);
|
||||||
pcm_play_data_start_int(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();
|
pcm_play_unlock();
|
||||||
}
|
}
|
||||||
|
|
@ -329,20 +361,22 @@ void pcm_set_frequency(unsigned int samplerate)
|
||||||
samplerate = pcm_sampr_to_hw_sampr(samplerate, type);
|
samplerate = pcm_sampr_to_hw_sampr(samplerate, type);
|
||||||
#endif /* CONFIG_SAMPR_TYPES */
|
#endif /* CONFIG_SAMPR_TYPES */
|
||||||
|
|
||||||
index = round_value_to_list32(samplerate, hw_freq_sampr,
|
mutex_lock(&sink_mutex);
|
||||||
HW_NUM_FREQ, false);
|
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])
|
if (samplerate != sink->caps.samprs[index])
|
||||||
index = HW_FREQ_DEFAULT; /* Invalid = default */
|
index = sink->caps.default_freq; /* Invalid = default */
|
||||||
|
|
||||||
pcm_sampr = hw_freq_sampr[index];
|
sink->pending_freq = index;
|
||||||
pcm_fsel = index;
|
mutex_unlock(&sink_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return last-set frequency */
|
/* return last-set frequency */
|
||||||
unsigned int pcm_get_frequency(void)
|
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 */
|
/* apply pcm settings to the hardware */
|
||||||
|
|
@ -352,12 +386,14 @@ void pcm_apply_settings(void)
|
||||||
|
|
||||||
pcm_wait_for_init();
|
pcm_wait_for_init();
|
||||||
|
|
||||||
if (pcm_sampr != pcm_curr_sampr)
|
mutex_lock(&sink_mutex);
|
||||||
{
|
struct pcm_sink* sink = sinks[cur_sink];
|
||||||
logf(" pcm_dma_apply_settings");
|
if(sink->pending_freq != sink->configured_freq) {
|
||||||
pcm_dma_apply_settings();
|
logf(" sink->set_freq");
|
||||||
pcm_curr_sampr = pcm_sampr;
|
sink->ops.set_freq(sink->pending_freq);
|
||||||
|
sink->configured_freq = sink->pending_freq;
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&sink_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_RECORDING
|
#ifdef HAVE_RECORDING
|
||||||
|
|
|
||||||
|
|
@ -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_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)
|
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)
|
void pcm_play_dma_stop_int(void)
|
||||||
{
|
{
|
||||||
pcm_play_dma_stop();
|
pcm_get_current_sink()->ops.stop();
|
||||||
src_buf_addr = NULL;
|
src_buf_addr = NULL;
|
||||||
src_buf_rem = 0;
|
src_buf_rem = 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include "mmu-arm.h"
|
#include "mmu-arm.h"
|
||||||
#include "cpucache-arm.h"
|
#include "cpucache-arm.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
#define MAX_TRANSFER (4*((1<<11)-1)) /* maximum data we can transfer via DMA
|
#define MAX_TRANSFER (4*((1<<11)-1)) /* maximum data we can transfer via DMA
|
||||||
* i.e. 32 bits at once (size of I2SO_DATA)
|
* i.e. 32 bits at once (size of I2SO_DATA)
|
||||||
|
|
@ -53,13 +54,13 @@ static bool volatile is_recording = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Mask the DMA interrupt */
|
/* Mask the DMA interrupt */
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
++locked;
|
++locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unmask the DMA interrupt if enabled */
|
/* Unmask the DMA interrupt if enabled */
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
if(--locked == 0 && is_playing)
|
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;
|
is_playing = true;
|
||||||
|
|
||||||
|
|
@ -136,7 +137,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
|
||||||
play_start_pcm();
|
play_start_pcm();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_stop(void)
|
static void sink_dma_stop(void)
|
||||||
{
|
{
|
||||||
is_playing = false;
|
is_playing = false;
|
||||||
|
|
||||||
|
|
@ -153,20 +154,6 @@ void pcm_play_dma_stop(void)
|
||||||
play_callback_pending = false;
|
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 */
|
/* divider is 9 bits but the highest one (for 8kHz) fit in 8 bits */
|
||||||
static const unsigned char divider[SAMPR_NUM_FREQ] = {
|
static const unsigned char divider[SAMPR_NUM_FREQ] = {
|
||||||
[HW_FREQ_96] = ((AS3525_MCLK_FREQ/128 + SAMPR_96/2) / SAMPR_96) - 1,
|
[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,
|
[HW_FREQ_8 ] = ((AS3525_MCLK_FREQ/128 + SAMPR_8 /2) / SAMPR_8 ) - 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline unsigned char mclk_divider(void)
|
static void sink_set_freq(uint16_t freq)
|
||||||
{
|
|
||||||
return divider[pcm_fsel];
|
|
||||||
}
|
|
||||||
|
|
||||||
void pcm_dma_apply_settings(void)
|
|
||||||
{
|
{
|
||||||
bitmod32(&CGU_AUDIO,
|
bitmod32(&CGU_AUDIO,
|
||||||
(0<<24) | /* I2SI_MCLK2PAD_EN = disabled */
|
(0<<24) | /* I2SI_MCLK2PAD_EN = disabled */
|
||||||
|
|
@ -196,11 +178,20 @@ void pcm_dma_apply_settings(void)
|
||||||
(0<<14) | /* I2SI_MCLK_DIV_SEL = unused */
|
(0<<14) | /* I2SI_MCLK_DIV_SEL = unused */
|
||||||
(0<<12) | /* I2SI_MCLK_SEL = clk_main */
|
(0<<12) | /* I2SI_MCLK_SEL = clk_main */
|
||||||
(1<<11) | /* I2SO_MCLK_EN */
|
(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 */
|
(AS3525_MCLK_SEL << 0), /* I2SO_MCLK_SEL */
|
||||||
0x01ffffff);
|
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
|
#ifdef HAVE_PCM_DMA_ADDRESS
|
||||||
void * pcm_dma_addr(void *addr)
|
void * pcm_dma_addr(void *addr)
|
||||||
{
|
{
|
||||||
|
|
@ -210,6 +201,22 @@ void * pcm_dma_addr(void *addr)
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
** Recording DMA transfer
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@
|
||||||
#include "dma-imx233.h"
|
#include "dma-imx233.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
#include "audioout-imx233.h"
|
#include "audioout-imx233.h"
|
||||||
|
#include "pcm_sampr.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
struct pcm_dma_command_t
|
struct pcm_dma_command_t
|
||||||
{
|
{
|
||||||
|
|
@ -47,7 +49,7 @@ static const void *dac_buf; /* current buffer */
|
||||||
static size_t dac_size; /* remaining size */
|
static size_t dac_size; /* remaining size */
|
||||||
|
|
||||||
/* for both recording and playback: maximum transfer size, see
|
/* 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);
|
static size_t dma_max_size = CACHEALIGN_UP(1600);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
|
@ -110,33 +112,33 @@ void INT_DAC_ERROR(void)
|
||||||
imx233_dma_clear_channel_interrupt(APB_AUDIO_DAC);
|
imx233_dma_clear_channel_interrupt(APB_AUDIO_DAC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
if(dac_locked++ == 0)
|
if(dac_locked++ == 0)
|
||||||
imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, false);
|
imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
if(--dac_locked == 0)
|
if(--dac_locked == 0)
|
||||||
imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, true);
|
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
|
/* do not interrupt the current transaction because resetting the dma
|
||||||
* would halt the DAC and clearing RUN causes sound havoc so simply
|
* would halt the DAC and clearing RUN causes sound havoc so simply
|
||||||
* wait for the end of transfer */
|
* wait for the end of transfer */
|
||||||
pcm_play_lock();
|
sink_lock();
|
||||||
dac_buf = NULL;
|
dac_buf = NULL;
|
||||||
dac_size = 0;
|
dac_size = 0;
|
||||||
dac_state = DAC_STOP_PENDING;
|
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 */
|
/* update pending buffer */
|
||||||
dac_buf = addr;
|
dac_buf = addr;
|
||||||
dac_size = size;
|
dac_size = size;
|
||||||
|
|
@ -145,15 +147,10 @@ void pcm_play_dma_start(const void *addr, size_t size)
|
||||||
play();
|
play();
|
||||||
else
|
else
|
||||||
dac_state = DAC_PLAYING;
|
dac_state = DAC_PLAYING;
|
||||||
pcm_play_unlock();
|
sink_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_init(void)
|
static void sink_dma_postinit(void)
|
||||||
{
|
|
||||||
audiohw_preinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
|
||||||
{
|
{
|
||||||
audiohw_postinit();
|
audiohw_postinit();
|
||||||
imx233_icoll_enable_interrupt(INT_SRC_DAC_DMA, true);
|
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);
|
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 */
|
/* update frequency */
|
||||||
audiohw_set_frequency(pcm_fsel);
|
audiohw_set_frequency(freq);
|
||||||
/* compute maximum transfer size: aim at ~1/100s stop time maximum, make sure
|
/* 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
|
* 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 */
|
* transfer two samples (2 x 2 bytes) F times per second = 4F b/s */
|
||||||
dma_max_size = CACHEALIGN_UP(4 * pcm_sampr / 100);
|
dma_max_size = CACHEALIGN_UP(4 * hw_freq_sampr[freq] / 100);
|
||||||
pcm_play_unlock();
|
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
|
* Recording
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "sdma-imx31.h"
|
#include "sdma-imx31.h"
|
||||||
#include "mmu-imx31.h"
|
#include "mmu-imx31.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
#define DMA_PLAY_CH_NUM 2
|
#define DMA_PLAY_CH_NUM 2
|
||||||
#define DMA_REC_CH_NUM 1
|
#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;
|
++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)
|
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 */
|
/* Init DMA channel information */
|
||||||
sdma_channel_init(DMA_PLAY_CH_NUM, &dma_play_cd, &dma_play_bd);
|
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();
|
audiohw_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
|
||||||
{
|
|
||||||
audiohw_postinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void play_start_pcm(void)
|
static void play_start_pcm(void)
|
||||||
{
|
{
|
||||||
/* Stop transmission (if in progress) */
|
/* Stop transmission (if in progress) */
|
||||||
|
|
@ -200,7 +196,7 @@ static void play_stop_pcm(void)
|
||||||
dma_play_data.callback_pending = 0;
|
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);
|
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);
|
play_start_dma(addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_stop(void)
|
static void sink_dma_stop(void)
|
||||||
{
|
{
|
||||||
sdma_channel_stop(DMA_PLAY_CH_NUM);
|
sdma_channel_stop(DMA_PLAY_CH_NUM);
|
||||||
play_stop_pcm();
|
play_stop_pcm();
|
||||||
|
|
@ -229,6 +225,23 @@ void * pcm_dma_addr(void *addr)
|
||||||
return (void *)addr_virt_to_phys((unsigned long)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
|
#ifdef HAVE_RECORDING
|
||||||
static struct buffer_descriptor dma_rec_bd NOCACHEBSS_ATTR;
|
static struct buffer_descriptor dma_rec_bd NOCACHEBSS_ATTR;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
#include "i2s.h"
|
#include "i2s.h"
|
||||||
#include "pcm.h"
|
#include "pcm.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
struct dma_data
|
struct dma_data
|
||||||
{
|
{
|
||||||
|
|
@ -62,7 +63,7 @@ struct dma_data dma_play_data SHAREDBSS_ATTR =
|
||||||
.state = 0
|
.state = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
void pcm_play_dma_init(void)
|
static void sink_dma_init(void)
|
||||||
{
|
{
|
||||||
DAVC = 0x0; /* Digital Volume = max */
|
DAVC = 0x0; /* Digital Volume = max */
|
||||||
#ifdef COWON_D2
|
#ifdef COWON_D2
|
||||||
|
|
@ -89,12 +90,7 @@ void pcm_play_dma_init(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
static void sink_set_freq(uint16_t freq)
|
||||||
{
|
|
||||||
audiohw_postinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void pcm_dma_apply_settings(void)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,7 +121,7 @@ static void play_stop_pcm(void)
|
||||||
dma_play_data.state = 0;
|
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.p_r = addr;
|
||||||
dma_play_data.size = size;
|
dma_play_data.size = size;
|
||||||
|
|
@ -140,7 +136,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
|
||||||
play_start_pcm();
|
play_start_pcm();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_stop(void)
|
static void sink_dma_stop(void)
|
||||||
{
|
{
|
||||||
play_stop_pcm();
|
play_stop_pcm();
|
||||||
dma_play_data.size = 0;
|
dma_play_data.size = 0;
|
||||||
|
|
@ -149,7 +145,7 @@ void pcm_play_dma_stop(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
int status = disable_fiq_save();
|
int status = disable_fiq_save();
|
||||||
|
|
||||||
|
|
@ -161,7 +157,7 @@ void pcm_play_lock(void)
|
||||||
restore_fiq(status);
|
restore_fiq(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
int status = disable_fiq_save();
|
int status = disable_fiq_save();
|
||||||
|
|
||||||
|
|
@ -173,6 +169,23 @@ void pcm_play_unlock(void)
|
||||||
restore_fiq(status);
|
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
|
#ifdef HAVE_RECORDING
|
||||||
/* TODO: implement */
|
/* TODO: implement */
|
||||||
void pcm_rec_dma_init(void)
|
void pcm_rec_dma_init(void)
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include "pcm.h"
|
#include "pcm.h"
|
||||||
#include "pcm_sampr.h"
|
#include "pcm_sampr.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
/** DMA **/
|
/** DMA **/
|
||||||
|
|
||||||
|
|
@ -89,10 +90,12 @@ static struct dma_data dma_play_data IBSS_ATTR =
|
||||||
.state = 0
|
.state = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
void pcm_dma_apply_settings(void)
|
/* 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
|
||||||
audiohw_set_frequency(pcm_fsel);
|
* 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)
|
#if defined(CPU_PP502x)
|
||||||
/* 16-bit, L-R packed into 32 bits with left in the least significant halfword */
|
/* 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) | \
|
#define DMA_PLAY_CONFIG ((DMA_REQ_IIS << DMA_CMD_REQ_ID_POS) | \
|
||||||
DMA_CMD_RAM_TO_PER | DMA_CMD_SINGLE | \
|
DMA_CMD_RAM_TO_PER | DMA_CMD_SINGLE | \
|
||||||
DMA_CMD_WAIT_REQ | DMA_CMD_INTR)
|
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)
|
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)
|
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? */
|
* than a FIFO's worth of data after this transfer? */
|
||||||
if (size + 16*4 > dma_play_data.size)
|
if (size + 16*4 > dma_play_data.size)
|
||||||
size = dma_play_data.size;
|
size = dma_play_data.size;
|
||||||
|
|
@ -430,10 +427,15 @@ void fiq_playback(void)
|
||||||
#endif /* ASM / C selection */
|
#endif /* ASM / C selection */
|
||||||
#endif /* CPU_PP502x */
|
#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
|
/* For the locks, FIQ must be disabled because the handler manipulates
|
||||||
IISCONFIG and the operation is not atomic - dual core support
|
IISCONFIG and the operation is not atomic - dual core support
|
||||||
will require other measures */
|
will require other measures */
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
int status = disable_fiq_save();
|
int status = disable_fiq_save();
|
||||||
|
|
||||||
|
|
@ -444,7 +446,7 @@ void pcm_play_lock(void)
|
||||||
restore_fiq(status);
|
restore_fiq(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
int status = disable_fiq_save();
|
int status = disable_fiq_save();
|
||||||
|
|
||||||
|
|
@ -455,14 +457,14 @@ void pcm_play_unlock(void)
|
||||||
restore_fiq(status);
|
restore_fiq(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void play_start_pcm(void)
|
static void sink_start_pcm(void)
|
||||||
{
|
{
|
||||||
fiq_function = fiq_playback;
|
fiq_function = fiq_playback;
|
||||||
dma_play_data.state = 1;
|
dma_play_data.state = 1;
|
||||||
dma_tx_start(true);
|
dma_tx_start(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void play_stop_pcm(void)
|
static void sink_stop_pcm(void)
|
||||||
{
|
{
|
||||||
dma_tx_stop();
|
dma_tx_stop();
|
||||||
|
|
||||||
|
|
@ -472,9 +474,11 @@ static void play_stop_pcm(void)
|
||||||
dma_play_data.state = 0;
|
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
|
#if NUM_CORES > 1
|
||||||
/* This will become more important later - and different ! */
|
/* 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.addr = dma_tx_buf_prepare(addr);
|
||||||
dma_play_data.size = size;
|
dma_play_data.size = size;
|
||||||
play_start_pcm();
|
sink_start_pcm();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stops the DMA transfer and interrupt */
|
/* 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.addr = 0;
|
||||||
dma_play_data.size = 0;
|
dma_play_data.size = 0;
|
||||||
#if NUM_CORES > 1
|
#if NUM_CORES > 1
|
||||||
|
|
@ -499,7 +503,7 @@ void pcm_play_dma_stop(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_init(void)
|
static void sink_dma_init(void)
|
||||||
{
|
{
|
||||||
/* Initialize default register values. */
|
/* Initialize default register values. */
|
||||||
audiohw_init();
|
audiohw_init();
|
||||||
|
|
@ -509,10 +513,22 @@ void pcm_play_dma_init(void)
|
||||||
IISCONFIG |= IIS_TXFIFOEN;
|
IISCONFIG |= IIS_TXFIFOEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
struct pcm_sink builtin_pcm_sink = {
|
||||||
{
|
.caps = {
|
||||||
audiohw_postinit();
|
.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
|
** Recording DMA transfer
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,12 @@
|
||||||
#include "audiohw.h"
|
#include "audiohw.h"
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
static int locked = 0;
|
static int locked = 0;
|
||||||
|
|
||||||
/* Mask the DMA interrupt */
|
/* Mask the DMA interrupt */
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
if (++locked == 1)
|
if (++locked == 1)
|
||||||
{
|
{
|
||||||
|
|
@ -43,7 +44,7 @@ void pcm_play_lock(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unmask the DMA interrupt if enabled */
|
/* Unmask the DMA interrupt if enabled */
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
if(--locked == 0)
|
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_CON0 = 0x00;
|
||||||
HDMA_ISR = 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 */
|
(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 */
|
/* Stop any DMA in progress */
|
||||||
pcm_play_dma_stop();
|
sink_dma_stop();
|
||||||
|
|
||||||
/* kick in DMA transfer */
|
/* kick in DMA transfer */
|
||||||
hdma_i2s_transfer(addr, size);
|
hdma_i2s_transfer(addr, size);
|
||||||
|
|
@ -225,7 +226,7 @@ static void set_codec_freq(unsigned int freq)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void pcm_play_dma_init(void)
|
static void sink_dma_init(void)
|
||||||
{
|
{
|
||||||
/* unmask HDMA interrupt in INTC */
|
/* unmask HDMA interrupt in INTC */
|
||||||
INTC_IMR |= IRQ_ARM_HDMA;
|
INTC_IMR |= IRQ_ARM_HDMA;
|
||||||
|
|
@ -236,18 +237,13 @@ void pcm_play_dma_init(void)
|
||||||
i2s_init();
|
i2s_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
static void sink_set_freq(uint16_t freq)
|
||||||
{
|
|
||||||
audiohw_postinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void pcm_dma_apply_settings(void)
|
|
||||||
{
|
{
|
||||||
#ifdef CODEC_SLAVE
|
#ifdef CODEC_SLAVE
|
||||||
set_codec_freq(pcm_fsel);
|
set_codec_freq(freq);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
audiohw_set_frequency(pcm_fsel);
|
audiohw_set_frequency(freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* audio DMA ISR called when chunk from callers buffer has been transfered */
|
/* 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
|
** Recording DMA transfer
|
||||||
**/
|
**/
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
/* PCM interrupt routine lockout */
|
/* PCM interrupt routine lockout */
|
||||||
static struct
|
static struct
|
||||||
|
|
@ -48,20 +49,20 @@ static struct
|
||||||
void fiq_handler(void) __attribute__((interrupt ("FIQ")));
|
void fiq_handler(void) __attribute__((interrupt ("FIQ")));
|
||||||
|
|
||||||
/* Mask the DMA interrupt */
|
/* Mask the DMA interrupt */
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
if (++dma_play_lock.locked == 1)
|
if (++dma_play_lock.locked == 1)
|
||||||
bitset32(&INTMSK, DMA2_MASK);
|
bitset32(&INTMSK, DMA2_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unmask the DMA interrupt if enabled */
|
/* Unmask the DMA interrupt if enabled */
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
if (--dma_play_lock.locked == 0)
|
if (--dma_play_lock.locked == 0)
|
||||||
bitclr32(&INTMSK, dma_play_lock.state);
|
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
|
/* There seem to be problems when changing the IIS interface configuration
|
||||||
* when a clock is not present.
|
* when a clock is not present.
|
||||||
|
|
@ -94,14 +95,9 @@ void pcm_play_dma_init(void)
|
||||||
bitset32(&INTMOD, DMA2_MASK);
|
bitset32(&INTMOD, DMA2_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
static void sink_set_freq(uint16_t freq)
|
||||||
{
|
{
|
||||||
audiohw_postinit();
|
audiohw_set_frequency(freq);
|
||||||
}
|
|
||||||
|
|
||||||
void pcm_dma_apply_settings(void)
|
|
||||||
{
|
|
||||||
audiohw_set_frequency(pcm_fsel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Connect the DMA and start filling the FIFO */
|
/* Connect the DMA and start filling the FIFO */
|
||||||
|
|
@ -158,7 +154,7 @@ static void play_stop_pcm(void)
|
||||||
IISCON &= ~(1<<0);
|
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 */
|
/* Enable the IIS clock */
|
||||||
bitset32(&CLKCON, 1<<17);
|
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 */
|
/* Promptly stop DMA transfers and stop IIS */
|
||||||
void pcm_play_dma_stop(void)
|
static void sink_dma_stop(void)
|
||||||
{
|
{
|
||||||
play_stop_pcm();
|
play_stop_pcm();
|
||||||
|
|
||||||
|
|
@ -219,3 +215,20 @@ void fiq_handler(void)
|
||||||
|
|
||||||
pcm_play_dma_status_callback(PCM_DMAST_STARTED);
|
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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,12 @@
|
||||||
#include "dma-target.h"
|
#include "dma-target.h"
|
||||||
#include "mmu-arm.h"
|
#include "mmu-arm.h"
|
||||||
#include "cpucache-arm.h"
|
#include "cpucache-arm.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
/* Driver for the IIS/PCM part of the s5l8700 using DMA
|
/* Driver for the IIS/PCM part of the s5l8700 using DMA
|
||||||
|
|
||||||
Notes:
|
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
|
- recording is not implemented
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -83,7 +84,7 @@ static const struct div_entry {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Mask the DMA interrupt */
|
/* Mask the DMA interrupt */
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
if (locked++ == 0) {
|
if (locked++ == 0) {
|
||||||
INTMSK &= ~(1 << 10);
|
INTMSK &= ~(1 << 10);
|
||||||
|
|
@ -91,7 +92,7 @@ void pcm_play_lock(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unmask the DMA interrupt if enabled */
|
/* Unmask the DMA interrupt if enabled */
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
if (--locked == 0) {
|
if (--locked == 0) {
|
||||||
INTMSK |= (1 << 10);
|
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 */
|
/* DMA channel on */
|
||||||
nextbuf = addr;
|
nextbuf = addr;
|
||||||
|
|
@ -161,7 +162,7 @@ void pcm_play_dma_start(const void* addr, size_t size)
|
||||||
(0 << 0); /* 0 = LRCK on */
|
(0 << 0); /* 0 = LRCK on */
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_stop(void)
|
static void sink_dma_stop(void)
|
||||||
{
|
{
|
||||||
/* DMA channel off */
|
/* DMA channel off */
|
||||||
DMACOM0 = 5;
|
DMACOM0 = 5;
|
||||||
|
|
@ -195,7 +196,7 @@ static void pcm_dma_set_freq(enum hw_freq_indexes idx)
|
||||||
(div.cdiv - 1); /* MCLK_DIV_VAL */
|
(div.cdiv - 1); /* MCLK_DIV_VAL */
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_init(void)
|
static void sink_dma_init(void)
|
||||||
{
|
{
|
||||||
/* configure IIS pins */
|
/* configure IIS pins */
|
||||||
#ifdef IPOD_NANO2G
|
#ifdef IPOD_NANO2G
|
||||||
|
|
@ -252,15 +253,10 @@ void pcm_play_dma_init(void)
|
||||||
audiohw_preinit();
|
audiohw_preinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
|
||||||
{
|
|
||||||
audiohw_postinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set the configured PCM frequency */
|
/* 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
|
#ifdef HAVE_PCM_DMA_ADDRESS
|
||||||
|
|
@ -272,6 +268,22 @@ void * pcm_dma_addr(void *addr)
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
** Recording DMA transfer
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include "pcm_sampr.h"
|
#include "pcm_sampr.h"
|
||||||
#include "pcm-target.h"
|
#include "pcm-target.h"
|
||||||
#include "dma-s5l8702.h"
|
#include "dma-s5l8702.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
/* DMA configuration */
|
/* DMA configuration */
|
||||||
|
|
||||||
|
|
@ -86,14 +87,14 @@ static int active_dblbuf;
|
||||||
size_t pcm_remaining;
|
size_t pcm_remaining;
|
||||||
|
|
||||||
/* Mask the DMA interrupt */
|
/* Mask the DMA interrupt */
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
if (locked++ == 0)
|
if (locked++ == 0)
|
||||||
dmac_ch_lock_int(&dma_play_ch);
|
dmac_ch_lock_int(&dma_play_ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unmask the DMA interrupt if enabled */
|
/* Unmask the DMA interrupt if enabled */
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
if (--locked == 0)
|
if (--locked == 0)
|
||||||
dmac_ch_unlock_int(&dma_play_ch);
|
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);
|
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;
|
pcm_remaining = size;
|
||||||
I2STXCOM = 0xe;
|
I2STXCOM = 0xe;
|
||||||
dma_play_callback((void*)addr);
|
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] */
|
/* MCLK = 12MHz (MCLKDIV2=1), [CS42L55 DS, s4.8] */
|
||||||
#define MCLK_FREQ 12000000
|
#define MCLK_FREQ 12000000
|
||||||
|
|
||||||
/* set the configured PCM frequency */
|
/* 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;
|
static uint16_t last_clkcon3l = 0;
|
||||||
uint16_t clkcon3l;
|
uint16_t clkcon3l;
|
||||||
int fsel;
|
|
||||||
|
|
||||||
/* For unknown reasons, s5l8702 I2S controller does not synchronize
|
/* For unknown reasons, s5l8702 I2S controller does not synchronize
|
||||||
* with CS42L55 at 32000 Hz. To fix it, the CODEC is configured with
|
* 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.
|
* obtaining 32 KHz in LRCK controller input and 8 MHz in SCLK input.
|
||||||
* OF uses this trick.
|
* OF uses this trick.
|
||||||
*/
|
*/
|
||||||
if (pcm_fsel == HW_FREQ_32) {
|
if (freq == HW_FREQ_32) {
|
||||||
fsel = HW_FREQ_48;
|
freq = HW_FREQ_48;
|
||||||
clkcon3l = 0x3028; /* PLL2 / 3 / 9 -> 8 MHz */
|
clkcon3l = 0x3028; /* PLL2 / 3 / 9 -> 8 MHz */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fsel = pcm_fsel;
|
|
||||||
clkcon3l = 0; /* OSC0 -> 12 MHz */
|
clkcon3l = 0; /* OSC0 -> 12 MHz */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,12 +191,12 @@ void pcm_dma_apply_settings(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* configure I2S clock ratio */
|
/* configure I2S clock ratio */
|
||||||
I2SCLKDIV = MCLK_FREQ / hw_freq_sampr[fsel];
|
I2SCLKDIV = MCLK_FREQ / hw_freq_sampr[freq];
|
||||||
/* select CS42L55 sample rate */
|
/* 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);
|
PWRCON(1) &= ~(1 << 7);
|
||||||
|
|
||||||
|
|
@ -207,12 +206,7 @@ void pcm_play_dma_init(void)
|
||||||
I2SCLKCON = 1;
|
I2SCLKCON = 1;
|
||||||
|
|
||||||
audiohw_preinit();
|
audiohw_preinit();
|
||||||
pcm_dma_apply_settings();
|
sink_set_freq(HW_FREQ_DEFAULT);
|
||||||
}
|
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
|
||||||
{
|
|
||||||
audiohw_postinit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_PCM_DMA_ADDRESS
|
#ifdef HAVE_PCM_DMA_ADDRESS
|
||||||
|
|
@ -222,6 +216,22 @@ void * pcm_dma_addr(void *addr)
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
** Recording DMA transfer
|
||||||
|
|
|
||||||
|
|
@ -20,37 +20,57 @@
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include "pcm.h"
|
#include "pcm.h"
|
||||||
#include "pcm-internal.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)
|
static void sink_dma_start(const void *addr, size_t size)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void pcm_play_dma_start(const void *addr, size_t size)
|
|
||||||
{
|
{
|
||||||
(void)addr;
|
(void)addr;
|
||||||
(void)size;
|
(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
|
#ifdef HAVE_RECORDING
|
||||||
void pcm_rec_dma_init(void)
|
void pcm_rec_dma_init(void)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,14 @@
|
||||||
#include "dsp-target.h"
|
#include "dsp-target.h"
|
||||||
#include "dsp/ipc.h"
|
#include "dsp/ipc.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
/* This is global to save some latency when pcm_play_dma_get_peak_buffer is
|
/* This is global to save some latency when pcm_play_dma_get_peak_buffer is
|
||||||
* called.
|
* called.
|
||||||
*/
|
*/
|
||||||
static const void *start;
|
static const void *start;
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
static void sink_dma_postinit(void)
|
||||||
{
|
{
|
||||||
/* Configure clock divider */
|
/* Configure clock divider */
|
||||||
tsc2100_writereg(CONTROL_PAGE2, TSPP1_ADDRESS, 0x1120);
|
tsc2100_writereg(CONTROL_PAGE2, TSPP1_ADDRESS, 0x1120);
|
||||||
|
|
@ -45,7 +46,7 @@ void pcm_play_dma_postinit(void)
|
||||||
audiohw_postinit();
|
audiohw_postinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_init(void)
|
static void sink_dma_init(void)
|
||||||
{
|
{
|
||||||
IO_INTC_IRQ0 = INTR_IRQ0_IMGBUF;
|
IO_INTC_IRQ0 = INTR_IRQ0_IMGBUF;
|
||||||
bitset16(&IO_INTC_EINT0, INTR_EINT0_IMGBUF);
|
bitset16(&IO_INTC_EINT0, INTR_EINT0_IMGBUF);
|
||||||
|
|
@ -67,15 +68,15 @@ void pcm_play_dma_init(void)
|
||||||
dsp_wake();
|
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
|
/* 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)
|
* 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;
|
unsigned long sdem_addr=(unsigned long)addr - CONFIG_SDRAM_START;
|
||||||
/* Initialize codec. */
|
/* Initialize codec. */
|
||||||
|
|
@ -87,18 +88,18 @@ void pcm_play_dma_start(const void *addr, size_t size)
|
||||||
dsp_wake();
|
dsp_wake();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_stop(void)
|
static void sink_dma_stop(void)
|
||||||
{
|
{
|
||||||
DSP_(_dma0_stopped)=1;
|
DSP_(_dma0_stopped)=1;
|
||||||
dsp_wake();
|
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);
|
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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include "dsp/ipc.h"
|
#include "dsp/ipc.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
#include "dma-target.h"
|
#include "dma-target.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
/* This is global to save some latency when pcm_play_dma_get_peak_buffer is
|
/* This is global to save some latency when pcm_play_dma_get_peak_buffer is
|
||||||
* called.
|
* called.
|
||||||
|
|
@ -36,12 +37,7 @@
|
||||||
static const void *start;
|
static const void *start;
|
||||||
static int dma_channel;
|
static int dma_channel;
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
static void sink_dma_init(void)
|
||||||
{
|
|
||||||
audiohw_postinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void pcm_play_dma_init(void)
|
|
||||||
{
|
{
|
||||||
/* GIO16 is DSP/AIC3X CLK */
|
/* GIO16 is DSP/AIC3X CLK */
|
||||||
IO_GIO_FSEL0 &= 0x3FFF;
|
IO_GIO_FSEL0 &= 0x3FFF;
|
||||||
|
|
@ -74,15 +70,15 @@ void pcm_play_dma_init(void)
|
||||||
dsp_wake();
|
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
|
/* 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)
|
* 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;
|
unsigned long sdem_addr=(unsigned long)addr - CONFIG_SDRAM_START;
|
||||||
/* Initialize codec. */
|
/* Initialize codec. */
|
||||||
|
|
@ -94,18 +90,18 @@ void pcm_play_dma_start(const void *addr, size_t size)
|
||||||
dsp_wake();
|
dsp_wake();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_stop(void)
|
static void sink_dma_stop(void)
|
||||||
{
|
{
|
||||||
DSP_(_dma0_stopped)=1;
|
DSP_(_dma0_stopped)=1;
|
||||||
dsp_wake();
|
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);
|
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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include "spdif.h"
|
#include "spdif.h"
|
||||||
#endif
|
#endif
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
|
#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
|
||||||
(IIS_PLAY & (7 << 8)) | \
|
(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
|
/* This clears the reset bit to enable monitoring immediately if monitoring
|
||||||
recording sources or always if playback is in progress - we might be
|
recording sources or always if playback is in progress - we might be
|
||||||
switching samplerates on the fly */
|
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);
|
int level = set_irq_level(DMA_IRQ_LEVEL);
|
||||||
|
|
||||||
/* remember table entry */
|
/* 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
|
/* Reprogramming bits 15-12 requires FIFO to be in a reset
|
||||||
condition - Users Manual 17-8, Note 11 */
|
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;
|
IIS_PLAY = IIS_PLAY_DEFPARM | IIS_FIFO_RESET;
|
||||||
restore_irq(level);
|
restore_irq(level);
|
||||||
|
|
||||||
audiohw_set_frequency(pcm_fsel);
|
audiohw_set_frequency(freq);
|
||||||
coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
|
coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
|
||||||
|
|
||||||
level = set_irq_level(DMA_IRQ_LEVEL);
|
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 */
|
PDOR3 = 0; /* Kick FIFO out of reset by writing to it */
|
||||||
|
|
||||||
restore_irq(level);
|
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;
|
AUDIOGLOB = AUDIOGLOB_DEFPARM;
|
||||||
DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
|
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);
|
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);
|
coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
|
||||||
|
|
||||||
#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT)
|
#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT)
|
||||||
spdif_init();
|
spdif_init();
|
||||||
#endif
|
#endif
|
||||||
} /* pcm_play_dma_init */
|
} /* sink_dma_init */
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
void sink_dma_postinit(void)
|
||||||
{
|
{
|
||||||
audiohw_postinit();
|
audiohw_postinit();
|
||||||
iis_play_reset();
|
iis_play_reset();
|
||||||
|
|
@ -223,23 +224,35 @@ static struct dma_lock dma_play_lock =
|
||||||
.state = (1 << 14) /* bit 14 is DMA0 */
|
.state = (1 << 14) /* bit 14 is DMA0 */
|
||||||
};
|
};
|
||||||
|
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
if (++dma_play_lock.locked == 1)
|
if (++dma_play_lock.locked == 1)
|
||||||
coldfire_imr_mod(1 << 14, 1 << 14);
|
coldfire_imr_mod(1 << 14, 1 << 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
if (--dma_play_lock.locked == 0)
|
if (--dma_play_lock.locked == 0)
|
||||||
coldfire_imr_mod(dma_play_lock.state, 1 << 14);
|
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 */
|
/* 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 */
|
/* Stop any DMA in progress */
|
||||||
pcm_play_dma_stop();
|
sink_dma_stop();
|
||||||
|
|
||||||
/* Set up DMA transfer */
|
/* Set up DMA transfer */
|
||||||
SAR0 = (unsigned long)addr; /* Source address */
|
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_SSIZE(DMA_SIZE_LINE) | DMA_START;
|
||||||
|
|
||||||
dma_play_lock.state = (0 << 14);
|
dma_play_lock.state = (0 << 14);
|
||||||
} /* pcm_play_dma_start */
|
} /* sink_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 */
|
|
||||||
|
|
||||||
/* DMA0 Interrupt is called when the DMA has finished transfering a chunk
|
/* DMA0 Interrupt is called when the DMA has finished transfering a chunk
|
||||||
from the caller's buffer */
|
from the caller's buffer */
|
||||||
|
|
@ -301,6 +302,23 @@ void DMA0(void)
|
||||||
/* else inished playing */
|
/* else inished playing */
|
||||||
} /* DMA0 */
|
} /* 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
|
#ifdef HAVE_RECORDING
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
** Recording DMA transfer
|
** Recording DMA transfer
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "pcm.h"
|
#include "pcm.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
|
#include "pcm_sampr.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
extern JNIEnv *env_ptr;
|
extern JNIEnv *env_ptr;
|
||||||
|
|
||||||
|
|
@ -133,23 +135,24 @@ Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this,
|
||||||
return max_size - left;
|
return max_size - left;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
if (++audio_locked == 1)
|
if (++audio_locked == 1)
|
||||||
lock_audio();
|
lock_audio();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
if (--audio_locked == 0)
|
if (--audio_locked == 0)
|
||||||
unlock_audio();
|
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_start = addr;
|
||||||
pcm_data_size = size;
|
pcm_data_size = size;
|
||||||
|
|
@ -160,7 +163,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
|
||||||
0);
|
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
|
/* NOTE: due to how pcm_play_dma_complete_callback() works, this is
|
||||||
* possibly called from nativeWrite(), i.e. another (host) thread
|
* possibly called from nativeWrite(), i.e. another (host) thread
|
||||||
|
|
@ -171,7 +174,7 @@ void pcm_play_dma_stop(void)
|
||||||
stop_method);
|
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,
|
/* in order to have background music playing after leaving the activity,
|
||||||
* we need to allocate the PCM object from the Rockbox thread (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");
|
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);
|
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
|
JNIEXPORT void JNICALL
|
||||||
Java_org_rockbox_RockboxPCM_postVolumeChangedEvent(JNIEnv *env,
|
Java_org_rockbox_RockboxPCM_postVolumeChangedEvent(JNIEnv *env,
|
||||||
jobject this,
|
jobject this,
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
#include "pcm_sampr.h"
|
#include "pcm_sampr.h"
|
||||||
#include "pcm_mixer.h"
|
#include "pcm_mixer.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
#include <3ds/ndsp/ndsp.h>
|
#include <3ds/ndsp/ndsp.h>
|
||||||
#include <3ds/ndsp/channel.h>
|
#include <3ds/ndsp/channel.h>
|
||||||
|
|
@ -102,14 +103,14 @@ static inline bool is_in_audio_thread(int audio_thread_id)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
if (!is_in_audio_thread(_pcm_thread_id)) {
|
if (!is_in_audio_thread(_pcm_thread_id)) {
|
||||||
RecursiveLock_Lock(&_pcm_lock_mtx);
|
RecursiveLock_Lock(&_pcm_lock_mtx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
if (!is_in_audio_thread(_pcm_thread_id)) {
|
if (!is_in_audio_thread(_pcm_thread_id)) {
|
||||||
RecursiveLock_Unlock(&_pcm_lock_mtx);
|
RecursiveLock_Unlock(&_pcm_lock_mtx);
|
||||||
|
|
@ -188,13 +189,13 @@ void dsp_callback(void *const nul_) {
|
||||||
LightEvent_Signal(&_dsp_callback_event);
|
LightEvent_Signal(&_dsp_callback_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pcm_dma_apply_settings_nolock(void)
|
static void sink_set_freq_nolock(uint16_t freq)
|
||||||
{
|
{
|
||||||
ndspChnReset(0);
|
ndspChnReset(0);
|
||||||
|
|
||||||
ndspSetOutputMode(NDSP_OUTPUT_STEREO);
|
ndspSetOutputMode(NDSP_OUTPUT_STEREO);
|
||||||
|
|
||||||
ndspChnSetRate(0, pcm_sampr);
|
ndspChnSetRate(0, hw_freq_sampr[freq]);
|
||||||
ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16);
|
ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16);
|
||||||
/* ndspChnSetInterp(0, NDSP_INTERP_POLYPHASE); */
|
/* ndspChnSetInterp(0, NDSP_INTERP_POLYPHASE); */
|
||||||
/* ndspChnSetInterp(0, NDSP_INTERP_NONE); */
|
/* ndspChnSetInterp(0, NDSP_INTERP_NONE); */
|
||||||
|
|
@ -235,7 +236,7 @@ static void pcm_dma_apply_settings_nolock(void)
|
||||||
-1, /* run on any core */ false);
|
-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 = addr;
|
||||||
_pcm_buffer_size = size;
|
_pcm_buffer_size = size;
|
||||||
|
|
@ -245,7 +246,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
|
||||||
RecursiveLock_Unlock(&_pcm_lock_mtx);
|
RecursiveLock_Unlock(&_pcm_lock_mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_stop(void)
|
static void sink_dma_stop(void)
|
||||||
{
|
{
|
||||||
RecursiveLock_Lock(&_pcm_lock_mtx);
|
RecursiveLock_Lock(&_pcm_lock_mtx);
|
||||||
ndspChnSetPaused(0, true);
|
ndspChnSetPaused(0, true);
|
||||||
|
|
@ -303,7 +304,7 @@ unsigned long spdif_measure_frequency(void)
|
||||||
|
|
||||||
#endif /* HAVE_RECORDING */
|
#endif /* HAVE_RECORDING */
|
||||||
|
|
||||||
void pcm_play_dma_init(void)
|
static void sink_dma_init(void)
|
||||||
{
|
{
|
||||||
Result ndsp_init_res = ndspInit();
|
Result ndsp_init_res = ndspInit();
|
||||||
if (R_FAILED(ndsp_init_res)) {
|
if (R_FAILED(ndsp_init_res)) {
|
||||||
|
|
@ -319,15 +320,15 @@ void pcm_play_dma_init(void)
|
||||||
LightEvent_Init(&_dsp_callback_event, RESET_ONESHOT);
|
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();
|
sink_lock();
|
||||||
pcm_dma_apply_settings_nolock();
|
sink_set_freq_nolock(freq);
|
||||||
pcm_play_unlock();
|
sink_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_close_device(void)
|
void pcm_close_device(void)
|
||||||
|
|
@ -357,3 +358,20 @@ void audiohw_close(void)
|
||||||
{
|
{
|
||||||
pcm_close_device();
|
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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
#include "pcm.h"
|
#include "pcm.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
|
#include "pcm_sampr.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
#include "sound/asound.h"
|
#include "sound/asound.h"
|
||||||
#include "tinyalsa/asoundlib.h"
|
#include "tinyalsa/asoundlib.h"
|
||||||
|
|
@ -187,26 +189,26 @@ static const unsigned int DEVICE = 0;
|
||||||
static struct pcm_config _config;
|
static struct pcm_config _config;
|
||||||
|
|
||||||
|
|
||||||
void pcm_play_dma_init(void)
|
static void sink_dma_init(void)
|
||||||
{
|
{
|
||||||
TRACE;
|
TRACE;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DEBUG pcm_play_dma_init: Access: 0x000009
|
DEBUG sink_dma_init: Access: 0x000009
|
||||||
DEBUG pcm_play_dma_init: Format[0]: 0x000044
|
DEBUG sink_dma_init: Format[0]: 0x000044
|
||||||
DEBUG pcm_play_dma_init: Format[1]: 0x000010
|
DEBUG sink_dma_init: Format[1]: 0x000010
|
||||||
DEBUG pcm_play_dma_init: Format: S16_LE
|
DEBUG sink_dma_init: Format: S16_LE
|
||||||
DEBUG pcm_play_dma_init: Format: S24_LE
|
DEBUG sink_dma_init: Format: S24_LE
|
||||||
DEBUG pcm_play_dma_init: Format: S20_3LE
|
DEBUG sink_dma_init: Format: S20_3LE
|
||||||
DEBUG pcm_play_dma_init: Subformat: 0x000001
|
DEBUG sink_dma_init: Subformat: 0x000001
|
||||||
DEBUG pcm_play_dma_init: Rate: min = 8000Hz, max = 192000Hz
|
DEBUG sink_dma_init: Rate: min = 8000Hz, max = 192000Hz
|
||||||
DEBUG pcm_play_dma_init: Channels: min = 2, max = 2
|
DEBUG sink_dma_init: Channels: min = 2, max = 2
|
||||||
DEBUG pcm_play_dma_init: Sample bits: min=16, max=32
|
DEBUG sink_dma_init: Sample bits: min=16, max=32
|
||||||
DEBUG pcm_play_dma_init: Period size: min=8, max=10922
|
DEBUG sink_dma_init: Period size: min=8, max=10922
|
||||||
DEBUG pcm_play_dma_init: Period count: min=3, max=128
|
DEBUG sink_dma_init: Period count: min=3, max=128
|
||||||
DEBUG pcm_play_dma_init: 0 mixer controls.
|
DEBUG sink_dma_init: 0 mixer controls.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct pcm_params* params = pcm_params_get(CARD, DEVICE, PCM_OUT);
|
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.
|
pcm_thread_run relies on this size match. See pcm_mixer.h.
|
||||||
*/
|
*/
|
||||||
_config.channels = 2;
|
_config.channels = 2;
|
||||||
_config.rate = pcm_sampr;
|
_config.rate = hw_freq_sampr[HW_FREQ_DEFAULT];
|
||||||
_config.period_size = 256;
|
_config.period_size = 256;
|
||||||
_config.period_count = 4;
|
_config.period_count = 4;
|
||||||
_config.format = PCM_FORMAT_S16_LE;
|
_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;
|
TRACE;
|
||||||
|
|
||||||
|
|
@ -364,7 +366,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
|
||||||
pthread_mutex_unlock(&_dma_suspended_mtx);
|
pthread_mutex_unlock(&_dma_suspended_mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_stop(void)
|
static void sink_dma_stop(void)
|
||||||
{
|
{
|
||||||
TRACE;
|
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;
|
static int _play_lock_recursion_count = -10000;
|
||||||
|
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
static void sink_dma_postinit(void)
|
||||||
{
|
{
|
||||||
TRACE;
|
TRACE;
|
||||||
|
|
||||||
|
|
@ -387,7 +389,7 @@ void pcm_play_dma_postinit(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
TRACE;
|
TRACE;
|
||||||
|
|
||||||
|
|
@ -402,7 +404,7 @@ void pcm_play_lock(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
TRACE;
|
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);
|
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);
|
pcm_close(_alsa_handle);
|
||||||
_alsa_handle = NULL;
|
_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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
#include "pcm_mixer.h"
|
#include "pcm_mixer.h"
|
||||||
#include "pcm_sampr.h"
|
#include "pcm_sampr.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
#include "audiohw.h"
|
#include "audiohw.h"
|
||||||
#include "pcm-alsa.h"
|
#include "pcm-alsa.h"
|
||||||
#include "fixedpoint.h"
|
#include "fixedpoint.h"
|
||||||
|
|
@ -122,7 +123,7 @@ void pcm_alsa_set_capture_device(const char *device)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int set_hwparams(snd_pcm_t *handle)
|
static int set_hwparams(snd_pcm_t *handle, unsigned long sampr)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
unsigned int srate;
|
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
|
Note these are in FRAMES, and are sized to be about 8.5ms
|
||||||
for the buffer and 2.1ms for the period
|
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;
|
buffer_size = MIX_FRAME_SAMPLES * 4 * 4;
|
||||||
period_size = MIX_FRAME_SAMPLES * 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;
|
buffer_size = MIX_FRAME_SAMPLES * 2 * 4;
|
||||||
period_size = MIX_FRAME_SAMPLES * 2;
|
period_size = MIX_FRAME_SAMPLES * 2;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -176,17 +177,17 @@ static int set_hwparams(snd_pcm_t *handle)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
/* set the stream rate */
|
/* set the stream rate */
|
||||||
srate = pcm_sampr;
|
srate = sampr;
|
||||||
err = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0);
|
err = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0);
|
||||||
if (err < 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;
|
goto error;
|
||||||
}
|
}
|
||||||
real_sample_rate = srate;
|
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;
|
err = -EINVAL;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
@ -595,7 +596,7 @@ static void open_hwdev(const char *device, snd_pcm_stream_t mode)
|
||||||
atexit(alsadev_cleanup);
|
atexit(alsadev_cleanup);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_init(void)
|
static void sink_dma_init(void)
|
||||||
{
|
{
|
||||||
logf("PCM DMA Init");
|
logf("PCM DMA Init");
|
||||||
|
|
||||||
|
|
@ -606,48 +607,50 @@ void pcm_play_dma_init(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&pcm_mtx);
|
pthread_mutex_lock(&pcm_mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
pthread_mutex_unlock(&pcm_mtx);
|
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
|
#ifdef AUDIOHW_MUTE_ON_SRATE_CHANGE
|
||||||
audiohw_mute(true);
|
audiohw_mute(true);
|
||||||
#endif
|
#endif
|
||||||
snd_pcm_drop(handle);
|
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?
|
set_swparams(handle); // FIXME: check return code?
|
||||||
|
|
||||||
#if defined(HAVE_NWZ_LINUX_CODEC)
|
#if defined(HAVE_NWZ_LINUX_CODEC)
|
||||||
/* Sony NWZ linux driver uses a nonstandard mecanism to set the sampling rate */
|
/* Sony NWZ linux driver uses a nonstandard mecanism to set the sampling rate */
|
||||||
audiohw_set_frequency(pcm_sampr);
|
audiohw_set_frequency(sampr);
|
||||||
#endif
|
#endif
|
||||||
/* (Will be unmuted by pcm resuming) */
|
/* (Will be unmuted by pcm resuming) */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_dma_apply_settings(void)
|
static void sink_set_freq(uint16_t freq)
|
||||||
{
|
{
|
||||||
pcm_play_lock();
|
sink_lock();
|
||||||
pcm_dma_apply_settings_nolock();
|
sink_set_freq_nolock(freq);
|
||||||
pcm_play_unlock();
|
sink_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_stop(void)
|
static void sink_dma_stop(void)
|
||||||
{
|
{
|
||||||
logf("PCM DMA stop (%d)", snd_pcm_state(handle));
|
logf("PCM DMA stop (%d)", snd_pcm_state(handle));
|
||||||
|
|
||||||
|
|
@ -660,10 +663,9 @@ void pcm_play_dma_stop(void)
|
||||||
#endif
|
#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);
|
logf("PCM DMA start (%p %d)", addr, size);
|
||||||
pcm_dma_apply_settings_nolock();
|
|
||||||
|
|
||||||
pcm_data = addr;
|
pcm_data = addr;
|
||||||
pcm_size = size;
|
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();
|
audiohw_postinit();
|
||||||
|
|
||||||
|
|
@ -768,15 +770,32 @@ unsigned int pcm_alsa_get_xruns(void)
|
||||||
return xruns;
|
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
|
#ifdef HAVE_RECORDING
|
||||||
void pcm_rec_lock(void)
|
void pcm_rec_lock(void)
|
||||||
{
|
{
|
||||||
pcm_play_lock();
|
sink_lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_rec_unlock(void)
|
void pcm_rec_unlock(void)
|
||||||
{
|
{
|
||||||
pcm_play_unlock();
|
sink_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_rec_dma_init(void)
|
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)
|
void pcm_rec_dma_start(void *start, size_t size)
|
||||||
{
|
{
|
||||||
logf("PCM REC DMA start (%p %d)", start, size);
|
logf("PCM REC DMA start (%p %d)", start, size);
|
||||||
pcm_dma_apply_settings_nolock();
|
|
||||||
pcm_data_rec = start;
|
pcm_data_rec = start;
|
||||||
pcm_size = size;
|
pcm_size = size;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
#include "pcm_sampr.h"
|
#include "pcm_sampr.h"
|
||||||
#include "pcm_mixer.h"
|
#include "pcm_mixer.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
|
|
||||||
/*#define LOGF_ENABLE*/
|
/*#define LOGF_ENABLE*/
|
||||||
#include "logf.h"
|
#include "logf.h"
|
||||||
|
|
@ -57,6 +58,8 @@ extern const char *audiodev;
|
||||||
|
|
||||||
static int cvt_status = -1;
|
static int cvt_status = -1;
|
||||||
|
|
||||||
|
static unsigned long pcm_sampr;
|
||||||
|
|
||||||
static const void *pcm_data;
|
static const void *pcm_data;
|
||||||
static size_t pcm_data_size;
|
static size_t pcm_data_size;
|
||||||
static size_t pcm_sample_bytes;
|
static size_t pcm_sample_bytes;
|
||||||
|
|
@ -80,13 +83,13 @@ static SDL_AudioCVT cvt;
|
||||||
static int audio_locked = 0;
|
static int audio_locked = 0;
|
||||||
static SDL_mutex *audio_lock;
|
static SDL_mutex *audio_lock;
|
||||||
|
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
if (++audio_locked == 1)
|
if (++audio_locked == 1)
|
||||||
SDL_LockMutex(audio_lock);
|
SDL_LockMutex(audio_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
if (--audio_locked == 0)
|
if (--audio_locked == 0)
|
||||||
SDL_UnlockMutex(audio_lock);
|
SDL_UnlockMutex(audio_lock);
|
||||||
|
|
@ -97,8 +100,11 @@ void pcm_play_unlock(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void sdl_audio_callback(void *handle, Uint8 *stream, int len);
|
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;
|
SDL_AudioSpec wanted_spec;
|
||||||
wanted_spec.freq = pcm_sampr;
|
wanted_spec.freq = pcm_sampr;
|
||||||
wanted_spec.format = AUDIO_S16SYS;
|
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();
|
sink_lock();
|
||||||
pcm_dma_apply_settings_nolock();
|
sink_set_freq_nolock(freq);
|
||||||
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_data = addr;
|
pcm_data = addr;
|
||||||
pcm_data_size = size;
|
pcm_data_size = size;
|
||||||
|
|
@ -180,7 +186,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_stop(void)
|
static void sink_dma_stop(void)
|
||||||
{
|
{
|
||||||
#if SDL_MAJOR_VERSION > 1
|
#if SDL_MAJOR_VERSION > 1
|
||||||
SDL_PauseAudioDevice(pcm_devid, 1);
|
SDL_PauseAudioDevice(pcm_devid, 1);
|
||||||
|
|
@ -397,7 +403,7 @@ unsigned long spdif_measure_frequency(void)
|
||||||
|
|
||||||
#endif /* HAVE_RECORDING */
|
#endif /* HAVE_RECORDING */
|
||||||
|
|
||||||
void pcm_play_dma_init(void)
|
static void sink_dma_init(void)
|
||||||
{
|
{
|
||||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO))
|
if (SDL_InitSubSystem(SDL_INIT_AUDIO))
|
||||||
{
|
{
|
||||||
|
|
@ -435,6 +441,23 @@ void pcm_play_dma_init(void)
|
||||||
#endif
|
#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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -26,14 +26,14 @@
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "pcm.h"
|
#include "pcm.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
#include "jz4740.h"
|
#include "jz4740.h"
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
** Playback DMA transfer
|
** Playback DMA transfer
|
||||||
**/
|
**/
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
static void sink_dma_postinit(void)
|
||||||
{
|
{
|
||||||
audiohw_postinit();
|
audiohw_postinit();
|
||||||
|
|
||||||
|
|
@ -47,7 +47,7 @@ void pcm_play_dma_postinit(void)
|
||||||
__aic_flush_fifo();
|
__aic_flush_fifo();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_init(void)
|
static void sink_dma_init(void)
|
||||||
{
|
{
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
|
||||||
|
|
@ -57,10 +57,10 @@ void pcm_play_dma_init(void)
|
||||||
audiohw_init();
|
audiohw_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_dma_apply_settings(void)
|
static void sink_set_freq(uint16_t freq)
|
||||||
{
|
{
|
||||||
/* TODO */
|
/* TODO */
|
||||||
audiohw_set_frequency(pcm_sampr);
|
audiohw_set_frequency(freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const void* playback_address;
|
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)
|
static void sink_dma_stop(void)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
int flags = disable_irq_save();
|
int flags = disable_irq_save();
|
||||||
|
|
||||||
|
|
@ -163,8 +149,22 @@ void pcm_play_dma_stop(void)
|
||||||
restore_irq(flags);
|
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;
|
static unsigned int play_lock = 0;
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
int flags = disable_irq_save();
|
int flags = disable_irq_save();
|
||||||
|
|
||||||
|
|
@ -174,7 +174,7 @@ void pcm_play_lock(void)
|
||||||
restore_irq(flags);
|
restore_irq(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
int flags = disable_irq_save();
|
int flags = disable_irq_save();
|
||||||
|
|
||||||
|
|
@ -189,6 +189,23 @@ void audiohw_close(void)
|
||||||
/* TODO: prevent pop */
|
/* 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
|
#ifdef HAVE_RECORDING
|
||||||
/* TODO */
|
/* TODO */
|
||||||
void pcm_rec_dma_init(void)
|
void pcm_rec_dma_init(void)
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,14 @@
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "pcm.h"
|
#include "pcm.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
** Playback DMA transfer
|
** Playback DMA transfer
|
||||||
**/
|
**/
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
static void sink_dma_postinit(void)
|
||||||
{
|
{
|
||||||
audiohw_postinit();
|
audiohw_postinit();
|
||||||
|
|
||||||
|
|
@ -40,7 +41,7 @@ void pcm_play_dma_postinit(void)
|
||||||
__aic_flush_tfifo();
|
__aic_flush_tfifo();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_init(void)
|
static void sink_dma_init(void)
|
||||||
{
|
{
|
||||||
system_enable_irq(DMA_IRQ(DMA_AIC_TX_CHANNEL));
|
system_enable_irq(DMA_IRQ(DMA_AIC_TX_CHANNEL));
|
||||||
|
|
||||||
|
|
@ -48,9 +49,9 @@ void pcm_play_dma_init(void)
|
||||||
audiohw_init();
|
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;
|
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)
|
static void sink_dma_stop(void)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
int flags = disable_irq_save();
|
int flags = disable_irq_save();
|
||||||
|
|
||||||
|
|
@ -152,8 +140,21 @@ void pcm_play_dma_stop(void)
|
||||||
restore_irq(flags);
|
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;
|
static unsigned int play_lock = 0;
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
int flags = disable_irq_save();
|
int flags = disable_irq_save();
|
||||||
|
|
||||||
|
|
@ -163,7 +164,7 @@ void pcm_play_lock(void)
|
||||||
restore_irq(flags);
|
restore_irq(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
int flags = disable_irq_save();
|
int flags = disable_irq_save();
|
||||||
|
|
||||||
|
|
@ -172,3 +173,20 @@ void pcm_play_unlock(void)
|
||||||
|
|
||||||
restore_irq(flags);
|
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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include "audiohw.h"
|
#include "audiohw.h"
|
||||||
#include "pcm.h"
|
#include "pcm.h"
|
||||||
#include "pcm-internal.h"
|
#include "pcm-internal.h"
|
||||||
|
#include "pcm_sink.h"
|
||||||
#include "panic.h"
|
#include "panic.h"
|
||||||
#include "dma-x1000.h"
|
#include "dma-x1000.h"
|
||||||
#include "irq-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);
|
static void pcm_rec_dma_int_cb(int event);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void pcm_play_dma_init(void)
|
static void sink_dma_init(void)
|
||||||
{
|
{
|
||||||
/* Ungate clock */
|
/* Ungate clock */
|
||||||
jz_writef(CPM_CLKGR, AIC(0));
|
jz_writef(CPM_CLKGR, AIC(0));
|
||||||
|
|
@ -99,14 +100,9 @@ void pcm_play_dma_init(void)
|
||||||
system_enable_irq(IRQ_AIC);
|
system_enable_irq(IRQ_AIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_dma_postinit(void)
|
static void sink_set_freq(uint16_t freq)
|
||||||
{
|
{
|
||||||
audiohw_postinit();
|
audiohw_set_frequency(freq);
|
||||||
}
|
|
||||||
|
|
||||||
void pcm_dma_apply_settings(void)
|
|
||||||
{
|
|
||||||
audiohw_set_frequency(pcm_fsel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void play_dma_start(const void* addr, size_t size)
|
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;
|
play_dma_pending_event = DMA_EVENT_NONE;
|
||||||
aic_state |= AIC_STATE_PLAYING;
|
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));
|
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 */
|
/* disable DMA and underrun interrupts */
|
||||||
jz_writef(AIC_CCR, TDMS(0), ETUR(0));
|
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) {
|
if (jz_readf(AIC_I2SCR, STPBK) == 0) {
|
||||||
while(jz_readf(AIC_SR, TFL) != 0);
|
while(jz_readf(AIC_SR, TFL) != 0);
|
||||||
} else {
|
} else {
|
||||||
panicf("pcm_play_dma_stop: No bit clock running!");
|
panicf("sink_dma_stop: No bit clock running!");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* disable playback */
|
/* disable playback */
|
||||||
|
|
@ -190,14 +186,14 @@ void pcm_play_dma_stop(void)
|
||||||
aic_state &= ~AIC_STATE_PLAYING;
|
aic_state &= ~AIC_STATE_PLAYING;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_lock(void)
|
static void sink_lock(void)
|
||||||
{
|
{
|
||||||
int irq = disable_irq_save();
|
int irq = disable_irq_save();
|
||||||
++play_lock;
|
++play_lock;
|
||||||
restore_irq(irq);
|
restore_irq(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_play_unlock(void)
|
static void sink_unlock(void)
|
||||||
{
|
{
|
||||||
int irq = disable_irq_save();
|
int irq = disable_irq_save();
|
||||||
if(--play_lock == 0 && (aic_state & AIC_STATE_PLAYING)) {
|
if(--play_lock == 0 && (aic_state & AIC_STATE_PLAYING)) {
|
||||||
|
|
@ -208,6 +204,23 @@ void pcm_play_unlock(void)
|
||||||
restore_irq(irq);
|
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
|
#ifdef HAVE_RECORDING
|
||||||
/*
|
/*
|
||||||
* Recording
|
* Recording
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue