summaryrefslogtreecommitdiff
authorZongdong Jiao <zongdong.jiao@amlogic.com>2019-10-22 02:10:44 (GMT)
committer Xindong Xu <xindong.xu@amlogic.com>2019-11-28 01:40:19 (GMT)
commit7a3c1b5090fa317eb33a05a13decabde3c2e788a (patch)
tree68b257ff931ce0e71a4320d85c84c49d73e1679e
parentccc5c3bb0b9e46e90596129cad3e3f0acc722fc7 (diff)
downloaduboot-7a3c1b5090fa317eb33a05a13decabde3c2e788a.zip
uboot-7a3c1b5090fa317eb33a05a13decabde3c2e788a.tar.gz
uboot-7a3c1b5090fa317eb33a05a13decabde3c2e788a.tar.bz2
hdmitx: add audio init function [1/1]
PD#SWPL-15263 Problem: No audio data in uboot hdmitx output Solution: Add audio init function, 48k PCM as default Verify: G12A/G12B Change-Id: I9d20b4dbe874c18cb8bc7f033f8670a0f8eaa6f7 Signed-off-by: Zongdong Jiao <zongdong.jiao@amlogic.com> Signed-off-by: jian.zhou <jian.zhou@amlogic.com>
Diffstat
-rw-r--r--arch/arm/cpu/armv8/g12a/Makefile1
-rw-r--r--arch/arm/cpu/armv8/g12a/hdmitx20/hdmitx_set.c155
-rw-r--r--arch/arm/cpu/armv8/g12a/sound.c209
-rw-r--r--arch/arm/cpu/armv8/g12b/Makefile1
-rw-r--r--arch/arm/cpu/armv8/g12b/hdmitx20/hdmitx_set.c153
-rw-r--r--arch/arm/cpu/armv8/g12b/sound.c180
-rw-r--r--include/amlogic/auge_sound.h23
7 files changed, 720 insertions, 2 deletions
diff --git a/arch/arm/cpu/armv8/g12a/Makefile b/arch/arm/cpu/armv8/g12a/Makefile
index 8b5f43d..a3837c2 100644
--- a/arch/arm/cpu/armv8/g12a/Makefile
+++ b/arch/arm/cpu/armv8/g12a/Makefile
@@ -10,3 +10,4 @@ obj-y += gate_init.o
obj-y += power_cal.o
obj-$(CONFIG_CMD_PLLTEST) += pll.o
obj-$(CONFIG_CMD_AML_MTEST) += core.o
+obj-$(CONFIG_AML_HDMITX20) += sound.o
diff --git a/arch/arm/cpu/armv8/g12a/hdmitx20/hdmitx_set.c b/arch/arm/cpu/armv8/g12a/hdmitx20/hdmitx_set.c
index 7d23656..700d9c0 100644
--- a/arch/arm/cpu/armv8/g12a/hdmitx20/hdmitx_set.c
+++ b/arch/arm/cpu/armv8/g12a/hdmitx20/hdmitx_set.c
@@ -25,6 +25,7 @@
#include <asm/cpu_id.h>
#include <amlogic/vout.h>
#include <amlogic/hdmi.h>
+#include <amlogic/auge_sound.h>
#include "hdmitx_reg.h"
#include "hdmitx_tvenc.h"
#include "mach_reg.h"
@@ -90,6 +91,7 @@ static void hdelay(int us)
#define msleep(i) hdelay(i)
static void hdmitx_set_hw(struct hdmitx_dev *hdev);
+static int hdmitx_set_audmode(struct hdmitx_dev *hdev);
// Internal functions:
static void hdmitx_csc_config (unsigned char input_color_format,
@@ -426,14 +428,18 @@ void hdmi_tx_set(struct hdmitx_dev *hdev)
{
unsigned char checksum[11];
+ aml_audio_init(); /* Init audio hw firstly */
hdmitx_hw_init();
hdmitx_debug();
ddc_init();
hdmitx_set_hw(hdev);
+ hdmitx_set_audmode(hdev);
hdmitx_debug();
//kernel will determine output mode on its own
setenv("hdmimode", getenv("outputmode"));
+ /* null char needed to terminate the string
+ otherwise garbage in checksum logopara */
memcpy(checksum, hdev->RXCap.checksum, 10);
checksum[10] = '\0';
setenv("hdmichecksum", (const char*)checksum);
@@ -485,6 +491,154 @@ static void hdcp14_init(void)
);
}
+static int hdmitx_set_audmode(struct hdmitx_dev *hdev)
+{
+ int i;
+ unsigned int data32;
+ unsigned int aud_n_para;
+
+ pr_info("hdmtix: set audio\n");
+ hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 3, 2, 2);
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 0, 1);
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 3, 1);
+
+ /* Disable HDMI audio clock input and its I2S input */
+ hd_write_reg(P_AIU_HDMI_CLK_DATA_CTRL, 0);
+
+ /* Enable HDMI I2S input from the selected source */
+ hd_write_reg(P_AIU_HDMI_CLK_DATA_CTRL, 0x22);
+
+ /* I2S Sampler config */
+ data32 = 0;
+/* [ 3] fifo_empty_mask: 0=enable int; 1=mask int. */
+ data32 |= (1 << 3);
+/* [ 2] fifo_full_mask: 0=enable int; 1=mask int. */
+ data32 |= (1 << 2);
+ hdmitx_wr_reg(HDMITX_DWC_AUD_INT, data32);
+
+ data32 = 0;
+/* [ 4] fifo_overrun_mask: 0=enable int; 1=mask int.
+ * Enable it later when audio starts. */
+ data32 |= (1 << 4);
+ hdmitx_wr_reg(HDMITX_DWC_AUD_INT1, data32);
+/* [ 5] 0=select SPDIF; 1=select I2S. */
+ data32 = 0;
+ data32 |= (0 << 7); /* [ 7] sw_audio_fifo_rst */
+ data32 |= (0 << 5);
+ data32 |= (0 << 0); /* [3:0] i2s_in_en: enable it later in test.c */
+/* if enable it now, fifo_overrun will happen, because packet don't get sent
+ * out until initial DE detected. */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_CONF0, data32);
+
+ data32 = 0;
+ data32 |= (0 << 5); /* [7:5] i2s_mode: 0=standard I2S mode */
+ data32 |= (24 << 0); /* [4:0] i2s_width */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_CONF1, data32);
+
+ data32 = 0;
+ data32 |= (0 << 1); /* [ 1] NLPCM */
+ data32 |= (0 << 0); /* [ 0] HBR */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_CONF2, data32);
+
+ /* spdif sampler config */
+ /* [ 2] SPDIF fifo_full_mask: 0=enable int; 1=mask int. */
+ /* [ 3] SPDIF fifo_empty_mask: 0=enable int; 1=mask int. */
+ data32 = 0;
+ data32 |= (1 << 3);
+ data32 |= (1 << 2);
+ hdmitx_wr_reg(HDMITX_DWC_AUD_SPDIFINT, data32);
+ /* [ 4] SPDIF fifo_overrun_mask: 0=enable int; 1=mask int. */
+ data32 = 0;
+ data32 |= (0 << 4);
+ hdmitx_wr_reg(HDMITX_DWC_AUD_SPDIFINT1, data32);
+
+ data32 = 0;
+ data32 |= (0 << 7); /* [ 7] sw_audio_fifo_rst */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_SPDIF0, data32);
+
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF0, 0, 0, 4); /* CT */
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF0, 1, 4, 3); /* CC */
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF1, 0, 0, 3); /* SF */
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF1, 0, 4, 2); /* SS */
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF2, 0x00);
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF3, 0);
+
+ /* audio packetizer config */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_INPUTCLKFS, 0);
+
+ /* 48kHz 2ch PCM as default */
+ aud_n_para = 6144;
+ switch (hdev->vic) {
+ case HDMI_3840x2160p24_16x9:
+ case HDMI_3840x2160p25_16x9:
+ case HDMI_3840x2160p30_16x9:
+ case HDMI_4096x2160p24_256x135:
+ case HDMI_4096x2160p25_256x135:
+ case HDMI_4096x2160p30_256x135:
+ aud_n_para = 5120;
+ break;
+ case HDMI_3840x2160p50_16x9:
+ case HDMI_3840x2160p60_16x9:
+ case HDMI_3840x2160p50_64x27:
+ case HDMI_3840x2160p60_64x27:
+ if (hdev->para->cs == HDMI_COLOR_FORMAT_420)
+ aud_n_para = 5120;
+ break;
+ default:
+ break;
+ }
+
+ /* ACR packet configuration */
+ data32 = 0;
+ data32 |= (1 << 7); /* [ 7] ncts_atomic_write */
+ data32 |= (0 << 0); /* [3:0] AudN[19:16] */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_N3, data32);
+
+ data32 = 0;
+ data32 |= (0 << 7); /* [7:5] N_shift */
+ data32 |= (0 << 4); /* [ 4] CTS_manual */
+ data32 |= (0 << 0); /* [3:0] manual AudCTS[19:16] */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_CTS3, data32);
+
+ hdmitx_wr_reg(HDMITX_DWC_AUD_CTS2, 0); /* manual AudCTS[15:8] */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_CTS1, 0); /* manual AudCTS[7:0] */
+
+ data32 = 0;
+ data32 |= (1 << 7); /* [ 7] ncts_atomic_write */
+ data32 |= (((aud_n_para>>16)&0xf) << 0); /* [3:0] AudN[19:16] */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_N3, data32);
+ hdmitx_wr_reg(HDMITX_DWC_AUD_N2, (aud_n_para>>8)&0xff); /* AudN[15:8] */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_N1, aud_n_para&0xff); /* AudN[7:0] */
+ for (i = 0; i < 9; i++)
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS0+i, 0x00);
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDSV, 0x11);
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS7, 0x02);
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS8, 0xd2);
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS3, 0x00);
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS5, 0x00);
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS7,
+ 0x2, 0, 4); /*CSB 27:24*/
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS7, 0x0, 6, 2); /*CSB 31:30*/
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS7, 0x0, 4, 2); /*CSB 29:28*/
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS8, 0x2, 0, 4); /*CSB 35:32*/
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS8, /* CSB 39:36 */
+ 0xd, 4, 4);
+
+ hdmitx_set_reg_bits(HDMITX_DWC_AUD_CONF0, 0, 5, 1);
+ /* reset audio fifo */
+ hdmitx_set_reg_bits(HDMITX_DWC_AUD_CONF0, 1, 7, 1);
+ hdmitx_set_reg_bits(HDMITX_DWC_AUD_CONF0, 0, 7, 1);
+ hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF0, 1, 7, 1);
+ hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF0, 0, 7, 1);
+ hdmitx_wr_reg(HDMITX_DWC_MC_SWRSTZREQ, 0xe7);
+ /* need reset again */
+ hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF0, 1, 7, 1);
+ hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF0, 0, 7, 1);
+ hdmitx_wr_reg(HDMITX_DWC_AUD_N1, hdmitx_rd_reg(HDMITX_DWC_AUD_N1));
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO3, 1, 0, 1);
+ return 0;
+}
+
/*
* set Source Product Description InfoFrame
*/
@@ -1324,7 +1478,6 @@ static void enc_vpu_bridge_reset(int mode)
{
unsigned int wr_clk = 0;
- printk("%s[%d]\n", __func__, __LINE__);
wr_clk = (hd_read_reg(P_VPU_HDMI_SETTING) & 0xf00) >> 8;
if (mode) {
hd_set_reg_bits(P_VPU_HDMI_SETTING, 0, 0, 2); // [ 0] src_sel_enci: Disable ENCP output to HDMI
diff --git a/arch/arm/cpu/armv8/g12a/sound.c b/arch/arm/cpu/armv8/g12a/sound.c
new file mode 100644
index 0000000..004537e
--- a/dev/null
+++ b/arch/arm/cpu/armv8/g12a/sound.c
@@ -0,0 +1,209 @@
+/*
+ * arch/arm/cpu/armv8/gx12a/sound.c
+ *
+ * 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 named License,
+ * or 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.
+ *
+ */
+#include <asm/arch/io.h>
+#include <asm/arch/secure_apb.h>
+#include <common.h>
+#include <amlogic/auge_sound.h>
+#include <asm/arch/cpu.h>
+#include <asm/cpu_id.h>
+
+#define EE_AUDIO_FRDDR_A_CTRL2 (0xff642000 + (0x07a << 2))
+
+struct aiu_958_channel_status {
+ unsigned short chstat0_l;
+ unsigned short chstat1_l;
+ unsigned short chstat0_r;
+ unsigned short chstat1_r;
+};
+
+/* g12a audio base address: 0xFF642000 */
+/* sm1 audio base address: 0xFF660000 */
+static int audiobus_read(unsigned long reg, unsigned int *val)
+{
+ if (get_cpu_id().family_id == MESON_CPU_MAJOR_ID_SM1) {
+ *val = readl(reg + 0x1E000);
+ } else {
+ *val = readl(reg);
+ }
+
+ return 0;
+}
+
+static void hhi_write(unsigned long reg, unsigned int val)
+{
+ writel(val, reg);
+}
+
+static void audiobus_write(unsigned long reg, unsigned int val)
+{
+ if (get_cpu_id().family_id == MESON_CPU_MAJOR_ID_SM1) {
+ writel(val, reg + 0x1E000);
+ } else {
+ writel(val, reg);
+ }
+}
+
+static int audiobus_update_bits(unsigned int reg, unsigned int mask, unsigned int value)
+{
+ bool change;
+ unsigned int old, new;
+
+ audiobus_read(reg, &old);
+
+ new = (old & ~mask) | (value & mask);
+ change = old != new;
+ if (change)
+ audiobus_write(reg, new);
+
+ return change;
+}
+
+static void aml_set_audio_spdif_clk(void)
+{
+ /*mpll0: 25m*/
+ hhi_write(HHI_MPLL_CNTL0, 0x543);
+ hhi_write(HHI_MPLL_CNTL1, 0xC5101856);
+ hhi_write(HHI_MPLL_CNTL2, 0x40000033);
+
+ /* audio clk gate */
+ audiobus_write(EE_AUDIO_CLK_GATE_EN,
+ 1 << 17 /* spdifout */
+ | 1 << 9 /* frddra */
+ | 1 << 0 /* ddr_arb */);
+
+ /*SPDIFOUT_CTRL clk:6m*/
+ audiobus_write(EE_AUDIO_CLK_SPDIFOUT_CTRL,
+ 1 << 31 /* enable */
+ | 0 << 24 /* mpll0 */
+ | 3 << 0 /* dividor */);
+}
+
+static void aml_spdif_fifo_ctrl(void)
+{
+ /* reg mute val */
+ audiobus_write(EE_AUDIO_SPDIFOUT_MUTE_VAL, 0x0);
+
+ /* mask lane0 L/R, lsb first, insert data from 31bits */
+ audiobus_update_bits(EE_AUDIO_SPDIFOUT_CTRL0,
+ 0x1<<20 | 0x1<<19 | 0xff << 4,
+ 0x0<<20 | 0x0<<19 | 0x3 << 4);
+
+ /* split 64bits ddr data to 2 sample */
+ /* msb position of data */
+ /* frddr_A */
+ audiobus_update_bits(EE_AUDIO_SPDIFOUT_CTRL1,
+ 0x3 << 24 | 0x1f << 8 | 0x7 << 4,
+ 0 << 24 | (32 - 1) << 8 | 3<<4);
+
+ audiobus_write(EE_AUDIO_SPDIFOUT_SWAP, 0x1 << 4);
+}
+
+static void spdifout_set_pcm_chsts(struct aiu_958_channel_status *set)
+{
+ if (!set) {
+ printf("spdifout_set_pcm_chsts, error set NULL point\n");
+ return;
+ }
+
+ audiobus_write(EE_AUDIO_SPDIFOUT_CHSTS0, set->chstat1_l << 16 | set->chstat0_l);
+ audiobus_write(EE_AUDIO_SPDIFOUT_CHSTS6, set->chstat1_r << 16 | set->chstat0_r);
+}
+
+void frddr_init_without_mngr(void)
+{
+ 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;
+
+ audiobus_write(EE_AUDIO_ARB_CTRL, 0x800000ff);
+
+ audiobus_write(EE_AUDIO_FRDDR_A_START_ADDR, start_addr);
+
+ audiobus_write(EE_AUDIO_FRDDR_A_INIT_ADDR, start_addr);
+
+ audiobus_write(EE_AUDIO_FRDDR_A_FINISH_ADDR, end_addr);
+
+ audiobus_write(EE_AUDIO_FRDDR_A_INT_ADDR, int_addr);
+
+ audiobus_write(EE_AUDIO_FRDDR_A_CTRL1,
+ (0x40 - 1) << 24 | (0x20 - 1) << 16 | 2 << 8 | 0 << 0);
+
+ if (get_cpu_id().family_id == MESON_CPU_MAJOR_ID_SM1) {
+ audiobus_write(EE_AUDIO_FRDDR_A_CTRL0,
+ 1 << 31
+ | 0 << 24
+ | 4 << 16
+ );
+
+ /* src0 enable, src0 select spdifout */
+ audiobus_write(EE_AUDIO_FRDDR_A_CTRL2, 1 << 4 | 3 << 0);
+ } else {
+ audiobus_write(EE_AUDIO_FRDDR_A_CTRL0,
+ 1 << 31
+ | 0 << 24
+ | 4 << 16
+ | 1 << 3 /* src0 enable */
+ | 3 << 0 /* src0 select spdifout*/
+ );
+ }
+}
+
+static void aml_spdif_enable(void)
+{
+ /* reset */
+ audiobus_update_bits(EE_AUDIO_SPDIFOUT_CTRL0, 3<<28, 0);
+ audiobus_update_bits(EE_AUDIO_SPDIFOUT_CTRL0, 1<<29, 1<<29);
+ audiobus_update_bits(EE_AUDIO_SPDIFOUT_CTRL0, 1<<28, 1<<28);
+ /* enable */
+ audiobus_update_bits(EE_AUDIO_SPDIFOUT_CTRL0, 1 << 31, 1 << 31);
+
+ /* tohdmitx enable */
+ audiobus_write(EE_AUDIO_TOHDMITX_CTRL0,
+ 1 << 31
+ | 1 << 3 /* spdif_clk_cap_inv */
+ | 0 << 2 /* spdif_clk_inv */
+ | 0 << 1 /* spdif_out */
+ | 0 << 0 /* spdif_clk */
+ );
+}
+
+static void aml_spdif_play(void)
+{
+ struct aiu_958_channel_status chstat;
+
+ chstat.chstat0_l = 0x0100;
+ chstat.chstat0_r = 0x0100;
+ chstat.chstat1_l = 0X200;
+ chstat.chstat1_r = 0X200;
+
+ aml_spdif_fifo_ctrl();
+ spdifout_set_pcm_chsts(&chstat);
+ frddr_init_without_mngr();
+ aml_spdif_enable();
+}
+
+int aml_audio_init(void)
+{
+ printf("aml_audio_init\n");
+
+ aml_set_audio_spdif_clk();
+ aml_spdif_play();
+
+ return 0;
+}
diff --git a/arch/arm/cpu/armv8/g12b/Makefile b/arch/arm/cpu/armv8/g12b/Makefile
index 72bd377..e9f843e 100644
--- a/arch/arm/cpu/armv8/g12b/Makefile
+++ b/arch/arm/cpu/armv8/g12b/Makefile
@@ -9,3 +9,4 @@ obj-y += mailbox.o
obj-y += gate_init.o
obj-y += power_cal.o
obj-$(CONFIG_CMD_PLLTEST) += pll.o
+obj-$(CONFIG_AML_HDMITX20) += sound.o
diff --git a/arch/arm/cpu/armv8/g12b/hdmitx20/hdmitx_set.c b/arch/arm/cpu/armv8/g12b/hdmitx20/hdmitx_set.c
index af1b1cf..2d793c6 100644
--- a/arch/arm/cpu/armv8/g12b/hdmitx20/hdmitx_set.c
+++ b/arch/arm/cpu/armv8/g12b/hdmitx20/hdmitx_set.c
@@ -25,6 +25,7 @@
#include <asm/cpu_id.h>
#include <amlogic/vout.h>
#include <amlogic/hdmi.h>
+#include <amlogic/auge_sound.h>
#include "hdmitx_reg.h"
#include "hdmitx_tvenc.h"
#include "mach_reg.h"
@@ -90,6 +91,7 @@ static void hdelay(int us)
#define msleep(i) hdelay(i)
static void hdmitx_set_hw(struct hdmitx_dev *hdev);
+static int hdmitx_set_audmode(struct hdmitx_dev *hdev);
// Internal functions:
static void hdmitx_csc_config (unsigned char input_color_format,
@@ -426,10 +428,12 @@ void hdmi_tx_set(struct hdmitx_dev *hdev)
{
unsigned char checksum[11];
+ aml_audio_init(); /* Init audio hw firstly */
hdmitx_hw_init();
hdmitx_debug();
ddc_init();
hdmitx_set_hw(hdev);
+ hdmitx_set_audmode(hdev);
hdmitx_debug();
//kernel will determine output mode on its own
setenv("hdmimode", getenv("outputmode"));
@@ -486,6 +490,154 @@ static void hdcp14_init(void)
);
}
+static int hdmitx_set_audmode(struct hdmitx_dev *hdev)
+{
+ int i;
+ unsigned int data32;
+ unsigned int aud_n_para;
+
+ pr_info("hdmtix: set audio\n");
+ hdmitx_set_reg_bits(HDMITX_TOP_CLK_CNTL, 3, 2, 2);
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 0, 1);
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_PACKET_TX_EN, 1, 3, 1);
+
+ /* Disable HDMI audio clock input and its I2S input */
+ hd_write_reg(P_AIU_HDMI_CLK_DATA_CTRL, 0);
+
+ /* Enable HDMI I2S input from the selected source */
+ hd_write_reg(P_AIU_HDMI_CLK_DATA_CTRL, 0x22);
+
+ /* I2S Sampler config */
+ data32 = 0;
+/* [ 3] fifo_empty_mask: 0=enable int; 1=mask int. */
+ data32 |= (1 << 3);
+/* [ 2] fifo_full_mask: 0=enable int; 1=mask int. */
+ data32 |= (1 << 2);
+ hdmitx_wr_reg(HDMITX_DWC_AUD_INT, data32);
+
+ data32 = 0;
+/* [ 4] fifo_overrun_mask: 0=enable int; 1=mask int.
+ * Enable it later when audio starts. */
+ data32 |= (1 << 4);
+ hdmitx_wr_reg(HDMITX_DWC_AUD_INT1, data32);
+/* [ 5] 0=select SPDIF; 1=select I2S. */
+ data32 = 0;
+ data32 |= (0 << 7); /* [ 7] sw_audio_fifo_rst */
+ data32 |= (0 << 5);
+ data32 |= (0 << 0); /* [3:0] i2s_in_en: enable it later in test.c */
+/* if enable it now, fifo_overrun will happen, because packet don't get sent
+ * out until initial DE detected. */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_CONF0, data32);
+
+ data32 = 0;
+ data32 |= (0 << 5); /* [7:5] i2s_mode: 0=standard I2S mode */
+ data32 |= (24 << 0); /* [4:0] i2s_width */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_CONF1, data32);
+
+ data32 = 0;
+ data32 |= (0 << 1); /* [ 1] NLPCM */
+ data32 |= (0 << 0); /* [ 0] HBR */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_CONF2, data32);
+
+ /* spdif sampler config */
+ /* [ 2] SPDIF fifo_full_mask: 0=enable int; 1=mask int. */
+ /* [ 3] SPDIF fifo_empty_mask: 0=enable int; 1=mask int. */
+ data32 = 0;
+ data32 |= (1 << 3);
+ data32 |= (1 << 2);
+ hdmitx_wr_reg(HDMITX_DWC_AUD_SPDIFINT, data32);
+ /* [ 4] SPDIF fifo_overrun_mask: 0=enable int; 1=mask int. */
+ data32 = 0;
+ data32 |= (0 << 4);
+ hdmitx_wr_reg(HDMITX_DWC_AUD_SPDIFINT1, data32);
+
+ data32 = 0;
+ data32 |= (0 << 7); /* [ 7] sw_audio_fifo_rst */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_SPDIF0, data32);
+
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF0, 0, 0, 4); /* CT */
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF0, 1, 4, 3); /* CC */
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF1, 0, 0, 3); /* SF */
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDICONF1, 0, 4, 2); /* SS */
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF2, 0x00);
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDICONF3, 0);
+
+ /* audio packetizer config */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_INPUTCLKFS, 0);
+
+ /* 48kHz 2ch PCM as default */
+ aud_n_para = 6144;
+ switch (hdev->vic) {
+ case HDMI_3840x2160p24_16x9:
+ case HDMI_3840x2160p25_16x9:
+ case HDMI_3840x2160p30_16x9:
+ case HDMI_4096x2160p24_256x135:
+ case HDMI_4096x2160p25_256x135:
+ case HDMI_4096x2160p30_256x135:
+ aud_n_para = 5120;
+ break;
+ case HDMI_3840x2160p50_16x9:
+ case HDMI_3840x2160p60_16x9:
+ case HDMI_3840x2160p50_64x27:
+ case HDMI_3840x2160p60_64x27:
+ if (hdev->para->cs == HDMI_COLOR_FORMAT_420)
+ aud_n_para = 5120;
+ break;
+ default:
+ break;
+ }
+
+ /* ACR packet configuration */
+ data32 = 0;
+ data32 |= (1 << 7); /* [ 7] ncts_atomic_write */
+ data32 |= (0 << 0); /* [3:0] AudN[19:16] */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_N3, data32);
+
+ data32 = 0;
+ data32 |= (0 << 7); /* [7:5] N_shift */
+ data32 |= (0 << 4); /* [ 4] CTS_manual */
+ data32 |= (0 << 0); /* [3:0] manual AudCTS[19:16] */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_CTS3, data32);
+
+ hdmitx_wr_reg(HDMITX_DWC_AUD_CTS2, 0); /* manual AudCTS[15:8] */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_CTS1, 0); /* manual AudCTS[7:0] */
+
+ data32 = 0;
+ data32 |= (1 << 7); /* [ 7] ncts_atomic_write */
+ data32 |= (((aud_n_para>>16)&0xf) << 0); /* [3:0] AudN[19:16] */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_N3, data32);
+ hdmitx_wr_reg(HDMITX_DWC_AUD_N2, (aud_n_para>>8)&0xff); /* AudN[15:8] */
+ hdmitx_wr_reg(HDMITX_DWC_AUD_N1, aud_n_para&0xff); /* AudN[7:0] */
+ for (i = 0; i < 9; i++)
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS0+i, 0x00);
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDSV, 0x11);
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS7, 0x02);
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS8, 0xd2);
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS3, 0x00);
+ hdmitx_wr_reg(HDMITX_DWC_FC_AUDSCHNLS5, 0x00);
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS7,
+ 0x2, 0, 4); /*CSB 27:24*/
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS7, 0x0, 6, 2); /*CSB 31:30*/
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS7, 0x0, 4, 2); /*CSB 29:28*/
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS8, 0x2, 0, 4); /*CSB 35:32*/
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_AUDSCHNLS8, /* CSB 39:36 */
+ 0xd, 4, 4);
+
+ hdmitx_set_reg_bits(HDMITX_DWC_AUD_CONF0, 0, 5, 1);
+ /* reset audio fifo */
+ hdmitx_set_reg_bits(HDMITX_DWC_AUD_CONF0, 1, 7, 1);
+ hdmitx_set_reg_bits(HDMITX_DWC_AUD_CONF0, 0, 7, 1);
+ hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF0, 1, 7, 1);
+ hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF0, 0, 7, 1);
+ hdmitx_wr_reg(HDMITX_DWC_MC_SWRSTZREQ, 0xe7);
+ /* need reset again */
+ hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF0, 1, 7, 1);
+ hdmitx_set_reg_bits(HDMITX_DWC_AUD_SPDIF0, 0, 7, 1);
+ hdmitx_wr_reg(HDMITX_DWC_AUD_N1, hdmitx_rd_reg(HDMITX_DWC_AUD_N1));
+ hdmitx_set_reg_bits(HDMITX_DWC_FC_DATAUTO3, 1, 0, 1);
+ return 0;
+}
+
/*
* set Source Product Description InfoFrame
*/
@@ -1325,7 +1477,6 @@ static void enc_vpu_bridge_reset(int mode)
{
unsigned int wr_clk = 0;
- printk("%s[%d]\n", __func__, __LINE__);
wr_clk = (hd_read_reg(P_VPU_HDMI_SETTING) & 0xf00) >> 8;
if (mode) {
hd_set_reg_bits(P_VPU_HDMI_SETTING, 0, 0, 2); // [ 0] src_sel_enci: Disable ENCP output to HDMI
diff --git a/arch/arm/cpu/armv8/g12b/sound.c b/arch/arm/cpu/armv8/g12b/sound.c
new file mode 100644
index 0000000..44f5ae1
--- a/dev/null
+++ b/arch/arm/cpu/armv8/g12b/sound.c
@@ -0,0 +1,180 @@
+/*
+ * arch/arm/cpu/armv8/gx12b/sound.c
+ *
+ * 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 named License,
+ * or 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.
+ *
+ */
+#include <asm/arch/io.h>
+#include <asm/arch/secure_apb.h>
+#include <common.h>
+#include <amlogic/auge_sound.h>
+
+
+struct aiu_958_channel_status {
+ unsigned short chstat0_l;
+ unsigned short chstat1_l;
+ unsigned short chstat0_r;
+ unsigned short chstat1_r;
+};
+
+static int audiobus_read(unsigned long reg, unsigned int *val)
+{
+ *val = readl(reg);
+
+ return 0;
+}
+
+static void audiobus_write(unsigned long reg, unsigned int val)
+{
+ writel(val, reg);
+}
+
+static int audiobus_update_bits(unsigned int reg, unsigned int mask, unsigned int value)
+{
+ bool change;
+ unsigned int old, new;
+
+ audiobus_read(reg, &old);
+
+ new = (old & ~mask) | (value & mask);
+ change = old != new;
+ if (change)
+ audiobus_write(reg, new);
+
+ return change;
+}
+
+static void aml_set_audio_spdif_clk(void)
+{
+ /*mpll0: 25m*/
+ audiobus_write(HHI_MPLL_CNTL0, 0x543);
+ audiobus_write(HHI_MPLL_CNTL1, 0xC5101856);
+ audiobus_write(HHI_MPLL_CNTL2, 0x40000033);
+
+ /* audio clk gate */
+ audiobus_write(EE_AUDIO_CLK_GATE_EN,
+ 1 << 17 /* spdifout */
+ | 1 << 9 /* frddra */
+ | 1 << 0 /* ddr_arb */);
+
+ /*SPDIFOUT_CTRL clk:6m*/
+ audiobus_write(EE_AUDIO_CLK_SPDIFOUT_CTRL,
+ 1 << 31 /* enable */
+ | 0 << 24 /* mpll0 */
+ | 3 << 0 /* dividor */);
+}
+
+static void aml_spdif_fifo_ctrl(void)
+{
+ /* reg mute val */
+ audiobus_write(EE_AUDIO_SPDIFOUT_MUTE_VAL, 0x0);
+
+ /* mask lane0 L/R, lsb first, insert data from 31bits */
+ audiobus_update_bits(EE_AUDIO_SPDIFOUT_CTRL0,
+ 0x1<<20 | 0x1<<19 | 0xff << 4,
+ 0x0<<20 | 0x0<<19 | 0x3 << 4);
+
+ /* split 64bits ddr data to 2 sample */
+ /* msb position of data */
+ /* frddr_A */
+ audiobus_update_bits(EE_AUDIO_SPDIFOUT_CTRL1,
+ 0x3 << 24 | 0x1f << 8 | 0x7 << 4,
+ 0 << 24 | (32 - 1) << 8 | 3<<4);
+
+ audiobus_write(EE_AUDIO_SPDIFOUT_SWAP, 0x1 << 4);
+}
+
+static void spdifout_set_pcm_chsts(struct aiu_958_channel_status *set)
+{
+ if (!set) {
+ printf("spdifout_set_pcm_chsts, error set NULL point\n");
+ return;
+ }
+
+ audiobus_write(EE_AUDIO_SPDIFOUT_CHSTS0, set->chstat1_l << 16 | set->chstat0_l);
+ audiobus_write(EE_AUDIO_SPDIFOUT_CHSTS6, set->chstat1_r << 16 | set->chstat0_r);
+}
+
+void frddr_init_without_mngr(void)
+{
+ 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;
+
+ audiobus_write(EE_AUDIO_ARB_CTRL, 0x800000ff);
+
+ audiobus_write(EE_AUDIO_FRDDR_A_START_ADDR, start_addr);
+
+ audiobus_write(EE_AUDIO_FRDDR_A_INIT_ADDR, start_addr);
+
+ audiobus_write(EE_AUDIO_FRDDR_A_FINISH_ADDR, end_addr);
+
+ audiobus_write(EE_AUDIO_FRDDR_A_INT_ADDR, int_addr);
+
+ audiobus_write(EE_AUDIO_FRDDR_A_CTRL1,
+ (0x40 - 1) << 24 | (0x20 - 1) << 16 | 2 << 8 | 0 << 0);
+
+ audiobus_write(EE_AUDIO_FRDDR_A_CTRL0,
+ 1 << 31
+ | 0 << 24
+ | 4 << 16
+ | 1 << 3 /* src0 enable */
+ | 3 << 0 /* src0 select spdifout*/
+ );
+}
+
+static void aml_spdif_enable(void)
+{
+ /* reset */
+ audiobus_update_bits(EE_AUDIO_SPDIFOUT_CTRL0, 3<<28, 0);
+ audiobus_update_bits(EE_AUDIO_SPDIFOUT_CTRL0, 1<<29, 1<<29);
+ audiobus_update_bits(EE_AUDIO_SPDIFOUT_CTRL0, 1<<28, 1<<28);
+ /* enable */
+ audiobus_update_bits(EE_AUDIO_SPDIFOUT_CTRL0, 1 << 31, 1 << 31);
+
+ /* tohdmitx enable */
+ audiobus_write(EE_AUDIO_TOHDMITX_CTRL0,
+ 1 << 31
+ | 1 << 3 /* spdif_clk_cap_inv */
+ | 0 << 2 /* spdif_clk_inv */
+ | 0 << 1 /* spdif_out */
+ | 0 << 0 /* spdif_clk */
+ );
+}
+
+static void aml_spdif_play(void)
+{
+ struct aiu_958_channel_status chstat;
+
+ chstat.chstat0_l = 0x0100;
+ chstat.chstat0_r = 0x0100;
+ chstat.chstat1_l = 0X200;
+ chstat.chstat1_r = 0X200;
+
+ aml_spdif_fifo_ctrl();
+ spdifout_set_pcm_chsts(&chstat);
+ frddr_init_without_mngr();
+ aml_spdif_enable();
+}
+
+int aml_audio_init(void)
+{
+ printf("aml_audio_init\n");
+
+ aml_set_audio_spdif_clk();
+ aml_spdif_play();
+
+ return 0;
+}
diff --git a/include/amlogic/auge_sound.h b/include/amlogic/auge_sound.h
new file mode 100644
index 0000000..971de67
--- a/dev/null
+++ b/include/amlogic/auge_sound.h
@@ -0,0 +1,23 @@
+/*
+ * include/amlogic/auge_sound.h
+ *
+ * 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 named License,
+ * or 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 __AUGE_SOUND_H__
+#define __AUGE_SOUND_H__
+
+/* auge audio register is defined in asm/arch/secure_apb.h */
+
+int aml_audio_init(void);
+
+#endif