audio: auge: init spdif_b when bootup and add channel status

PD#165171: audio: auge: init spdif_b when bootup and add channel status

Change-Id: I001d74a0f21fb3f02edf741bd3b87d45dfddcd5f
Signed-off-by: Xing Wang <xing.wang@amlogic.com>
This commit is contained in:
Xing Wang
2018-04-30 21:12:28 +08:00
committed by Yixun Lan
parent 2c4f36cf8e
commit cc26d57309
25 changed files with 538 additions and 130 deletions

View File

@@ -14454,3 +14454,13 @@ F: drivers/amlogic/media/dtv_demod/*
AMLOGIC DEFENDKEY DRIVER
M: Zhongfu Luo <zhongfu.luo@amlogic.com>
F: drivers/amlogic/defendkey/*
AMLOGIC DEBUG
M: Jianxin Pan <jianxin.pan@amlogic.com>
F: drivers/amlogic/debug/
AMLOGIC G12A spdif channel status
M: xing wang<xing.wang@amlogic.com>
F: arch/arm64/boot/dts/amlogic/g12a_*
F: include/linux/amlogic/media/sound/spdif_info.h
F: sound/soc/amlogic/auge*

View File

@@ -587,6 +587,7 @@
aml-audio-card,dai-link@4 {
mclk-fs = <128>;
//continuous-clock;
/* suffix-name, sync with android audio hal
* what's the dai link used for
*/
@@ -602,6 +603,7 @@
/* spdif_b to hdmi, only playback */
aml-audio-card,dai-link@5 {
mclk-fs = <128>;
continuous-clock;
/* suffix-name, sync with android audio hal
* what's the dai link used for
*/

View File

@@ -670,6 +670,7 @@
/* spdif_b to hdmi, only playback */
aml-audio-card,dai-link@5 {
mclk-fs = <128>;
continuous-clock;
/* suffix-name, sync with android audio hal
* what's the dai link used for
*/

View File

@@ -671,6 +671,7 @@
/* spdif_b to hdmi, only playback */
aml-audio-card,dai-link@5 {
mclk-fs = <128>;
continuous-clock;
/* suffix-name, sync with android audio hal
* what's the dai link used for
*/

View File

@@ -589,6 +589,7 @@
/* spdif_b to hdmi, only playback */
aml-audio-card,dai-link@5 {
mclk-fs = <128>;
continuous-clock;
/* suffix-name, sync with android audio hal
* what's the dai link used for
*/

View File

@@ -603,6 +603,7 @@
/* spdif_b to hdmi, only playback */
aml-audio-card,dai-link@5 {
mclk-fs = <128>;
continuous-clock;
/* suffix-name, sync with android audio hal
* what's the dai link used for
*/

View File

@@ -700,6 +700,7 @@
/* spdif_b to hdmi, only playback */
aml-audio-card,dai-link@5 {
mclk-fs = <128>;
continuous-clock;
/* suffix-name, sync with android audio hal
* what's the dai link used for
*/

View File

@@ -563,6 +563,7 @@
/* spdif_b to hdmi, only playback */
aml-audio-card,dai-link@5 {
mclk-fs = <128>;
continuous-clock;
/* suffix-name, sync with android audio hal
* what's the dai link used for
*/

View File

@@ -0,0 +1,37 @@
/*
* include/linux/amlogic/media/sound/spdif_info.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* 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 program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef __SPDIF_INFO_H__
#define __SPDIF_INFO_H__
#include <sound/pcm.h>
struct iec958_chsts {
unsigned short chstat0_l;
unsigned short chstat1_l;
unsigned short chstat0_r;
unsigned short chstat1_r;
};
extern bool spdif_is_4x_clk(void);
extern void spdif_get_channel_status_info(struct iec958_chsts *chsts,
unsigned int rate);
extern void spdif_notify_to_hdmitx(struct snd_pcm_substream *substream);
#endif

View File

@@ -510,15 +510,18 @@ static int aml_card_dai_init(struct snd_soc_pcm_runtime *rtd)
bool idle_clk = false;
int ret, i;
/* enable dai-link mclk when CONTINUOUS clk setted */
idle_clk = !!(rtd->dai_link->dai_fmt & SND_SOC_DAIFMT_CONT);
for (i = 0; i < rtd->num_codecs; i++) {
codec = rtd->codec_dais[i];
ret = aml_card_init_dai(codec, &dai_props->codec_dai);
ret = aml_card_init_dai(codec, &dai_props->codec_dai, idle_clk);
if (ret < 0)
return ret;
}
ret = aml_card_init_dai(cpu, &dai_props->cpu_dai);
ret = aml_card_init_dai(cpu, &dai_props->cpu_dai, idle_clk);
if (ret < 0)
return ret;
@@ -527,14 +530,6 @@ static int aml_card_dai_init(struct snd_soc_pcm_runtime *rtd)
aml_card_init_mic(rtd->card, &priv->mic_jack, PREFIX);
hp_mic_detect_cnt = 1;
}
/* enable dai-link mclk when CONTINUOUS clk setted */
idle_clk = !!(rtd->dai_link->dai_fmt & SND_SOC_DAIFMT_CONT);
if (idle_clk && dai_props->cpu_dai.clk) {
clk_set_rate(dai_props->cpu_dai.clk, dai_props->cpu_dai.sysclk);
ret = clk_prepare_enable(dai_props->cpu_dai.clk);
if (ret)
return ret;
}
return 0;
}

View File

@@ -242,11 +242,11 @@ codec_confs_end:
}
int aml_card_init_dai(struct snd_soc_dai *dai,
struct aml_dai *aml_dai)
struct aml_dai *aml_dai, bool cont_clk)
{
int ret;
if (aml_dai->sysclk) {
if (aml_dai->sysclk && cont_clk) {
ret = snd_soc_dai_set_sysclk(dai, 0, aml_dai->sysclk, 0);
if (ret && ret != -ENOTSUPP) {
dev_err(dai->dev, "aml-card: set_sysclk error\n");

View File

@@ -71,7 +71,7 @@ int aml_card_parse_codec_confs(struct device_node *codec_np,
struct snd_soc_card *card);
int aml_card_init_dai(struct snd_soc_dai *dai,
struct aml_dai *aml_dai);
struct aml_dai *aml_dai, bool cont_clk);
int aml_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link);
void aml_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,

View File

@@ -854,6 +854,49 @@ static void aml_check_aed(bool enable, int dst)
}
}
void frddr_init_default(unsigned int frddr_index, unsigned int src0_sel)
{
unsigned int offset, reg;
unsigned int start_addr, end_addr, int_addr;
static int buf[256];
memset(buf, 0x0, sizeof(buf));
start_addr = virt_to_phys(buf);
end_addr = start_addr + sizeof(buf) - 1;
int_addr = sizeof(buf) / 64;
offset = EE_AUDIO_FRDDR_B_START_ADDR - EE_AUDIO_FRDDR_A_START_ADDR;
reg = EE_AUDIO_FRDDR_A_START_ADDR + offset * frddr_index;
audiobus_write(reg, start_addr);
offset = EE_AUDIO_FRDDR_B_INIT_ADDR - EE_AUDIO_FRDDR_A_INIT_ADDR;
reg = EE_AUDIO_FRDDR_A_INIT_ADDR + offset * frddr_index;
audiobus_write(reg, start_addr);
offset = EE_AUDIO_FRDDR_B_FINISH_ADDR - EE_AUDIO_FRDDR_A_FINISH_ADDR;
reg = EE_AUDIO_FRDDR_A_FINISH_ADDR + offset * frddr_index;
audiobus_write(reg, end_addr);
offset = EE_AUDIO_FRDDR_B_INT_ADDR - EE_AUDIO_FRDDR_A_INT_ADDR;
reg = EE_AUDIO_FRDDR_A_INT_ADDR + offset * frddr_index;
audiobus_write(reg, int_addr);
offset = EE_AUDIO_FRDDR_B_CTRL1 - EE_AUDIO_FRDDR_A_CTRL1;
reg = EE_AUDIO_FRDDR_A_CTRL1 + offset * frddr_index;
audiobus_write(reg,
(0x40 - 1) << 24 | (0x20 - 1) << 16 | 2 << 8 | 0 << 0);
offset = EE_AUDIO_FRDDR_B_CTRL0 - EE_AUDIO_FRDDR_A_CTRL0;
reg = EE_AUDIO_FRDDR_A_CTRL0 + offset * frddr_index;
audiobus_write(reg,
1 << 31
| 0 << 24
| 4 << 16
| 1 << 3 /* src0 enable */
| src0_sel << 0 /* src0 sel */
);
}
static struct ddr_chipinfo g12a_ddr_chipinfo = {
.addr_separated = true,
.same_src_fn = true,

View File

@@ -99,5 +99,7 @@ void aml_frddr_set_fifos(struct frddr *fr,
unsigned int aml_frddr_get_fifo_id(struct frddr *fr);
/* audio eq drc */
void aml_aed_enable(bool enable, int aed_module);
void frddr_init_default(unsigned int frddr_index, unsigned int src0_sel);
#endif

View File

@@ -28,6 +28,7 @@ static int sharebuffer_spdifout_prepare(struct snd_pcm_substream *substream,
{
struct snd_pcm_runtime *runtime = substream->runtime;
int bit_depth;
struct iec958_chsts chsts;
bit_depth = snd_pcm_format_width(runtime->format);
@@ -35,11 +36,13 @@ static int sharebuffer_spdifout_prepare(struct snd_pcm_substream *substream,
aml_frddr_get_fifo_id(fr),
bit_depth, true);
/* spdif b, notify hdmitx audio */
if (spdif_id == 1) {
spdifoutb_to_hdmitx_ctrl(spdif_id);
aout_notifier_call_chain(0x1, substream);
}
/* spdif to hdmitx */
spdifoutb_to_hdmitx_ctrl(spdif_id);
/* check and set channel status */
spdif_get_channel_status_info(&chsts, runtime->rate);
spdif_set_channel_status_info(&chsts, spdif_id);
/* notify hdmitx audio */
aout_notifier_call_chain(0x1, substream);
return 0;
}
@@ -52,9 +55,11 @@ static int sharebuffer_spdifout_free(struct snd_pcm_substream *substream,
bit_depth = snd_pcm_format_width(runtime->format);
spdifout_samesource_set(spdif_id,
aml_frddr_get_fifo_id(fr),
bit_depth, false);
/* spdif b is always on */
if (spdif_id != 1)
spdifout_samesource_set(spdif_id,
aml_frddr_get_fifo_id(fr),
bit_depth, false);
return 0;
}

View File

@@ -38,8 +38,6 @@
#include "spdif_hw.h"
#include "audio_utils.h"
#include <linux/amlogic/media/sound/aout_notify.h>
#define DRV_NAME "aml_spdif"
#define SPDIF_A 0
@@ -81,6 +79,7 @@ struct aml_spdif {
unsigned int id;
struct spdif_chipinfo *chipinfo;
unsigned int clk_cont; /* CONTINUOUS CLOCK */
};
static const struct snd_pcm_hardware aml_spdif_hardware = {
@@ -276,6 +275,9 @@ static irqreturn_t aml_spdif_ddr_isr(int irq, void *devid)
struct snd_pcm_substream *substream =
(struct snd_pcm_substream *)devid;
if (!snd_pcm_running(substream))
return IRQ_HANDLED;
snd_pcm_period_elapsed(substream);
return IRQ_HANDLED;
@@ -389,8 +391,6 @@ static int aml_spdif_prepare(struct snd_pcm_substream *substream)
end_addr = start_addr + runtime->dma_bytes - 8;
int_addr = frames_to_bytes(runtime, runtime->period_size) / 8;
pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
struct frddr *fr = p_spdif->fddr;
@@ -411,6 +411,7 @@ static snd_pcm_uframes_t aml_spdif_pointer(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct aml_spdif *p_spdif = runtime->private_data;
unsigned int addr, start_addr;
snd_pcm_uframes_t frames;
start_addr = runtime->dma_addr;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -418,7 +419,11 @@ static snd_pcm_uframes_t aml_spdif_pointer(struct snd_pcm_substream *substream)
else
addr = aml_toddr_get_position(p_spdif->tddr);
return bytes_to_frames(runtime, addr - start_addr);
frames = bytes_to_frames(runtime, addr - start_addr);
if (frames > runtime->buffer_size)
frames = 0;
return frames;
}
int aml_spdif_silence(struct snd_pcm_substream *substream, int channel,
@@ -502,14 +507,29 @@ static int aml_dai_spdif_startup(
pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
aml_spdif_fifo_reset(p_spdif->actrl,
substream->stream,
p_spdif->id);
if (!p_spdif->clk_cont)
aml_spdif_fifo_reset(p_spdif->actrl,
substream->stream,
p_spdif->id);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
/* enable clock gate */
if (p_spdif->clk_cont) {
pr_info("spdif_%s keep clk continuous\n",
(p_spdif->id == 0) ? "a":"b");
return 0;
}
/* enable clock gate */
ret = clk_prepare_enable(p_spdif->gate_spdifout);
/* clock parent */
ret = clk_set_parent(p_spdif->clk_spdifout, p_spdif->sysclk);
if (ret) {
pr_err("Can't set clk_spdifout parent clock\n");
ret = PTR_ERR(p_spdif->clk_spdifout);
goto err;
}
/* enable clock */
ret = clk_prepare_enable(p_spdif->sysclk);
if (ret) {
@@ -522,10 +542,18 @@ static int aml_dai_spdif_startup(
ret);
goto err;
}
} else {
/* enable clock gate */
ret = clk_prepare_enable(p_spdif->gate_spdifin);
/* clock parent */
ret = clk_set_parent(p_spdif->clk_spdifin, p_spdif->fixed_clk);
if (ret) {
pr_err("Can't set clk_spdifin parent clock\n");
ret = PTR_ERR(p_spdif->clk_spdifin);
goto err;
}
/* enable clock */
ret = clk_prepare_enable(p_spdif->fixed_clk);
if (ret) {
@@ -553,6 +581,12 @@ static void aml_dai_spdif_shutdown(
/* disable clock and gate */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (p_spdif->clk_cont) {
pr_info("spdif_%s keep clk continuous\n",
(p_spdif->id == 0) ? "a":"b");
return;
}
clk_disable_unprepare(p_spdif->clk_spdifout);
clk_disable_unprepare(p_spdif->sysclk);
clk_disable_unprepare(p_spdif->gate_spdifout);
@@ -573,13 +607,12 @@ static int aml_dai_spdif_prepare(
unsigned int bit_depth = 0;
unsigned int fifo_id = 0;
pr_info("%s stream:%d\n", __func__, substream->stream);
bit_depth = snd_pcm_format_width(runtime->format);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
struct frddr *fr = p_spdif->fddr;
enum frddr_dest dst;
struct iec958_chsts chsts;
switch (p_spdif->id) {
case 0:
@@ -597,47 +630,17 @@ static int aml_dai_spdif_prepare(
aml_frddr_select_dst(fr, dst);
aml_frddr_set_fifos(fr, 0x40, 0x20);
/* check channel status info, and set them */
spdif_get_channel_status_info(&chsts, runtime->rate);
spdif_set_channel_status_info(&chsts, p_spdif->id);
/* TOHDMITX_CTRL0 */
if (p_spdif->id == 1) {
spdifoutb_to_hdmitx_ctrl(p_spdif->id);
if (IEC958_mode_codec == 2) {
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_AC_3,
substream);
} else if (IEC958_mode_codec == 3) {
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_DTS,
substream);
} else if (IEC958_mode_codec == 4) {
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_DOBLY_DIGITAL_PLUS,
substream);
} else if (IEC958_mode_codec == 5) {
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_DTS_HD,
substream);
} else if (IEC958_mode_codec == 7 ||
IEC958_mode_codec == 8) {
//aml_aiu_write(AIU_958_CHSTAT_L0, 0x1902);
//aml_aiu_write(AIU_958_CHSTAT_L1, 0x900);
//aml_aiu_write(AIU_958_CHSTAT_R0, 0x1902);
//aml_aiu_write(AIU_958_CHSTAT_R1, 0x900);
if (IEC958_mode_codec == 8)
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_DTS_HD_MA,
substream);
else
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_MAT_MLP,
substream);
} else {
aout_notifier_call_chain(
AOUT_EVENT_IEC_60958_PCM,
substream);
}
/* notify to hdmitx */
spdif_notify_to_hdmitx(substream);
}
} else {
struct toddr *to = p_spdif->tddr;
unsigned int msb, lsb, toddr_type;
@@ -729,8 +732,9 @@ static int aml_dai_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
dev_info(substream->pcm->card->dev, "spdif capture disable\n");
aml_toddr_enable(p_spdif->tddr, 0);
}
aml_spdif_enable(p_spdif->actrl,
substream->stream, p_spdif->id, false);
if (!p_spdif->clk_cont)
aml_spdif_enable(p_spdif->actrl,
substream->stream, p_spdif->id, false);
break;
default:
return -EINVAL;
@@ -779,13 +783,14 @@ static void aml_set_spdifclk(struct aml_spdif *p_spdif)
p_spdif->sysclk_freq);
if (p_spdif->sysclk_freq) {
unsigned int mul = 4;
if (IEC958_mode_codec == 4 || IEC958_mode_codec == 5 ||
IEC958_mode_codec == 7 || IEC958_mode_codec == 8) {
pr_info("set 4x audio clk for 958\n");
p_spdif->sysclk_freq = p_spdif->sysclk_freq * 4;
} else {
pr_info("set normal 512 fs /4 fs\n");
}
int ret;
if (spdif_is_4x_clk()) {
pr_info("set 4x audio clk for 958\n");
p_spdif->sysclk_freq *= 4;
} else {
pr_info("set normal 512 fs /4 fs\n");
}
mpll_freq = p_spdif->sysclk_freq * mul;
#ifdef G12A_PTM
@@ -794,6 +799,17 @@ static void aml_set_spdifclk(struct aml_spdif *p_spdif)
clk_set_rate(p_spdif->sysclk, mpll_freq);
clk_set_rate(p_spdif->clk_spdifout,
p_spdif->sysclk_freq);
ret = clk_prepare_enable(p_spdif->sysclk);
if (ret) {
pr_err("Can't enable pcm sysclk clock: %d\n", ret);
return;
}
ret = clk_prepare_enable(p_spdif->clk_spdifout);
if (ret) {
pr_err("Can't enable clk_spdifout clock: %d\n", ret);
return;
}
}
}
@@ -933,13 +949,6 @@ static int aml_spdif_parse_of(struct platform_device *pdev)
dev_err(dev, "Can't retrieve spdifout clock\n");
return PTR_ERR(p_spdif->clk_spdifout);
}
ret = clk_set_parent(p_spdif->clk_spdifout, p_spdif->sysclk);
if (ret) {
dev_err(dev,
"Can't set clk_spdifout parent clock\n");
ret = PTR_ERR(p_spdif->clk_spdifout);
return ret;
}
return 0;
}
@@ -1007,6 +1016,15 @@ static int aml_spdif_platform_probe(struct platform_device *pdev)
of_device_get_match_data(dev);
if (p_spdif_chipinfo) {
aml_spdif->id = p_spdif_chipinfo->id;
/* for spdif_b, clk be continuous,
* and keep silence when no valid data
*/
if (aml_spdif->id == 1)
aml_spdif->clk_cont = 1;
if (aml_spdif->clk_cont)
spdifout_play_with_zerodata(aml_spdif->id);
aml_spdif->chipinfo = p_spdif_chipinfo;
} else
dev_warn_once(dev,

View File

@@ -19,6 +19,9 @@
#include "iomap.h"
#include "spdif_hw.h"
#include "ddr_mngr.h"
#include <linux/amlogic/media/sound/aout_notify.h>
/*#define G12A_PTM*/
/*#define G12A_PTM_LB_INTERNAL*/
@@ -29,8 +32,6 @@ void aml_spdif_enable(
int index,
bool is_enable)
{
pr_info("spdif stream :%d is_enable:%d\n", stream, is_enable);
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
unsigned int offset, reg;
@@ -146,8 +147,8 @@ void aml_spdif_fifo_ctrl(
reg = EE_AUDIO_SPDIFOUT_CTRL0 + offset * index;
aml_audiobus_update_bits(actrl,
reg,
0x1<<29|0x1<<28|0x1<<20|0x1<<19|0xff<<4,
1<<29|1<<28|0<<20|0<<19|0x3<<4);
0x1<<29|0x1<<28|0x3<<21|0x1<<20|0x1<<19|0xff<<4,
1<<29|1<<28|0x0<<21|0<<20|0<<19|0x3<<4);
offset = EE_AUDIO_SPDIFOUT_B_CTRL1 - EE_AUDIO_SPDIFOUT_CTRL1;
reg = EE_AUDIO_SPDIFOUT_CTRL1 + offset * index;
@@ -319,15 +320,18 @@ void spdifout_fifo_ctrl(int spdif_id, int fifo_id, int bitwidth)
return;
}
pr_info("%s, bit depth:%d, frddr type:%d\n",
__func__, bitwidth, frddr_type);
pr_info("spdif_%s fifo ctrl, frddr:%d type:%d, %d bits\n",
(spdif_id == 0) ? "a":"b",
fifo_id,
frddr_type,
bitwidth);
/* mask lane 0 L/R channels */
offset = EE_AUDIO_SPDIFOUT_B_CTRL0 - EE_AUDIO_SPDIFOUT_CTRL0;
reg = EE_AUDIO_SPDIFOUT_CTRL0 + offset * spdif_id;
audiobus_update_bits(reg,
0x1<<29|0x1<<28|0x1<<20|0x1<<19|0xff<<4,
1<<29|1<<28|0<<20|0<<19|0x3<<4);
0x3<<21|0x1<<20|0x1<<19|0xff<<4,
0x0<<21|0<<20|0<<19|0x3<<4);
offset = EE_AUDIO_SPDIFOUT_B_CTRL1 - EE_AUDIO_SPDIFOUT_CTRL1;
reg = EE_AUDIO_SPDIFOUT_CTRL1 + offset * spdif_id;
@@ -345,15 +349,46 @@ void spdifout_fifo_ctrl(int spdif_id, int fifo_id, int bitwidth)
audiobus_update_bits(reg, 3<<28, 0);
audiobus_update_bits(reg, 1<<29, 1<<29);
audiobus_update_bits(reg, 1<<28, 1<<28);
}
static void spdifout_mute(int spdif_id)
{
unsigned int offset, reg;
/* mute */
offset = EE_AUDIO_SPDIFOUT_B_CTRL0 - EE_AUDIO_SPDIFOUT_CTRL0;
reg = EE_AUDIO_SPDIFOUT_CTRL0 + offset * spdif_id;
audiobus_update_bits(reg, 0x3 << 21, 0x3 << 21);
}
static bool spdifout_is_enable(int spdif_id)
{
unsigned int offset, reg, val;
offset = EE_AUDIO_SPDIFOUT_B_CTRL0 - EE_AUDIO_SPDIFOUT_CTRL0;
reg = EE_AUDIO_SPDIFOUT_CTRL0 + offset * spdif_id;
val = audiobus_read(reg);
return ((val >> 31) == 1);
}
void spdifout_enable(int spdif_id, bool is_enable)
{
unsigned int offset, reg;
pr_info("spdif_%s is set to %s\n",
(spdif_id == 0) ? "a":"b",
is_enable ? "enable":"disable");
offset = EE_AUDIO_SPDIFOUT_B_CTRL0 - EE_AUDIO_SPDIFOUT_CTRL0;
reg = EE_AUDIO_SPDIFOUT_CTRL0 + offset * spdif_id;
if (!is_enable) {
/* share buffer, spdif should be active, so mute it */
audiobus_update_bits(reg, 0x3 << 21, 0x3 << 21);
return;
}
audiobus_update_bits(reg, 1<<31, is_enable<<31);
}
@@ -367,11 +402,12 @@ void spdifout_samesource_set(int spdif_index, int fifo_id,
else
spdif_id = 0;
if (is_enable) {
spdifout_clk_ctrl(spdif_id, true);
/* clk for spdif_b is always on */
if (!spdif_id)
spdifout_clk_ctrl(spdif_id, is_enable);
if (is_enable)
spdifout_fifo_ctrl(spdif_id, fifo_id, bitwidth);
} else
spdifout_clk_ctrl(spdif_id, false);
}
int spdifin_get_sample_rate(void)
@@ -394,3 +430,107 @@ int spdifin_get_audio_type(void)
return (val >> 16) & 0xff;
}
void spdif_set_channel_status_info(
struct iec958_chsts *chsts, int spdif_id)
{
unsigned int offset, reg;
/* "ch status" = reg_chsts0~B */
offset = EE_AUDIO_SPDIFOUT_B_CTRL0 - EE_AUDIO_SPDIFOUT_CTRL0;
reg = EE_AUDIO_SPDIFOUT_CTRL0 + offset * spdif_id;
audiobus_update_bits(reg, 0x1 << 24, 0x0 << 24);
offset = EE_AUDIO_SPDIFOUT_B_CHSTS0 - EE_AUDIO_SPDIFOUT_CHSTS0;
reg = EE_AUDIO_SPDIFOUT_CHSTS0 + offset * spdif_id;
audiobus_write(reg, chsts->chstat1_l << 16 | chsts->chstat0_l);
offset = EE_AUDIO_SPDIFOUT_B_CHSTS1 - EE_AUDIO_SPDIFOUT_CHSTS1;
reg = EE_AUDIO_SPDIFOUT_CHSTS1 + offset * spdif_id;
audiobus_write(reg, chsts->chstat1_l << 16 | chsts->chstat0_l);
offset = EE_AUDIO_SPDIFOUT_B_CHSTS2 - EE_AUDIO_SPDIFOUT_CHSTS2;
reg = EE_AUDIO_SPDIFOUT_CHSTS2 + offset * spdif_id;
audiobus_write(reg, chsts->chstat1_l << 16 | chsts->chstat0_l);
offset = EE_AUDIO_SPDIFOUT_B_CHSTS3 - EE_AUDIO_SPDIFOUT_CHSTS3;
reg = EE_AUDIO_SPDIFOUT_CHSTS3 + offset * spdif_id;
audiobus_write(reg, chsts->chstat1_l << 16 | chsts->chstat0_l);
offset = EE_AUDIO_SPDIFOUT_B_CHSTS4 - EE_AUDIO_SPDIFOUT_CHSTS4;
reg = EE_AUDIO_SPDIFOUT_CHSTS4 + offset * spdif_id;
audiobus_write(reg, chsts->chstat1_l << 16 | chsts->chstat0_l);
offset = EE_AUDIO_SPDIFOUT_B_CHSTS5 - EE_AUDIO_SPDIFOUT_CHSTS5;
reg = EE_AUDIO_SPDIFOUT_CHSTS5 + offset * spdif_id;
audiobus_write(reg, chsts->chstat1_l << 16 | chsts->chstat0_l);
offset = EE_AUDIO_SPDIFOUT_B_CHSTS6 - EE_AUDIO_SPDIFOUT_CHSTS6;
reg = EE_AUDIO_SPDIFOUT_CHSTS6 + offset * spdif_id;
audiobus_write(reg, chsts->chstat1_r << 16 | chsts->chstat0_r);
offset = EE_AUDIO_SPDIFOUT_B_CHSTS7 - EE_AUDIO_SPDIFOUT_CHSTS7;
reg = EE_AUDIO_SPDIFOUT_CHSTS7 + offset * spdif_id;
audiobus_write(reg, chsts->chstat1_r << 16 | chsts->chstat0_r);
offset = EE_AUDIO_SPDIFOUT_B_CHSTS8 - EE_AUDIO_SPDIFOUT_CHSTS8;
reg = EE_AUDIO_SPDIFOUT_CHSTS8 + offset * spdif_id;
audiobus_write(reg, chsts->chstat1_r << 16 | chsts->chstat0_r);
offset = EE_AUDIO_SPDIFOUT_B_CHSTS9 - EE_AUDIO_SPDIFOUT_CHSTS9;
reg = EE_AUDIO_SPDIFOUT_CHSTS9 + offset * spdif_id;
audiobus_write(reg, chsts->chstat1_r << 16 | chsts->chstat0_r);
offset = EE_AUDIO_SPDIFOUT_B_CHSTSA - EE_AUDIO_SPDIFOUT_CHSTSA;
reg = EE_AUDIO_SPDIFOUT_CHSTSA + offset * spdif_id;
audiobus_write(reg, chsts->chstat1_r << 16 | chsts->chstat0_r);
offset = EE_AUDIO_SPDIFOUT_B_CHSTSB - EE_AUDIO_SPDIFOUT_CHSTSB;
reg = EE_AUDIO_SPDIFOUT_CHSTSB + offset * spdif_id;
audiobus_write(reg, chsts->chstat1_r << 16 | chsts->chstat0_r);
}
void spdifout_play_with_zerodata(unsigned int spdif_id)
{
pr_info("%s, spdif id:%d enable:%d\n",
__func__,
spdif_id,
spdifout_is_enable(spdif_id));
if (!spdifout_is_enable(spdif_id)) {
unsigned int frddr_index = 0;
unsigned int bitwidth = 32;
unsigned int sample_rate = 48000;
unsigned int src0_sel = 4; /* spdif b */
struct iec958_chsts chsts;
struct snd_pcm_substream substream;
struct snd_pcm_runtime runtime;
substream.runtime = &runtime;
runtime.rate = 48000;
runtime.format = SNDRV_PCM_FORMAT_S16_LE;
runtime.channels = 2;
runtime.sample_bits = 16;
/* check whether fix to spdif a */
if (spdif_id == 0)
src0_sel = 3;
/* spdif ctrl */
spdifout_fifo_ctrl(spdif_id, frddr_index, bitwidth);
/* channel status info */
spdif_get_channel_status_info(&chsts, sample_rate);
spdif_set_channel_status_info(&chsts, spdif_id);
/* notify hdmitx audio */
spdifoutb_to_hdmitx_ctrl(spdif_id);
aout_notifier_call_chain(0x1, &substream);
frddr_init_default(frddr_index, src0_sel);
spdifout_enable(spdif_id, true);
spdifout_mute(spdif_id);
}
}

View File

@@ -19,15 +19,8 @@
#define __AML_SPDIF_HW_H__
#include "audio_io.h"
#include "regs.h"
/*
* 0 -- other formats except(DD,DD+,DTS)
* 1 -- DTS
* 2 -- DD
* 3 -- DTS with 958 PCM RAW package mode
* 4 -- DD+
*/
extern unsigned int IEC958_mode_codec;
#include <linux/amlogic/media/sound/spdif_info.h>
extern void aml_spdif_enable(
struct aml_audio_controller *actrl,
@@ -71,4 +64,9 @@ extern void spdifout_enable(int spdif_id, bool is_enable);
extern int spdifin_get_sample_rate(void);
extern int spdifin_get_audio_type(void);
extern void spdif_set_channel_status_info(
struct iec958_chsts *chsts, int spdif_id);
extern void spdifout_play_with_zerodata(unsigned int spdif_id);
#endif

View File

@@ -139,6 +139,9 @@ static irqreturn_t aml_tdm_ddr_isr(int irq, void *devid)
{
struct snd_pcm_substream *substream = (struct snd_pcm_substream *)devid;
if (!snd_pcm_running(substream))
return IRQ_HANDLED;
snd_pcm_period_elapsed(substream);
return IRQ_HANDLED;
@@ -314,6 +317,7 @@ static snd_pcm_uframes_t aml_tdm_pointer(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct aml_tdm *p_tdm = runtime->private_data;
unsigned int addr, start_addr;
snd_pcm_uframes_t frames;
start_addr = runtime->dma_addr;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -321,7 +325,11 @@ static snd_pcm_uframes_t aml_tdm_pointer(struct snd_pcm_substream *substream)
else
addr = aml_toddr_get_position(p_tdm->tddr);
return bytes_to_frames(runtime, addr - start_addr);
frames = bytes_to_frames(runtime, addr - start_addr);
if (frames > runtime->buffer_size)
frames = 0;
return frames;
}
static int aml_tdm_mmap(struct snd_pcm_substream *substream,

View File

@@ -1 +1 @@
obj-y += notify.o
obj-y += notify.o spdif_info.o

View File

@@ -1,5 +1,5 @@
/*
* sound/soc/amlogic/meson/notify.c
* sound/soc/amlogic/common/notify.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*

View File

@@ -0,0 +1,160 @@
/*
* sound/soc/amlogic/common/spdif_info.c
*
* Copyright (C) 2018 Amlogic, Inc. All rights reserved.
*
* 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 program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#undef pr_fmt
#define pr_fmt(fmt) "spdif_info: " fmt
#include <linux/amlogic/media/sound/aout_notify.h>
#include <linux/amlogic/media/sound/spdif_info.h>
/*
* 0 -- other formats except(DD,DD+,DTS)
* 1 -- DTS
* 2 -- DD
* 3 -- DTS with 958 PCM RAW package mode
* 4 -- DD+
*/
unsigned int IEC958_mode_codec;
EXPORT_SYMBOL(IEC958_mode_codec);
bool spdif_is_4x_clk(void)
{
bool is_4x = false;
if (IEC958_mode_codec == 4 || IEC958_mode_codec == 5 ||
IEC958_mode_codec == 7 || IEC958_mode_codec == 8) {
is_4x = true;
}
return is_4x;
}
void spdif_get_channel_status_info(
struct iec958_chsts *chsts,
unsigned int rate)
{
int rate_bit = snd_pcm_rate_to_rate_bit(rate);
if (rate_bit == SNDRV_PCM_RATE_KNOT) {
pr_err("Unsupport sample rate\n");
return;
}
if (IEC958_mode_codec && IEC958_mode_codec != 9) {
if (IEC958_mode_codec == 1) {
/* dts, use raw sync-word mode */
pr_info("iec958 mode RAW\n");
} else {
/* ac3,use the same pcm mode as i2s */
}
chsts->chstat0_l = 0x1902;
chsts->chstat0_r = 0x1902;
if (IEC958_mode_codec == 4 || IEC958_mode_codec == 5) {
/* DD+ */
if (rate_bit == SNDRV_PCM_RATE_32000) {
chsts->chstat1_l = 0x300;
chsts->chstat1_r = 0x300;
} else if (rate_bit == SNDRV_PCM_RATE_44100) {
chsts->chstat1_l = 0xc00;
chsts->chstat1_r = 0xc00;
} else {
chsts->chstat1_l = 0Xe00;
chsts->chstat1_r = 0Xe00;
}
} else {
/* DTS,DD */
if (rate_bit == SNDRV_PCM_RATE_32000) {
chsts->chstat1_l = 0x300;
chsts->chstat1_r = 0x300;
} else if (rate_bit == SNDRV_PCM_RATE_44100) {
chsts->chstat1_l = 0;
chsts->chstat1_r = 0;
} else {
chsts->chstat1_l = 0x200;
chsts->chstat1_r = 0x200;
}
}
} else {
chsts->chstat0_l = 0x0100;
chsts->chstat0_r = 0x0100;
chsts->chstat1_l = 0x200;
chsts->chstat1_r = 0x200;
if (rate_bit == SNDRV_PCM_RATE_44100) {
chsts->chstat1_l = 0;
chsts->chstat1_r = 0;
} else if (rate_bit == SNDRV_PCM_RATE_88200) {
chsts->chstat1_l = 0x800;
chsts->chstat1_r = 0x800;
} else if (rate_bit == SNDRV_PCM_RATE_96000) {
chsts->chstat1_l = 0xa00;
chsts->chstat1_r = 0xa00;
} else if (rate_bit == SNDRV_PCM_RATE_176400) {
chsts->chstat1_l = 0xc00;
chsts->chstat1_r = 0xc00;
} else if (rate_bit == SNDRV_PCM_RATE_192000) {
chsts->chstat1_l = 0xe00;
chsts->chstat1_r = 0xe00;
}
}
pr_info("rate: %d, channel status ch0_l:0x%x, ch0_r:0x%x, ch1_l:0x%x, ch1_r:0x%x\n",
rate,
chsts->chstat0_l,
chsts->chstat0_r,
chsts->chstat1_l,
chsts->chstat1_r);
}
void spdif_notify_to_hdmitx(struct snd_pcm_substream *substream)
{
if (IEC958_mode_codec == 2) {
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_AC_3,
substream);
} else if (IEC958_mode_codec == 3) {
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_DTS,
substream);
} else if (IEC958_mode_codec == 4) {
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_DOBLY_DIGITAL_PLUS,
substream);
} else if (IEC958_mode_codec == 5) {
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_DTS_HD,
substream);
} else if (IEC958_mode_codec == 7 ||
IEC958_mode_codec == 8) {
//aml_aiu_write(AIU_958_CHSTAT_L0, 0x1902);
//aml_aiu_write(AIU_958_CHSTAT_L1, 0x900);
//aml_aiu_write(AIU_958_CHSTAT_R0, 0x1902);
//aml_aiu_write(AIU_958_CHSTAT_R1, 0x900);
if (IEC958_mode_codec == 8)
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_DTS_HD_MA,
substream);
else
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_MAT_MLP,
substream);
} else {
aout_notifier_call_chain(
AOUT_EVENT_IEC_60958_PCM,
substream);
}
}

View File

@@ -1011,7 +1011,7 @@ void audio_hw_958_raw(void)
}
void set_958_channel_status(struct _aiu_958_channel_status_t *set)
void set_958_channel_status(struct iec958_chsts *set)
{
if (set) {
aml_aiu_write(AIU_958_CHSTAT_L0, set->chstat0_l);

View File

@@ -19,6 +19,7 @@
#define __AML_AUDIO_HW_H__
#include "sound/asound.h"
#include <linux/amlogic/media/sound/spdif_info.h>
#define AUDIO_CLK_GATE_ON(a) CLK_GATE_ON(a)
#define AUDIO_CLK_GATE_OFF(a) CLK_GATE_OFF(a)
@@ -29,13 +30,6 @@ struct _aiu_clk_setting_t {
unsigned short devisor;
};
struct _aiu_958_channel_status_t {
unsigned short chstat0_l;
unsigned short chstat1_l;
unsigned short chstat0_r;
unsigned short chstat1_r;
};
struct audio_output_config_t {
/* audio clock */
unsigned short clock;
@@ -55,7 +49,7 @@ struct audio_output_config_t {
unsigned short brst;
unsigned short length;
unsigned short paddsize;
struct _aiu_958_channel_status_t chan_status;
struct iec958_chsts chan_status;
};
struct _aiu_958_raw_setting_t {
@@ -64,7 +58,7 @@ struct _aiu_958_raw_setting_t {
unsigned short brst;
unsigned short length;
unsigned short paddsize;
struct _aiu_958_channel_status_t *chan_stat;
struct iec958_chsts *chan_stat;
};
struct aml_chipset_info {

View File

@@ -50,16 +50,6 @@
#include <linux/amlogic/media/sound/audin_regs.h>
#include <linux/amlogic/media/sound/audio_iomap.h>
/*
* 0 -- other formats except(DD,DD+,DTS)
* 1 -- DTS
* 2 -- DD
* 3 -- DTS with 958 PCM RAW package mode
* 4 -- DD+
*/
unsigned int IEC958_mode_codec;
EXPORT_SYMBOL(IEC958_mode_codec);
struct aml_spdif {
struct clk *clk_mpl1;
struct clk *clk_i958;
@@ -99,7 +89,7 @@ void aml_spdif_play(int samesrc)
uint div = 0;
static int iec958buf[DEFAULT_PLAYBACK_SIZE];
struct _aiu_958_raw_setting_t set;
struct _aiu_958_channel_status_t chstat;
struct iec958_chsts chstat;
struct snd_pcm_substream substream;
struct snd_pcm_runtime runtime;
int size = DEFAULT_PLAYBACK_SIZE;
@@ -203,7 +193,7 @@ static int aml_dai_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
void aml_hw_iec958_init(struct snd_pcm_substream *substream, int samesrc)
{
struct _aiu_958_raw_setting_t set;
struct _aiu_958_channel_status_t chstat;
struct iec958_chsts chstat;
unsigned int i2s_mode, iec958_mode;
unsigned int start, size;
int sample_rate;