blob: 664cdaccf7193faaa5f3e1d082ab1b3313541a6c [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/major.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/amlogic/media/vout/hdmi_tx/hdmi_info_global.h>
#include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h>
#include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_compliance.h>
#include "hw/common.h"
#undef PCM_USE_INFOFRAME
static const unsigned char cs_freq[] = {
0x0,
0x3, /*32K*/
0x0, /*44.1k*/
0x2, /*48k*/
0x8, /*88.2k*/
0xa, /*96k*/
0xc, /*176.4k*/
0xe, /*192k*/
};
static const unsigned char cs_sw_len[] = {
0x0,
0x2, /*16 bits*/
0x3, /*20 bits*/
0xb /*24 bits*/
};
static void
hdmi_tx_construct_aud_packet(struct hdmitx_audpara *audio_param,
unsigned char *AUD_DB,
unsigned char *CHAN_STAT_BUF,
int hdmi_ch)
{
#ifndef PCM_USE_INFOFRAME
if (audio_param->type == CT_PCM) {
pr_info(AUD "Audio Type: PCM\n");
if (AUD_DB) {
/*Note: HDMI Spec V1.4 Page 154*/
if (audio_param->channel_num == CC_2CH ||
audio_param->channel_num == CC_REFER_TO_STREAM)
AUD_DB[0] = 0;
else
AUD_DB[0] = 0 << 4 |
audio_param->channel_num;
AUD_DB[1] = FS_REFER_TO_STREAM << 2 |
SS_REFER_TO_STREAM;
AUD_DB[2] = 0x0;
if (audio_param->channel_num == CC_6CH) {
AUD_DB[3] = 0xb;
} else if (audio_param->channel_num == CC_8CH) {
if (hdmi_ch == CC_6CH)
AUD_DB[3] = 0x0b;
else
AUD_DB[3] = 0x13;
} else {
AUD_DB[3] = 0;
}
AUD_DB[4] = 0;
}
if (CHAN_STAT_BUF) {
CHAN_STAT_BUF[2] = 0x10 |
(audio_param->channel_num + 1);
CHAN_STAT_BUF[24 + 2] = 0x20 |
(audio_param->channel_num + 1);
CHAN_STAT_BUF[3] =
cs_freq[audio_param->sample_rate];
CHAN_STAT_BUF[24 + 3] =
cs_freq[audio_param->sample_rate];
CHAN_STAT_BUF[4] =
cs_sw_len[audio_param->sample_size] |
~cs_freq[audio_param->sample_rate] << 4;
CHAN_STAT_BUF[24 + 4] =
cs_sw_len[audio_param->sample_size] |
~cs_freq[audio_param->sample_rate] << 4;
}
} else if (audio_param->type == CT_AC_3) {
pr_info(AUD "Audio Type: AC3\n");
if (AUD_DB) {
AUD_DB[0] = CT_AC_3 << 4 | CC_REFER_TO_STREAM;
AUD_DB[1] = FS_REFER_TO_STREAM << 2 |
SS_REFER_TO_STREAM;
AUD_DB[3] = 0;
AUD_DB[4] = 0;
}
} else if (audio_param->type == CT_MPEG1) {
pr_info(AUD "Audio Type: MPEG1\n");
if (AUD_DB) {
AUD_DB[0] = CT_MPEG1 << 4 | CC_REFER_TO_STREAM;
AUD_DB[1] = FS_REFER_TO_STREAM << 2 |
SS_REFER_TO_STREAM;
AUD_DB[3] = 0;
AUD_DB[4] = 0;
}
} else if (audio_param->type == CT_MP3) {
pr_info(AUD "Audio Type: MP3\n");
if (AUD_DB) {
AUD_DB[0] = CT_MP3 << 4 | CC_REFER_TO_STREAM;
AUD_DB[1] = FS_REFER_TO_STREAM << 2 |
SS_REFER_TO_STREAM;
AUD_DB[3] = 0;
AUD_DB[4] = 0;
}
} else if (audio_param->type == CT_MPEG2) {
pr_info(AUD "Audio Type: MPEG2\n");
if (AUD_DB) {
AUD_DB[0] = CT_MPEG2 << 4 | CC_REFER_TO_STREAM;
AUD_DB[1] = FS_REFER_TO_STREAM << 2 |
SS_REFER_TO_STREAM;
AUD_DB[3] = 0;
AUD_DB[4] = 0;
}
} else if (audio_param->type == CT_AAC) {
pr_info(AUD "Audio Type: AAC\n");
if (AUD_DB) {
AUD_DB[0] = CT_AAC << 4 | CC_REFER_TO_STREAM;
AUD_DB[1] = FS_REFER_TO_STREAM << 2 |
SS_REFER_TO_STREAM;
AUD_DB[3] = 0;
AUD_DB[4] = 0;
}
} else if (audio_param->type == CT_DTS) {
pr_info(AUD "Audio Type: DTS\n");
if (AUD_DB) {
AUD_DB[0] = CT_DTS << 4 | CC_REFER_TO_STREAM;
AUD_DB[1] = FS_REFER_TO_STREAM << 2 |
SS_REFER_TO_STREAM;
AUD_DB[3] = 0;
AUD_DB[4] = 0;
}
} else if (audio_param->type == CT_ATRAC) {
pr_info(AUD "Audio Type: ATRAC\n");
if (AUD_DB) {
AUD_DB[0] = CT_ATRAC << 4 | CC_REFER_TO_STREAM;
AUD_DB[1] = FS_REFER_TO_STREAM << 2 |
SS_REFER_TO_STREAM;
AUD_DB[3] = 0;
AUD_DB[4] = 0;
}
} else if (audio_param->type == CT_ONE_BIT_AUDIO) {
pr_info(AUD "Audio Type: One Bit Audio\n");
if (AUD_DB) {
AUD_DB[0] = CT_ONE_BIT_AUDIO << 4 | CC_REFER_TO_STREAM;
AUD_DB[1] = FS_REFER_TO_STREAM << 2 |
SS_REFER_TO_STREAM;
AUD_DB[3] = 0;
AUD_DB[4] = 0;
}
} else if (audio_param->type == CT_DOLBY_D) {
pr_info(AUD "Audio Type: Dobly Digital +\n");
if (AUD_DB) {
AUD_DB[0] = FS_REFER_TO_STREAM << 4 |
CC_REFER_TO_STREAM;
AUD_DB[1] = FS_REFER_TO_STREAM << 2 |
SS_REFER_TO_STREAM;
AUD_DB[3] = 0;
AUD_DB[4] = 0;
}
if (CHAN_STAT_BUF) {
CHAN_STAT_BUF[0] = 0x2;
CHAN_STAT_BUF[24 + 0] = 0x2;
CHAN_STAT_BUF[3] = 0x1e;
CHAN_STAT_BUF[24 + 3] = 0x1e;
CHAN_STAT_BUF[4] = 0x1;
CHAN_STAT_BUF[24 + 4] = 0x1;
}
} else if (audio_param->type == CT_DTS_HD) {
pr_info(AUD "Audio Type: DTS-HD\n");
if (AUD_DB) {
AUD_DB[0] = FS_REFER_TO_STREAM << 4 |
CC_REFER_TO_STREAM;
AUD_DB[1] = FS_REFER_TO_STREAM << 2 |
SS_REFER_TO_STREAM;
AUD_DB[3] = 0;
AUD_DB[4] = 0;
}
} else if (audio_param->type == CT_MAT) {
pr_info(AUD "Audio Type: MAT(MLP)\n");
if (AUD_DB) {
AUD_DB[0] = CT_MAT << 4 | CC_REFER_TO_STREAM;
AUD_DB[1] = FS_REFER_TO_STREAM << 2 |
SS_REFER_TO_STREAM;
AUD_DB[3] = 0;
AUD_DB[4] = 0;
}
} else if (audio_param->type == CT_DST) {
pr_info(AUD "Audio Type: DST\n");
if (AUD_DB) {
AUD_DB[0] = CT_DST << 4 | CC_REFER_TO_STREAM;
AUD_DB[1] = FS_REFER_TO_STREAM << 2 |
SS_REFER_TO_STREAM;
AUD_DB[3] = 0;
AUD_DB[4] = 0;
}
} else if (audio_param->type == CT_WMA) {
pr_info(AUD "Audio Type: WMA Pro\n");
if (AUD_DB) {
AUD_DB[0] = CT_WMA << 4 | CC_REFER_TO_STREAM;
AUD_DB[1] = FS_REFER_TO_STREAM << 2 |
SS_REFER_TO_STREAM;
AUD_DB[3] = 0;
AUD_DB[4] = 0;
}
} else {
;
}
if (AUD_DB) {
AUD_DB[0] = AUD_DB[0] & 0xf;/*bit[7:4] always set to 0 in HDMI*/
AUD_DB[1] = 0; /*always set to 0 in HDMI*/
}
#endif
}
int hdmitx_set_audio(struct hdmitx_dev *hdmitx_device,
struct hdmitx_audpara *audio_param)
{
int i, ret = -1;
unsigned char AUD_DB[32];
unsigned char CHAN_STAT_BUF[24 * 2];
unsigned int hdmi_ch = hdmitx_device->hdmi_ch;
for (i = 0; i < 32; i++)
AUD_DB[i] = 0;
for (i = 0; i < (24 * 2); i++)
CHAN_STAT_BUF[i] = 0;
if (hdmitx_device->hwop.setaudmode(hdmitx_device,
audio_param) >= 0) {
hdmi_tx_construct_aud_packet(audio_param, AUD_DB,
CHAN_STAT_BUF, hdmi_ch);
hdmitx_device->hwop.setaudioinfoframe(AUD_DB, CHAN_STAT_BUF);
ret = 0;
}
return ret;
}