author | Zongdong 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) |
commit | 7a3c1b5090fa317eb33a05a13decabde3c2e788a (patch) | |
tree | 68b257ff931ce0e71a4320d85c84c49d73e1679e | |
parent | ccc5c3bb0b9e46e90596129cad3e3f0acc722fc7 (diff) | |
download | uboot-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>
-rw-r--r-- | arch/arm/cpu/armv8/g12a/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/g12a/hdmitx20/hdmitx_set.c | 155 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/g12a/sound.c | 209 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/g12b/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/g12b/hdmitx20/hdmitx_set.c | 153 | ||||
-rw-r--r-- | arch/arm/cpu/armv8/g12b/sound.c | 180 | ||||
-rw-r--r-- | include/amlogic/auge_sound.h | 23 |
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 |