mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-21 22:31:51 +00:00
http://forum.armbian.com/index.php/topic/1396-kernel-panic-when-playing-video-with-spdif-audio-output/
214 lines
7.9 KiB
Diff
214 lines
7.9 KiB
Diff
From 1c0859a723e350d2ea9b82f0343da6195722b566 Mon Sep 17 00:00:00 2001
|
|
From: Nikolay <nikkov@gmail.com>
|
|
Date: Mon, 4 Apr 2016 19:38:48 +0600
|
|
Subject: [PATCH 17/19] SPDIF experiments
|
|
|
|
---
|
|
sound/soc/sunxi/spdif/sunxi_spdif.c | 92 +++++++++++++++----------------------
|
|
sound/soc/sunxi/spdif/sunxi_spdma.c | 11 ++---
|
|
2 files changed, 41 insertions(+), 62 deletions(-)
|
|
|
|
diff --git a/sound/soc/sunxi/spdif/sunxi_spdif.c b/sound/soc/sunxi/spdif/sunxi_spdif.c
|
|
index 5400e3f..9608b14 100644
|
|
--- a/sound/soc/sunxi/spdif/sunxi_spdif.c
|
|
+++ b/sound/soc/sunxi/spdif/sunxi_spdif.c
|
|
@@ -62,51 +62,39 @@ static struct clk *spdif_apbclk, *spdif_pll2clk, *spdif_pllx8, *spdif_moduleclk;
|
|
void sunxi_snd_txctrl(struct snd_pcm_substream *substream, int on)
|
|
{
|
|
u32 reg_val;
|
|
+ if (on) {
|
|
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
|
|
+ reg_val |= SUNXI_SPDIF_FCTL_FTX; //flush TX FIFO
|
|
+ reg_val |= SUNXI_SPDIF_FCTL_TXTL(0x10); //TX FIFO empty Trigger Level
|
|
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
|
|
|
|
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
|
|
- if (substream->runtime->channels == 1) {
|
|
- reg_val |= SUNXI_SPDIF_TXCFG_SINGLEMOD;
|
|
- }
|
|
- else {
|
|
- reg_val &= ~SUNXI_SPDIF_TXCFG_SINGLEMOD;
|
|
- }
|
|
- reg_val |= SUNXI_SPDIF_TXCFG_ASS; //Sending the last audio (may be 0?)
|
|
- reg_val |= SUNXI_SPDIF_TXCFG_CHSTMODE; //Channel status A&B generated form TX_CHSTA
|
|
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
|
|
-
|
|
- /*flush TX FIFO and set FIFO empty trigger level*/
|
|
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
|
|
- reg_val |= SUNXI_SPDIF_FCTL_TXTL(0x10); //TX FIFO empty Trigger Level
|
|
- reg_val |= SUNXI_SPDIF_FCTL_FTX; //flush TX FIFO
|
|
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
|
|
-
|
|
- /*clear interrupt status*/
|
|
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_ISTA);
|
|
- reg_val |= SUNXI_SPDIF_ISTA_TXCLR;
|
|
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_ISTA);
|
|
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_ISTA);
|
|
+ reg_val |= SUNXI_SPDIF_ISTA_TXCLR; //clear interrupt status
|
|
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_ISTA);
|
|
|
|
- /*clear TX counter*/
|
|
- writel(0, sunxi_spdif.regs + SUNXI_SPDIF_TXCNT);
|
|
+ writel(0, sunxi_spdif.regs + SUNXI_SPDIF_TXCNT); //clear TX counter
|
|
|
|
- if (on) {
|
|
- //SPDIF TX ENABLE
|
|
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
|
|
- reg_val |= SUNXI_SPDIF_TXCFG_TXEN;
|
|
+ if (substream->runtime->channels == 1)
|
|
+ reg_val |= SUNXI_SPDIF_TXCFG_SINGLEMOD;
|
|
+ else
|
|
+ reg_val &= ~SUNXI_SPDIF_TXCFG_SINGLEMOD;
|
|
+ reg_val |= SUNXI_SPDIF_TXCFG_ASS; //Sending the last audio (may be 0?)
|
|
+ reg_val |= SUNXI_SPDIF_TXCFG_CHSTMODE; //Channel status A&B generated form TX_CHSTA
|
|
+ reg_val |= SUNXI_SPDIF_TXCFG_TXEN; //SPDIF TX ENABLE
|
|
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
|
|
|
|
- //DRQ ENABLE
|
|
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_INT);
|
|
- reg_val |= SUNXI_SPDIF_INT_TXDRQEN;
|
|
+ reg_val |= SUNXI_SPDIF_INT_TXDRQEN; //DRQ ENABLE
|
|
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_INT);
|
|
+
|
|
} else {
|
|
- //SPDIF TX DISABLE
|
|
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
|
|
- reg_val &= ~SUNXI_SPDIF_TXCFG_TXEN;
|
|
+ reg_val &= ~SUNXI_SPDIF_TXCFG_TXEN; //SPDIF TX DISABLE
|
|
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
|
|
|
|
- //DRQ DISABLE
|
|
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_INT);
|
|
- reg_val &= ~SUNXI_SPDIF_INT_TXDRQEN;
|
|
+ reg_val &= ~SUNXI_SPDIF_INT_TXDRQEN; //DRQ DISABLE
|
|
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_INT);
|
|
}
|
|
}
|
|
@@ -114,40 +102,33 @@ void sunxi_snd_txctrl(struct snd_pcm_substream *substream, int on)
|
|
void sunxi_snd_rxctrl(struct snd_pcm_substream *substream, int on)
|
|
{
|
|
u32 reg_val;
|
|
-
|
|
- /*flush RX FIFO and set FIFO empty trigger level*/
|
|
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
|
|
- reg_val |= SUNXI_SPDIF_FCTL_RXTL(0x0F); //RX FIFO Trigger Level
|
|
- reg_val |= SUNXI_SPDIF_FCTL_FRX; //flush RX FIFO
|
|
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
|
|
-
|
|
- /*clear interrupt status*/
|
|
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_ISTA);
|
|
- reg_val |= SUNXI_SPDIF_ISTA_RXCLR;
|
|
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_ISTA);
|
|
|
|
- /*clear RX counter*/
|
|
- writel(0, sunxi_spdif.regs + SUNXI_SPDIF_RXCNT);
|
|
-
|
|
if (on) {
|
|
- /*SPDIF RX ENABLE*/
|
|
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
|
|
+ reg_val |= SUNXI_SPDIF_FCTL_RXTL(0x0F); //RX FIFO Trigger Level
|
|
+ reg_val |= SUNXI_SPDIF_FCTL_FRX; //flush RX FIFO
|
|
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
|
|
+
|
|
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_ISTA);
|
|
+ reg_val |= SUNXI_SPDIF_ISTA_RXCLR; //clear interrupt status
|
|
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_ISTA);
|
|
+
|
|
+ writel(0, sunxi_spdif.regs + SUNXI_SPDIF_RXCNT); //clear RX counter
|
|
+
|
|
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_RXCFG);
|
|
- reg_val |= SUNXI_SPDIF_RXCFG_RXEN;
|
|
+ reg_val |= SUNXI_SPDIF_RXCFG_RXEN; //SPDIF RX ENABLE
|
|
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_RXCFG);
|
|
|
|
- /*DRQ ENABLE*/
|
|
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_INT);
|
|
- reg_val |= SUNXI_SPDIF_INT_RXDRQEN;
|
|
+ reg_val |= SUNXI_SPDIF_INT_RXDRQEN; //DRQ ENABLE
|
|
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_INT);
|
|
} else {
|
|
- /*SPDIF TX DISABLE*/
|
|
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_RXCFG);
|
|
- reg_val &= ~SUNXI_SPDIF_RXCFG_RXEN;
|
|
+ reg_val &= ~SUNXI_SPDIF_RXCFG_RXEN; //SPDIF RX DISABLE
|
|
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_RXCFG);
|
|
|
|
- /*DRQ DISABLE*/
|
|
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_INT);
|
|
- reg_val &= ~SUNXI_SPDIF_INT_RXDRQEN;
|
|
+ reg_val &= ~SUNXI_SPDIF_INT_RXDRQEN; //DRQ DISABLE
|
|
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_INT);
|
|
}
|
|
}
|
|
@@ -286,8 +267,7 @@ static int sunxi_spdif_trigger(struct snd_pcm_substream *substream,
|
|
{
|
|
int ret = 0;
|
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
|
- struct sunxi_dma_params *dma_data =
|
|
- snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
|
+ struct sunxi_dma_params *dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
|
|
|
switch (cmd) {
|
|
case SNDRV_PCM_TRIGGER_START:
|
|
diff --git a/sound/soc/sunxi/spdif/sunxi_spdma.c b/sound/soc/sunxi/spdif/sunxi_spdma.c
|
|
index d5377fc..b2af6a9 100644
|
|
--- a/sound/soc/sunxi/spdif/sunxi_spdma.c
|
|
+++ b/sound/soc/sunxi/spdif/sunxi_spdma.c
|
|
@@ -45,7 +45,7 @@ static const struct snd_pcm_hardware sunxi_pcm_out_hardware = {
|
|
.channels_min = 1,
|
|
.channels_max = 2,
|
|
.buffer_bytes_max = 128*1024, /* value must be (2^n)Kbyte size */
|
|
- .period_bytes_min = 1024,//1024*4,
|
|
+ .period_bytes_min = 1024*4,
|
|
.period_bytes_max = 1024*32,//1024*128,
|
|
.periods_min = 4,
|
|
.periods_max = 8,
|
|
@@ -63,7 +63,7 @@ static const struct snd_pcm_hardware sunxi_pcm_in_hardware = {
|
|
.channels_min = 1,
|
|
.channels_max = 2,
|
|
.buffer_bytes_max = 128*1024, /* value must be (2^n)Kbyte size */
|
|
- .period_bytes_min = 1024,//1024*4,
|
|
+ .period_bytes_min = 1024*4,
|
|
.period_bytes_max = 1024*32,//1024*128,
|
|
.periods_min = 4,
|
|
.periods_max = 8,
|
|
@@ -88,12 +88,11 @@ static void sunxi_pcm_enqueue(struct snd_pcm_substream *substream)
|
|
{
|
|
struct sunxi_runtime_data *prtd = substream->runtime->private_data;
|
|
dma_addr_t pos = prtd->dma_pos;
|
|
- unsigned int limit;
|
|
int ret;
|
|
+ unsigned int limit = prtd->dma_limit;
|
|
unsigned long len = prtd->dma_period;
|
|
int read = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
|
|
|
|
- limit = prtd->dma_limit;
|
|
while(prtd->dma_loaded < limit){
|
|
if((pos + len) > prtd->dma_end){
|
|
len = prtd->dma_end - pos;
|
|
@@ -296,15 +295,20 @@ static int sunxi_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|
case SNDRV_PCM_TRIGGER_START:
|
|
case SNDRV_PCM_TRIGGER_RESUME:
|
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
|
- sunxi_dma_start(prtd->params);
|
|
prtd->state |= ST_RUNNING;
|
|
+ /* enqueue dma buffers */
|
|
+ sunxi_pcm_enqueue(substream);
|
|
+ sunxi_dma_start(prtd->params);
|
|
+ ret =0;
|
|
break;
|
|
|
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
|
case SNDRV_PCM_TRIGGER_STOP:
|
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
|
- sunxi_dma_stop(prtd->params);
|
|
prtd->state &= ~ST_RUNNING;
|
|
+ sunxi_dma_stop(prtd->params);
|
|
+ prtd->dma_loaded = 0;
|
|
+ ret = 0;
|
|
break;
|
|
|
|
default:
|
|
--
|
|
1.9.1
|
|
|