| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (C) 2019 Amlogic, Inc. All rights reserved. |
| * |
| */ |
| |
| #define DEBUG |
| |
| #include <linux/types.h> |
| #include <linux/kernel.h> |
| #include <sound/asoundef.h> |
| |
| #include "earc_hw.h" |
| |
| void earcrx_pll_refresh(struct regmap *top_map, |
| enum pll_rst_src rst_src, |
| bool level) |
| { |
| pr_info("%s, level %d\n", __func__, level); |
| if (rst_src == RST_BY_SELF) { |
| /* pll tdc mode */ |
| mmio_update_bits(top_map, EARCRX_PLL_CTRL3, |
| 0x1 << 15, 0x1 << 15); |
| |
| /* pll self reset */ |
| mmio_update_bits(top_map, EARCRX_PLL_CTRL0, |
| 0x1 << 29, 0x1 << 29); |
| mmio_update_bits(top_map, EARCRX_PLL_CTRL0, |
| 0x1 << 29, 0x0 << 29); |
| |
| mmio_update_bits(top_map, EARCRX_PLL_CTRL3, |
| 0x1 << 15, 0x0 << 15); |
| } else if (rst_src == RST_BY_D2A) { |
| int rst_src_val = level ? 0x10 : 0x0; |
| |
| mmio_update_bits(top_map, EARCRX_PLL_CTRL0, |
| 0x3 << 23, rst_src_val << 23); |
| } else if (rst_src == RST_BY_DMACRX) { |
| int rst_src_val = level ? 0x01 : 0x0; |
| |
| mmio_update_bits(top_map, EARCRX_PLL_CTRL0, |
| 0x3 << 23, rst_src_val << 23); |
| } |
| } |
| |
| void earcrx_cmdc_int_mask(struct regmap *top_map) |
| { |
| /* set irq mask */ |
| mmio_write(top_map, EARCRX_CMDC_INT_MASK, |
| (1 << 15) | /* idle2_int */ |
| (1 << 14) | /* idle1_int */ |
| (1 << 13) | /* disc2_int */ |
| (1 << 12) | /* disc1_int */ |
| (1 << 11) | /* earc_int */ |
| (1 << 10) | /* hb_status_int */ |
| (1 << 9) | /* losthb_int */ |
| (1 << 8) | /* timeout_int */ |
| (1 << 7) | /* status_ch_int */ |
| (0 << 6) | /* int_rec_invalid_id */ |
| (0 << 5) | /* int_rec_invalid_offset */ |
| (0 << 4) | /* int_rec_unexp */ |
| (0 << 3) | /* int_rec_ecc_err */ |
| (0 << 2) | /* int_rec_parity_err */ |
| (0 << 1) | /* int_recv_packet */ |
| (0 << 0) /* int_rec_time_out */ |
| ); |
| } |
| |
| void earcrx_cmdc_init(struct regmap *top_map, bool en, bool rx_dmac_sync_int, bool rterm_on) |
| { |
| if (rterm_on) { |
| mmio_write(top_map, EARCRX_ANA_CTRL0, |
| en << 31 | /* earcrx_en_d2a */ |
| 0x10 << 25 | /* earcrx_cmdcrx_reftrim */ |
| 0x10 << 20 | /* earcrx_idr_trim */ |
| 0x10 << 15 | /* earcrx_rterm_trim */ |
| 0x4 << 12 | /* earcrx_cmdctx_ack_hystrim */ |
| 0x10 << 7 | /* earcrx_cmdctx_ack_reftrim */ |
| 0x1 << 4 | /* earcrx_cmdcrx_rcfilter_sel */ |
| 0x4 << 0 /* earcrx_cmdcrx_hystrim */ |
| ); |
| mmio_write(top_map, EARCRX_ANA_CTRL1, |
| 0x1 << 11 | 0x1 << 10 | 0x8 << 4 | 0x8 << 0); |
| } else { |
| mmio_write(top_map, EARCRX_ANA_CTRL0, |
| en << 31 | /* earcrx_en_d2a */ |
| 0x10 << 24 | /* earcrx_cmdcrx_reftrim */ |
| 0x8 << 20 | /* earcrx_idr_trim */ |
| 0x10 << 15 | /* earcrx_rterm_trim */ |
| 0x4 << 12 | /* earcrx_cmdctx_ack_hystrim */ |
| 0x10 << 7 | /* earcrx_cmdctx_ack_reftrim */ |
| 0x1 << 4 | /* earcrx_cmdcrx_rcfilter_sel */ |
| 0x4 << 0 /* earcrx_cmdcrx_hystrim */ |
| ); |
| } |
| |
| mmio_write(top_map, EARCRX_PLL_CTRL3, |
| 0x2 << 20 | /* earcrx_pll_bias_adj */ |
| 0x4 << 16 | /* earcrx_pll_rou */ |
| en << 13 /* earcrx_pll_dco_sdm_e */ |
| ); |
| |
| mmio_write(top_map, EARCRX_PLL_CTRL0, |
| en << 28 | /* earcrx_pll_en */ |
| 0x1 << 23 | /* earcrx_pll_dmacrx_sqout_rstn_sel */ |
| 0x1 << 10 /* earcrx_pll_n */ |
| ); |
| mmio_write(top_map, |
| EARCRX_PLL_CTRL1, |
| 0x1410a8); |
| mmio_update_bits(top_map, |
| EARCRX_PLL_CTRL2, |
| 0x3, |
| 0x2); |
| mmio_write(top_map, |
| EARCRX_PLL_CTRL3, |
| 0x20046000); |
| } |
| |
| void earcrx_cmdc_arc_connect(struct regmap *cmdc_map, bool init) |
| { |
| if (init) |
| mmio_update_bits(cmdc_map, |
| EARC_RX_CMDC_VSM_CTRL0, |
| 0x7 << 25, |
| 0x1 << 27 | /* arc_initiated */ |
| 0x0 << 26 | /* arc_terminated */ |
| 0x1 << 25 /* arc_enable */ |
| ); |
| else |
| mmio_update_bits(cmdc_map, |
| EARC_RX_CMDC_VSM_CTRL0, |
| 0x7 << 25, |
| 0x0 << 27 | /* arc_initiated */ |
| 0x1 << 26 | /* arc_terminated */ |
| 0x0 << 25 /* arc_enable */ |
| ); |
| } |
| |
| void earcrx_cmdc_hpd_detect(struct regmap *cmdc_map, bool st) |
| { |
| if (st) { |
| mmio_update_bits(cmdc_map, |
| EARC_RX_CMDC_VSM_CTRL0, |
| 0x1 << 19, |
| 0x1 << 19 /* comma_cnt_rst */ |
| ); |
| |
| mmio_update_bits(cmdc_map, |
| EARC_RX_CMDC_VSM_CTRL0, |
| 0x1 << 19 | 0xff << 0, |
| 0x0 << 19 | /* comma_cnt_rst */ |
| 0xa << 0 |
| ); |
| } else { |
| /* soft reset */ |
| mmio_update_bits(cmdc_map, |
| EARC_RX_CMDC_TOP_CTRL1, |
| 0xf << 1, |
| 0xf << 1); |
| mmio_update_bits(cmdc_map, |
| EARC_RX_CMDC_TOP_CTRL1, |
| 0xf << 1, |
| 0x0 << 1); |
| } |
| } |
| |
| void earcrx_dmac_sync_int_enable(struct regmap *top_map, int enable) |
| { |
| /* dmac_sync dmac_valid_auto neg_int_se */ |
| mmio_update_bits(top_map, EARCRX_DMAC_INT_MASK, |
| (0x1 << 28), (enable << 28)); |
| } |
| |
| void earcrx_dmac_init(struct regmap *top_map, |
| struct regmap *dmac_map, |
| bool unstable_tick_sel, |
| bool chnum_mult_mode) |
| { |
| /* can't open bit 5 as it will cause stuck on t7 chips */ |
| mmio_update_bits(top_map, EARCRX_DMAC_INT_MASK, |
| 0x3FFFF, |
| (0x1 << 17) | /* earcrx_ana_rst c_new_format_set */ |
| (0x1 << 16) | /* earcrx_ana_rst c_earcrx_div2_hold_set */ |
| (0x1 << 15) | /* earcrx_err_correct c_bcherr_int_set */ |
| (0x0 << 14) | /* earcrx_err_correct r_afifo_overflow_set */ |
| (0x0 << 13) | /* earcrx_err_correct r_fifo_overflow_set */ |
| (0x0 << 12) | /* earcrx_user_bit_check r_fifo_overflow */ |
| (0x0 << 11) | /* earcrx_user_bit_check c_fifo_thd_pass */ |
| (0x0 << 10) | /* earcrx_user_bit_check c_u_pk_lost_int_set */ |
| (0x0 << 9) | /* arcrx_user_bit_check c_iu_pk_end */ |
| (0x0 << 8) | /* arcrx_biphase_decode c_chst_mute_clr */ |
| (0x1 << 7) | /* arcrx_biphase_decode c_find_papb */ |
| (0x1 << 6) | /* arcrx_biphase_decode c_valid_change */ |
| (0x0 << 5) | /* arcrx_biphase_decode c_find_nonpcm2pcm */ |
| (0x1 << 4) | /* arcrx_biphase_decode c_pcpd_change */ |
| (0x1 << 3) | /* arcrx_biphase_decode c_ch_status_change */ |
| (0x1 << 2) | /* arcrx_biphase_decode sample_mod_change */ |
| (0x1 << 1) | /* arcrx_biphase_decode r_parity_err */ |
| (0x0 << 0) /* arcrx_dmac_sync afifo_overflow */ |
| ); |
| |
| mmio_write(dmac_map, EARCRX_DMAC_SYNC_CTRL0, |
| (1 << 16) | /* reg_ana_buf_data_sel_en */ |
| (3 << 12) | /* reg_ana_buf_data_sel */ |
| (7 << 8) | /* reg_ana_clr_cnt */ |
| (7 << 4) /* reg_ana_set_cnt */ |
| ); |
| mmio_write(dmac_map, EARCRX_DMAC_UBIT_CTRL0, |
| (47 << 16) | /* reg_fifo_thd */ |
| (1 << 12) | /* reg_user_lr */ |
| (29 << 0) /* reg_data_bit */ |
| ); |
| mmio_write(dmac_map, EARCRX_ANA_RST_CTRL0, 1 << 31 | 2000 << 0); |
| if (chnum_mult_mode) |
| mmio_update_bits(dmac_map, EARCRX_SPDIFIN_CTRL6, 0x1 << 27, 0x1 << 27); |
| if (unstable_tick_sel) { |
| mmio_update_bits(top_map, EARCRX_DMAC_INT_MASK, 0x1 << 28, 0x1 << 28); |
| mmio_write(dmac_map, EARCRX_DMAC_SYNC_CTRL3, 0x1 << 19 | 0x2 << 16 | 0x64 << 0); |
| mmio_write(dmac_map, EARCRX_DMAC_SYNC_CTRL4, 0x1 << 19 | 0x2 << 16 | 0x32 << 0); |
| mmio_write(dmac_map, EARCRX_DMAC_SYNC_CTRL5, 0x1 << 19 | 0x2 << 16 | 0x32 << 0); |
| } |
| } |
| |
| void earcrx_arc_init(struct regmap *dmac_map) |
| { |
| unsigned int spdifin_clk = 500000000; |
| |
| /* sysclk/rate/32(bit)/2(ch)/2(bmc) */ |
| unsigned int counter_32k = (spdifin_clk / (32000 * 64)); |
| unsigned int counter_44k = (spdifin_clk / (44100 * 64)); |
| unsigned int counter_48k = (spdifin_clk / (48000 * 64)); |
| unsigned int counter_88k = (spdifin_clk / (88200 * 64)); |
| unsigned int counter_96k = (spdifin_clk / (96000 * 64)); |
| unsigned int counter_176k = (spdifin_clk / (176400 * 64)); |
| unsigned int counter_192k = (spdifin_clk / (192000 * 64)); |
| unsigned int mode0_th = 3 * (counter_32k + counter_44k) >> 1; |
| unsigned int mode1_th = 3 * (counter_44k + counter_48k) >> 1; |
| unsigned int mode2_th = 3 * (counter_48k + counter_88k) >> 1; |
| unsigned int mode3_th = 3 * (counter_88k + counter_96k) >> 1; |
| unsigned int mode4_th = 3 * (counter_96k + counter_176k) >> 1; |
| unsigned int mode5_th = 3 * (counter_176k + counter_192k) >> 1; |
| unsigned int mode0_timer = counter_32k >> 1; |
| unsigned int mode1_timer = counter_44k >> 1; |
| unsigned int mode2_timer = counter_48k >> 1; |
| unsigned int mode3_timer = counter_88k >> 1; |
| unsigned int mode4_timer = counter_96k >> 1; |
| unsigned int mode5_timer = (counter_176k >> 1); |
| unsigned int mode6_timer = (counter_192k >> 1); |
| |
| mmio_write(dmac_map, |
| EARCRX_SPDIFIN_SAMPLE_CTRL0, |
| 0x0 << 28 | /* detect by max_width */ |
| (spdifin_clk / 10000) << 0 /* base timer */ |
| ); |
| |
| mmio_write(dmac_map, |
| EARCRX_SPDIFIN_SAMPLE_CTRL1, |
| mode0_th << 20 | |
| mode1_th << 10 | |
| mode2_th << 0); |
| |
| mmio_write(dmac_map, |
| EARCRX_SPDIFIN_SAMPLE_CTRL2, |
| mode3_th << 20 | |
| mode4_th << 10 | |
| mode5_th << 0); |
| |
| mmio_write(dmac_map, |
| EARCRX_SPDIFIN_SAMPLE_CTRL3, |
| (mode0_timer << 24) | |
| (mode1_timer << 16) | |
| (mode2_timer << 8) | |
| (mode3_timer << 0) |
| ); |
| |
| mmio_write(dmac_map, |
| EARCRX_SPDIFIN_SAMPLE_CTRL4, |
| (mode4_timer << 24) | |
| (mode5_timer << 16) | |
| (mode6_timer << 8) |
| ); |
| |
| mmio_write(dmac_map, |
| EARCRX_SPDIFIN_CTRL0, |
| 0x1 << 31 | /* reg_work_en */ |
| 0x0 << 30 | /* reg_chnum_sel */ |
| 0x1 << 25 | /* reg_findpapb_en */ |
| 0x1 << 24 | /* nonpcm2pcm_th enable */ |
| 0xFFF << 12 | /* reg_nonpcm2pcm_th */ |
| 0x1 << 2 /* reg_check_parity */ |
| ); |
| mmio_write(dmac_map, |
| EARCRX_SPDIFIN_CTRL2, |
| (1 << 16) | /* auto clear compress mode if cs not compress */ |
| (1 << 15) | /* auto clear compress mode when nonpcm2pcm */ |
| (1 << 14) | /* earc_auto */ |
| (1 << 13) | /* earcin_papb_lr */ |
| (1 << 12) | /* earcin_check_papb */ |
| (19 << 4) /* earc_papb_msb */ |
| ); |
| mmio_write(dmac_map, |
| EARCRX_SPDIFIN_CTRL3, |
| (0xEC37 << 16) | /* reg_earc_pa_value */ |
| (0x5A5A << 0) /* reg_earc_pb_value */ |
| ); |
| } |
| |
| static void earcrx_mute_block_enable(struct regmap *dmac_map, bool en) |
| { |
| /* time thd, tick */ |
| mmio_update_bits(dmac_map, |
| EARCRX_SPDIFIN_CTRL1, |
| 0x7fff << 9, |
| 0x500 << 12 | /* thd */ |
| 0x4 << 9 /* tick, 1ms */ |
| ); |
| |
| /* Mute bit in CS |
| * mute mini block number, enable |
| * check channel A status always |
| */ |
| mmio_update_bits(dmac_map, |
| EARCRX_SPDIFIN_CTRL2, |
| 0x7fff << 17, |
| IEC_CS_MUTE_OFFSET | 0x2 << 19 | en << 17 |
| ); |
| } |
| |
| /* Note: mask without offset */ |
| static unsigned int earcrx_get_cs_bits(struct regmap *dmac_map, |
| int cs_offset, int mask) |
| { |
| int reg_offset = cs_offset / REG_CS_LEN; |
| int bits_offset = cs_offset % REG_CS_LEN; |
| enum channel_status_type cs_type; |
| int stats_sel, val, cs_a, cs_b; |
| |
| /* channel A status */ |
| cs_type = CS_TYPE_A; |
| stats_sel = reg_offset + cs_type * 8; |
| mmio_update_bits(dmac_map, |
| EARCRX_SPDIFIN_CTRL0, |
| 0xf << 8, |
| stats_sel << 8); |
| val = mmio_read(dmac_map, EARCRX_SPDIFIN_STAT1); |
| cs_a = (val >> bits_offset) & mask; |
| |
| /* channel B status */ |
| cs_type = CS_TYPE_B; |
| stats_sel = reg_offset + cs_type * 8; |
| mmio_update_bits(dmac_map, |
| EARCRX_SPDIFIN_CTRL0, |
| 0xf << 8, |
| stats_sel << 8); |
| val = mmio_read(dmac_map, EARCRX_SPDIFIN_STAT1); |
| cs_b = (val >> bits_offset) & mask; |
| |
| if (cs_a != cs_b) |
| pr_warn("use CHANNEL A STATUS as default.\n"); |
| |
| return cs_a; |
| } |
| |
| unsigned int earcrx_get_cs_iec958(struct regmap *dmac_map) |
| { |
| /* channel status A/B bits [31 - 0]*/ |
| return earcrx_get_cs_bits(dmac_map, |
| 0x0, 0xffffffff); |
| } |
| |
| unsigned int earcrx_get_cs_layout(struct regmap *dmac_map) |
| { |
| return earcrx_get_cs_bits(dmac_map, |
| IEC_CS_AUDIO_LAYOUT_OFFSET, |
| IEC_CS_AUDIO_LAYOUT_MASK); |
| } |
| |
| unsigned int earcrx_get_cs_ca(struct regmap *dmac_map) |
| { |
| return earcrx_get_cs_bits(dmac_map, |
| IEC_CS_AIF_DB4_OFFSET, |
| IEC_CS_AIF_DB4_MASK); |
| } |
| |
| unsigned int earcrx_get_cs_mute(struct regmap *dmac_map) |
| { |
| return earcrx_get_cs_bits(dmac_map, |
| IEC_CS_MUTE_OFFSET, |
| IEC_CS_MUTE_MASK); |
| } |
| |
| static unsigned int ecc_syndrome(unsigned int val1, unsigned int val2) |
| { |
| val1 &= ~0x5555; |
| val1 |= val2 & 0x5555; |
| |
| return val1; |
| } |
| |
| static int earcrx_get_cs_pcpd(struct regmap *dmac_map, bool ecc_check) |
| { |
| unsigned int val = earcrx_get_cs_bits(dmac_map, 192, 0xffffffff); |
| unsigned int pc_e = (val >> 16) & 0xffff; |
| unsigned int pd_e = val & 0xffff; |
| |
| if (ecc_check) |
| return ecc_syndrome(pc_e, pd_e) << 16 | |
| ecc_syndrome(pd_e, pc_e); |
| else |
| return val; |
| } |
| |
| unsigned int earcrx_get_cs_fmt(struct regmap *dmac_map, enum attend_type type) |
| { |
| enum audio_coding_types coding_type = AUDIO_CODING_TYPE_UNDEFINED; |
| unsigned int val, layout; |
| |
| val = earcrx_get_cs_bits(dmac_map, 0x0, 0x3b); |
| layout = earcrx_get_cs_layout(dmac_map); |
| |
| /* One Bit Audio, Channel Status Bits 0,1,3,4, and 5 |
| * use case: 0 0 0 1 1 for bit 0,1,3,4 and 5 |
| * use case: 0 1 1 1 1 for bit 0,1,3,4 and 5 |
| */ |
| if (unlikely((val & 0x30) == 0x30)) { |
| unsigned int val1 = earcrx_get_cs_bits(dmac_map, 0x32, 0x7); |
| |
| if (val1 == 0x0 && |
| (((val & 0x3b) == 0x30) || ((val & 0x3b) == 0x3a))) { |
| int layout = earcrx_get_cs_bits(dmac_map, |
| IEC_CS_AUDIO_LAYOUT_OFFSET, |
| IEC_CS_AUDIO_LAYOUT_MASK); |
| if (layout == LO12_OBA) { |
| coding_type = AUDIO_CODING_TYPE_SACD_12CH; |
| } else if (layout == LO6_OBA) { |
| coding_type = AUDIO_CODING_TYPE_SACD_6CH; |
| } else { |
| pr_err("unknown for DSD(One Bit Audio), default as 6ch\n"); |
| coding_type = AUDIO_CODING_TYPE_SACD_6CH; |
| } |
| } |
| } else if ((val & 0x30) == 0x20) { |
| if (layout == LO32_LPCM) { |
| coding_type = AUDIO_CODING_TYPE_MULTICH_32CH_LPCM; |
| } else if (layout == LO16_LPCM) { |
| coding_type = AUDIO_CODING_TYPE_MULTICH_16CH_LPCM; |
| } else if (layout == LO8_LPCM) { |
| coding_type = AUDIO_CODING_TYPE_MULTICH_8CH_LPCM; |
| } else if (layout == LO2_LPCM) { |
| coding_type = AUDIO_CODING_TYPE_MULTICH_2CH_LPCM; |
| } else { |
| pr_err("unknown for Multi-Ch LPCM, default as 2ch\n"); |
| coding_type = AUDIO_CODING_TYPE_MULTICH_2CH_LPCM; |
| } |
| } else if ((val & IEC958_AES0_NONAUDIO) == IEC958_AES0_NONAUDIO) { |
| if ((val & 0x38) == 0x0) { |
| if (layout == 0x7) { |
| coding_type = AUDIO_CODING_TYPE_AC3_LAYOUT_B; |
| } else { |
| int pcpd = earcrx_get_cs_pcpd(dmac_map, |
| type == ATNDTYP_EARC); |
| int pc_v = (pcpd >> 16) & 0xffff; |
| |
| /* compressed audio type */ |
| coding_type = iec_61937_pc_to_coding_type(pc_v); |
| if (coding_type == AUDIO_CODING_TYPE_UNDEFINED) |
| pr_warn("non-lpcm audio, failed to get coding type, pcpd:%#x, pc_v:%#x\n", |
| pcpd, pc_v); |
| } |
| } |
| } else { |
| coding_type = AUDIO_CODING_TYPE_STEREO_LPCM; |
| } |
| |
| return coding_type; |
| } |
| |
| static int earcrx_get_cs_channels(struct regmap *dmac_map, |
| enum audio_coding_types coding_type) |
| { |
| int channels = 0; |
| |
| switch (coding_type) { |
| case AUDIO_CODING_TYPE_MULTICH_32CH_LPCM: |
| channels = 32; |
| break; |
| case AUDIO_CODING_TYPE_MULTICH_16CH_LPCM: |
| channels = 16; |
| break; |
| case AUDIO_CODING_TYPE_MULTICH_8CH_LPCM: |
| channels = 8; |
| break; |
| case AUDIO_CODING_TYPE_MULTICH_2CH_LPCM: |
| channels = 2; |
| break; |
| case AUDIO_CODING_TYPE_SACD_12CH: |
| channels = 12; |
| break; |
| case AUDIO_CODING_TYPE_SACD_6CH: |
| channels = 6; |
| break; |
| case AUDIO_CODING_TYPE_AC3_LAYOUT_B: |
| channels = 8; /* Layout for coding type */ |
| break; |
| default: |
| channels = 2; |
| break; |
| } |
| |
| return channels; |
| } |
| |
| unsigned int earcrx_get_cs_freq(struct regmap *dmac_map, |
| enum audio_coding_types coding_type) |
| { |
| unsigned int val; |
| unsigned int csfs, freq, channels; |
| |
| val = earcrx_get_cs_bits(dmac_map, |
| IEC_CS_SFREQ_OFFSET, |
| IEC_CS_SFREQ_MASK); |
| |
| csfs = val & 0xf; |
| freq = iec_rate_from_csfs(csfs); |
| |
| /* Fix to really fs */ |
| channels = earcrx_get_cs_channels(dmac_map, coding_type); |
| freq /= (channels / 2); |
| |
| return freq; |
| } |
| |
| unsigned int earcrx_get_cs_word_length(struct regmap *dmac_map) |
| { |
| unsigned int val; |
| unsigned int max_len, len = 0; |
| |
| val = earcrx_get_cs_bits(dmac_map, |
| IEC_CS_WLEN_OFFSET, |
| IEC_CS_WLEN_MASK); |
| |
| /* Maximum audio sample word length */ |
| if (val & (1 << 0)) |
| max_len = 24; |
| else |
| max_len = 20; |
| |
| switch ((val >> 1) & 0x7) { |
| case 0: |
| len = (max_len == 24) ? 20 : 24; /* Not indicated */ |
| break; |
| case 1: |
| len = max_len - 4; |
| break; |
| case 0x5: |
| len = max_len - 0; |
| break; |
| default: |
| pr_warn("%s, Not support world length code:%#x\n", |
| __func__, (val >> 1)); |
| break; |
| } |
| |
| pr_info("max len:%d, %slen:%d, len_mask:%#x\n", |
| max_len, |
| ((val >> 1) & 0x7) == 0 ? "(n.a.)" : "", |
| len, |
| ((val >> 1) & 0x7)); |
| |
| return len; |
| } |
| |
| enum cmdc_st earcrx_cmdc_get_state(struct regmap *cmdc_map) |
| { |
| int val = mmio_read(cmdc_map, EARC_RX_CMDC_STATUS0); |
| enum cmdc_st state = (enum cmdc_st)(val & 0x7); |
| |
| return state; |
| } |
| |
| enum attend_type earcrx_cmdc_get_attended_type(struct regmap *cmdc_map) |
| { |
| int val = mmio_read(cmdc_map, EARC_RX_CMDC_STATUS0); |
| enum cmdc_st state = (enum cmdc_st)(val & 0x7); |
| enum attend_type type = ATNDTYP_DISCNCT; |
| |
| if ((val & (1 << 0x3)) && state == CMDC_ST_ARC) |
| type = ATNDTYP_ARC; |
| else if ((val & (1 << 0x4)) && state == CMDC_ST_EARC) |
| type = ATNDTYP_EARC; |
| |
| return type; |
| } |
| |
| void earcrx_cdmc_clr_irqs(struct regmap *top_map, int clr) |
| { |
| mmio_write(top_map, EARCRX_CMDC_INT_PENDING, clr); |
| } |
| |
| int earcrx_cdmc_get_irqs(struct regmap *top_map) |
| { |
| return mmio_read(top_map, EARCRX_CMDC_INT_PENDING); |
| } |
| |
| void earcrx_dmac_sync_clr_irqs(struct regmap *top_map) |
| { |
| mmio_write(top_map, EARCRX_DMAC_INT_PENDING, 0x1 << 28); |
| } |
| |
| void earcrx_dmac_clr_irqs(struct regmap *top_map, int clr) |
| { |
| mmio_write(top_map, EARCRX_DMAC_INT_PENDING, clr & 0xEFFFFFFF); |
| } |
| |
| int earcrx_dmac_get_irqs(struct regmap *top_map) |
| { |
| return mmio_read(top_map, EARCRX_DMAC_INT_PENDING); |
| } |
| |
| int earcrx_dmac_get_mask(struct regmap *top_map) |
| { |
| return mmio_read(top_map, EARCRX_DMAC_INT_MASK); |
| } |
| |
| bool earcrx_pll_dmac_valid(struct regmap *top_map) |
| { |
| unsigned int pll_status0 = mmio_read(top_map, EARCRX_PLL_STAT0); |
| |
| return (pll_status0 >> 30) & 0x3; |
| } |
| |
| void earcrx_reset(struct regmap *dmac_map) |
| { |
| /* top soft reset */ |
| mmio_update_bits(dmac_map, EARCRX_DMAC_TOP_CTRL0, 1 << 30, 0x1 << 30); |
| mmio_update_bits(dmac_map, EARCRX_DMAC_TOP_CTRL0, 1 << 30, 0x0 << 30); |
| } |
| |
| void earcrx_enable(struct regmap *cmdc_map, |
| struct regmap *dmac_map, bool enable) |
| { |
| enum attend_type type = earcrx_cmdc_get_attended_type(cmdc_map); |
| |
| if (enable) { |
| mmio_update_bits(dmac_map, EARCRX_DMAC_SYNC_CTRL0, |
| 1 << 30, /* reg_rst_afifo_out_n */ |
| 1 << 30); |
| |
| mmio_update_bits(dmac_map, EARCRX_DMAC_SYNC_CTRL0, |
| 1 << 29, /* reg_rst_afifo_in_n */ |
| 0x1 << 29); |
| |
| mmio_update_bits(dmac_map, EARCRX_ERR_CORRECT_CTRL0, |
| 1 << 29, /* reg_rst_afifo_out_n */ |
| 1 << 29 |
| ); |
| mmio_update_bits(dmac_map, EARCRX_ERR_CORRECT_CTRL0, |
| 1 << 28, /* reg_rst_afifo_in_n */ |
| 1 << 28 /* reg_rst_afifo_in_n */ |
| ); |
| } else { |
| mmio_update_bits(dmac_map, EARCRX_DMAC_SYNC_CTRL0, |
| 0x3 << 29, |
| 0x0 << 29); |
| |
| mmio_update_bits(dmac_map, EARCRX_ERR_CORRECT_CTRL0, |
| 0x3 << 28, 0x0 << 28); |
| } |
| |
| if (type == ATNDTYP_EARC) { |
| /* mute block check */ |
| earcrx_mute_block_enable(dmac_map, true); |
| |
| mmio_update_bits(dmac_map, EARCRX_DMAC_SYNC_CTRL0, |
| 1 << 31, /* reg_work_en */ |
| enable << 31); |
| } else if (type == ATNDTYP_ARC) { |
| /* mute block check */ |
| earcrx_mute_block_enable(dmac_map, false); |
| |
| mmio_update_bits(dmac_map, |
| EARCRX_SPDIFIN_SAMPLE_CTRL0, |
| 0x1 << 31, /* reg_work_enable */ |
| enable << 31); |
| |
| mmio_write(dmac_map, EARCRX_DMAC_SYNC_CTRL0, 0x0); |
| } |
| |
| mmio_update_bits(dmac_map, EARCRX_DMAC_UBIT_CTRL0, |
| 1 << 31, /* reg_work_enable */ |
| enable << 31); |
| |
| mmio_update_bits(dmac_map, EARCRX_ERR_CORRECT_CTRL0, |
| 1 << 31, |
| enable << 31); /* reg_work_en */ |
| |
| mmio_update_bits(dmac_map, EARCRX_DMAC_TOP_CTRL0, |
| 1 << 31, |
| enable << 31); /* reg_top_work_en */ |
| } |
| |
| void earctx_cmdc_int_mask(struct regmap *top_map) |
| { |
| mmio_write(top_map, EARCTX_CMDC_INT_MASK, |
| (0x0 << 17) | /* hpd_high_int */ |
| (0x0 << 16) | /* hpd_low_int */ |
| (0x1 << 15) | /* idle2_int */ |
| (0x1 << 14) | /* idle1_int */ |
| (0x1 << 13) | /* disc2_int */ |
| (0x1 << 12) | /* disc1_int */ |
| (0x1 << 11) | /* earc_int */ |
| (0x0 << 10) | /* hb_status_int */ |
| (0x1 << 9) | /* losthb_int */ |
| (0x1 << 8) | /* timeout_int */ |
| (0x1 << 7) | /* status_ch_int */ |
| (0x0 << 6) | /* int_recv_finished */ |
| (0x0 << 5) | /* int_recv_nack */ |
| (0x0 << 4) | /* int_recv_norsp */ |
| (0x0 << 3) | /* int_recv_unexp */ |
| (0x0 << 2) | /* int_recv_data */ |
| (0x0 << 1) | /* int_recv_ack */ |
| (0x0 << 0) /* int_recv_ecc_err */ |
| ); |
| } |
| |
| void earctx_enable_d2a(struct regmap *top_map, int enable) |
| { |
| mmio_update_bits(top_map, EARCTX_ANA_CTRL0, 0x1 << 31, enable << 31); |
| } |
| |
| void earctx_cmdc_init(struct regmap *top_map, bool en, bool rterm_on) |
| { |
| /* ana */ |
| if (rterm_on) |
| mmio_write(top_map, EARCTX_ANA_CTRL0, |
| en << 31 | /* earctx_en_d2a */ |
| 0x1 << 28 | /* earctx_cmdcrx_rcfilter_sel */ |
| 0x4 << 24 | /* earctx_cmdcrx_hystrim */ |
| 0x10 << 19 | /* earctx_idr_trim */ |
| 0x1 << 17 | /* earctx_rterm_on */ |
| 0x10 << 12 | /* earctx_rterm_trim */ |
| 0x4 << 8 | /* earctx_dmac_slew_con */ |
| 0x4 << 5 | /* earctx_cmdctx_ack_hystrim */ |
| 0x10 << 0 /* earctx_cmdctx_ack_reftrim */ |
| ); |
| else |
| mmio_write(top_map, EARCTX_ANA_CTRL0, |
| en << 31 | /* earctx_en_d2a */ |
| 0x1 << 28 | /* earctx_cmdcrx_rcfilter_sel */ |
| 0x4 << 24 | /* earctx_cmdcrx_hystrim */ |
| 0x8 << 20 | /* earctx_idr_trim */ |
| 0x10 << 12 | /* earctx_rterm_trim */ |
| 0x4 << 8 | /* earctx_dmac_slew_con */ |
| 0x4 << 5 | /* earctx_cmdctx_ack_hystrim */ |
| 0x10 << 0 /* earctx_cmdctx_ack_reftrim */ |
| ); |
| } |
| |
| void earctx_cmdc_set_timeout(struct regmap *cmdc_map, int no_timeout) |
| { |
| /* no timeout */ |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_VSM_CTRL5, |
| 0x3 << 0, |
| no_timeout << 1 |
| ); |
| } |
| |
| void earctx_cmdc_arc_connect(struct regmap *cmdc_map, bool init) |
| { |
| if (init) |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_VSM_CTRL0, |
| 0x7 << 25, |
| 0x1 << 27 | /* arc_initiated */ |
| 0x0 << 26 | /* arc_terminated */ |
| 0x1 << 25 /* arc_enable */ |
| ); |
| else |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_VSM_CTRL0, |
| 0x7 << 25, |
| 0x0 << 27 | /* arc_initiated */ |
| 0x1 << 26 | /* arc_terminated */ |
| 0x0 << 25 /* arc_enable */ |
| ); |
| } |
| |
| void earctx_cmdc_hpd_detect(struct regmap *top_map, |
| struct regmap *cmdc_map, |
| int earc_port, bool st) |
| { |
| /* select hdmirx_hpd */ |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_VSM_CTRL1, |
| 0x1 << 8, /* cntl_hpd_sel */ |
| 0x1 << 8); |
| |
| /* select hdmi_hpd mux */ |
| mmio_update_bits(top_map, EARCTX_TOP_CTRL0, |
| 0x1 << 11 | 0x3 << 8 | 0x3 << 4, |
| 0x1 << 11 | /* hdmi_hpd invent */ |
| earc_port << 8 | /* hdmi_hpd mux, port 0/1/2 */ |
| /* earctx_hd_hdp mux,3:register value 2:gpiow_5 1:gpiow_9 0:gpiow_1 */ |
| earc_port << 4 |
| ); |
| |
| if (st) { |
| /* reset for comma_cnt, timeout_sts */ |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_VSM_CTRL0, |
| 0x3 << 18, |
| 0x3 << 18 |
| ); |
| |
| /* reset and hpd sel */ |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_VSM_CTRL0, |
| 0x3f << 18, |
| 0x0 << 18 | |
| 0x3 << 20 | 0x3 << 22 |
| ); |
| |
| earctx_cmdc_set_timeout(cmdc_map, 0); |
| |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_VSM_CTRL1, |
| 0xff << 0, |
| 0x3 << 0 /* comma_cnt_th */ |
| ); |
| |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_VSM_CTRL4, |
| 0xfffff << 12, |
| 0x19 << 12 /* no heartbeat ack timing */ |
| ); |
| |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_BIPHASE_CTRL2, |
| 0xffff << 0, |
| 0x640 |
| ); |
| } else { |
| /* soft reset */ |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_TOP_CTRL1, |
| 0xf << 0, |
| 0xf << 0); |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_TOP_CTRL1, |
| 0xf << 0, |
| 0x0 << 0); |
| } |
| } |
| |
| void earctx_dmac_init(struct regmap *top_map, |
| struct regmap *dmac_map, |
| int earc_spdifout_lane_mask, |
| unsigned int chmask, |
| unsigned int swap_masks) |
| { |
| unsigned int lswap_masks, rswap_masks; |
| |
| mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL0, |
| 0x3 << 28, |
| 0x0 << 28); |
| mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL0, |
| 0x1 << 29, /* afifo out reset */ |
| 0x1 << 29); |
| mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL0, |
| 0x1 << 28 | /* afifo in reset */ |
| 0x1 << 26 | /* user Bit select */ |
| 0x1 << 24 | /* chdata select*/ |
| 0x1 << 20 | /* reg_data_sel, 1: data from 27bit */ |
| 0x1 << 19 | /* 0: lsb first */ |
| 0x1 << 18, /* biphase encode valid Bit value sel */ |
| 0x1 << 28 | |
| 0x1 << 26 | |
| 0x1 << 24 | |
| 0x1 << 20 | |
| 0x0 << 19 | |
| 0x1 << 18 |
| ); |
| |
| if (earc_spdifout_lane_mask == EARC_SPDIFOUT_LANE_MASK_V2) |
| mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL2, |
| 0xffff, /* lane mask */ |
| chmask); /* ODO: lane 0 now */ |
| else |
| mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL0, |
| 0xff << 4, /* lane mask */ |
| chmask << 4); /* ODO: lane 0 now */ |
| mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL0, |
| 0x1 << 23 | /* reg_bch_in_reverse */ |
| 0x1 << 21 | /* reg_bch_out_data_reverse */ |
| 0x1 << 16, /* reg_ubit_fifo_init_n */ |
| 0x1 << 23 | |
| 0x1 << 21 | |
| 0x1 << 16); |
| lswap_masks = swap_masks & 0xf; |
| rswap_masks = (swap_masks & 0xf0) >> 4; |
| if (lswap_masks > 7) |
| mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL0, |
| 0x1 << 14 | 0x7 << 4, |
| 0x1 << 14 | (lswap_masks - 8) << 4); |
| else |
| mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL0, |
| 0x1 << 14 | 0x7 << 4, |
| 0x0 << 14 | lswap_masks << 4); |
| if (rswap_masks > 7) |
| mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL0, |
| 0x1 << 15 | 0x7 << 8, |
| 0x1 << 15 | (rswap_masks - 8) << 8); |
| else |
| mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL0, |
| 0x1 << 15 | 0x7 << 8, |
| 0x0 << 15 | rswap_masks << 8); |
| |
| mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL4, |
| 0xf << 17, |
| 0x1 << 19 | /* userBit sel, 1: reg_value */ |
| 0x1 << 18 | /* validBit sel, 1: reg_value */ |
| 0x1 << 17 /* reg_chst_sel, 1: reg_value */ |
| ); |
| } |
| |
| void earctx_dmac_set_format(struct regmap *dmac_map, |
| int frddr_idx, int msb, int frddr_type) |
| { |
| mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL1, |
| 0x7 << 24 | /* frddr src */ |
| 0xff << 16 | /* waiting count after enabled */ |
| 0x1f << 8 | /* msb position */ |
| 0x7 << 4, /* frddr type */ |
| frddr_idx << 24 | |
| 0x40 << 16 | |
| msb << 8 | |
| frddr_type << 4); |
| |
| mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL4, |
| 0x1f << 25, |
| 0x1f << 25 /* msb */ |
| ); |
| |
| /* for raw data */ |
| mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL3, |
| 0x1f << 24, |
| 0x17 << 24 |
| ); |
| } |
| |
| static unsigned int earctx_get_cs_bits(struct regmap *dmac_map, |
| int cs_offset, int mask) |
| { |
| int reg_offset = cs_offset / REG_CS_LEN; |
| int bits_offset = cs_offset % REG_CS_LEN; |
| int reg, val, cs_a, cs_b; |
| |
| /* CHANNEL A STATUS */ |
| reg = EARCTX_SPDIFOUT_CHSTS0 + reg_offset; |
| val = mmio_read(dmac_map, reg); |
| cs_a = (val >> bits_offset) & mask; |
| |
| /* CHANNEL B STATUS */ |
| reg = EARCTX_SPDIFOUT_CHSTS6 + reg_offset; |
| val = mmio_read(dmac_map, reg); |
| cs_b = (val >> bits_offset) & mask; |
| |
| if (cs_a != cs_b) |
| pr_warn("use CHANNEL A STATUS as default.\n"); |
| |
| return cs_a; |
| } |
| |
| /* Note: mask without offset */ |
| static void earctx_update_cs_bits(struct regmap *dmac_map, |
| int cs_offset, int mask, int val) |
| { |
| int reg_offset = cs_offset / REG_CS_LEN; |
| int bits_offset = cs_offset % REG_CS_LEN; |
| int reg, orig_val; |
| |
| /* CHANNEL A STATUS */ |
| reg = EARCTX_SPDIFOUT_CHSTS0 + reg_offset; |
| orig_val = mmio_read(dmac_map, reg); |
| orig_val &= ~(mask << bits_offset); |
| orig_val |= (val & mask) << bits_offset; |
| mmio_write(dmac_map, reg, orig_val); |
| |
| /* CHANNEL B STATUS */ |
| reg = EARCTX_SPDIFOUT_CHSTS6 + reg_offset; |
| orig_val &= ~(mask << bits_offset); |
| orig_val |= (val & mask) << bits_offset; |
| mmio_write(dmac_map, reg, orig_val); |
| } |
| |
| int earctx_get_cs_iec958(struct regmap *dmac_map) |
| { |
| /* channel status A/B bits [31 - 0]*/ |
| return earctx_get_cs_bits(dmac_map, |
| 0x0, 0xffffffff); |
| } |
| |
| void earctx_set_cs_iec958(struct regmap *dmac_map, int cs) |
| { |
| /* channel status A/B bits [31 - 0]*/ |
| earctx_update_cs_bits(dmac_map, 0x0, 0xffffffff, cs); |
| } |
| |
| void earctx_set_cs_mute(struct regmap *dmac_map, bool mute) |
| { |
| earctx_update_cs_bits(dmac_map, |
| IEC_CS_MUTE_OFFSET, |
| IEC_CS_MUTE_MASK, |
| mute); |
| } |
| |
| static void earctx_set_cs_fmt(struct regmap *dmac_map, enum earc_audio_fmt fmt) |
| { |
| unsigned int offset, mask; |
| |
| if (fmt == EARC_FMT_LPCM || fmt == EARC_FMT_NONLPCM) { |
| offset = 0x1; |
| mask = 0x1; |
| } else if (fmt == EARC_FMT_OBA) { |
| int val; |
| |
| /* word length is not indicated for One Bit Audio */ |
| offset = IEC_CS_WLEN_OFFSET; |
| mask = IEC_CS_WLEN_MASK; |
| val = 0x0; |
| earctx_update_cs_bits(dmac_map, offset, mask, val); |
| |
| /* use case 0 0 0 1 1 for bit 0,1,3,4 and 5 */ |
| offset = 0x0; |
| mask = 0x3; |
| val = 0; |
| earctx_update_cs_bits(dmac_map, offset, mask, val); |
| offset = 0x3; |
| mask = 0x7; |
| fmt = 0x6; |
| } else { |
| pr_err("%s, Not support eARC audio format:%#x\n", |
| __func__, fmt); |
| return; |
| } |
| |
| earctx_update_cs_bits(dmac_map, offset, mask, fmt); |
| } |
| |
| static void earctx_set_cs_freq(struct regmap *dmac_map, unsigned int con_sf) |
| { |
| unsigned int offset, mask; |
| |
| offset = IEC_CS_SFREQ_OFFSET; |
| mask = IEC_CS_SFREQ_MASK; |
| earctx_update_cs_bits(dmac_map, offset, mask, con_sf); |
| } |
| |
| static void earctx_set_cs_category(struct regmap *dmac_map, int ctg_code) |
| { |
| unsigned int offset, mask; |
| |
| offset = IEC_CS_CATEGORY_OFFSET; |
| mask = IEC_CS_CATEGORY_MASK; |
| earctx_update_cs_bits(dmac_map, offset, mask, ctg_code); |
| } |
| |
| static void earctx_set_cs_multich(struct regmap *dmac_map, bool is_multich) |
| { |
| unsigned int offset, mask, val; |
| |
| /* Multi-channel L-PCM */ |
| offset = IEC_CS_EARC_MULTICH_OFFSET; |
| mask = IEC_CS_EARC_MULTICH_MASK; |
| if (is_multich) |
| val = 0x2; |
| else |
| val = 0x0; |
| |
| earctx_update_cs_bits(dmac_map, offset, mask, val); |
| } |
| |
| static void earctx_update_cs_layout(struct regmap *dmac_map, |
| enum audio_coding_types coding_type) |
| { |
| unsigned int offset, mask; |
| enum iec_audio_layout layout; |
| |
| switch (coding_type) { |
| case AUDIO_CODING_TYPE_AC3_LAYOUT_B: |
| layout = LOB_COMPRESS; |
| break; |
| case AUDIO_CODING_TYPE_AC3: |
| layout = LOA_COMPRESS; |
| break; |
| case AUDIO_CODING_TYPE_MULTICH_32CH_LPCM: |
| layout = LO32_LPCM; |
| break; |
| case AUDIO_CODING_TYPE_MULTICH_16CH_LPCM: |
| layout = LO16_LPCM; |
| break; |
| case AUDIO_CODING_TYPE_MULTICH_8CH_LPCM: |
| layout = LO8_LPCM; |
| break; |
| case AUDIO_CODING_TYPE_MULTICH_2CH_LPCM: |
| layout = LO2_LPCM; |
| break; |
| case AUDIO_CODING_TYPE_SACD_12CH: |
| layout = LO12_OBA; |
| break; |
| case AUDIO_CODING_TYPE_SACD_6CH: |
| layout = LO6_OBA; |
| break; |
| default: |
| layout = 0x0; |
| break; |
| } |
| |
| /* audio layout */ |
| offset = IEC_CS_AUDIO_LAYOUT_OFFSET; |
| mask = IEC_CS_AUDIO_LAYOUT_MASK; |
| earctx_update_cs_bits(dmac_map, offset, mask, layout); |
| } |
| |
| static unsigned int get_cs_ca(enum audio_coding_types coding_type) |
| { |
| unsigned int ca = 0; |
| |
| switch (coding_type) { |
| case AUDIO_CODING_TYPE_MULTICH_32CH_LPCM: |
| ca = AIF_32CH; |
| break; |
| case AUDIO_CODING_TYPE_MULTICH_16CH_LPCM: |
| ca = AIF_16CH; |
| break; |
| case AUDIO_CODING_TYPE_MULTICH_8CH_LPCM: |
| ca = AIF_8CH; |
| break; |
| case AUDIO_CODING_TYPE_MULTICH_2CH_LPCM: |
| ca = AIF_2CH; |
| break; |
| case AUDIO_CODING_TYPE_SACD_6CH: |
| case AUDIO_CODING_TYPE_SACD_12CH: |
| // TODO: for one bit audio |
| pr_warn("to Check Channel Allocation for One Bit Audio\n"); |
| break; |
| default: |
| ca = 0x0; /* clear the bits */ |
| break; |
| } |
| |
| return ca; |
| } |
| |
| void earctx_set_cs_ca(struct regmap *dmac_map, unsigned int ca) |
| { |
| unsigned int offset, mask; |
| |
| /* AIF databyte 4 for channel allocation */ |
| offset = IEC_CS_AIF_DB4_OFFSET; |
| mask = IEC_CS_AIF_DB4_MASK; |
| earctx_update_cs_bits(dmac_map, offset, mask, ca); |
| } |
| |
| void earctx_set_cs_info(struct regmap *dmac_map, |
| enum audio_coding_types coding_type, |
| struct iec_cnsmr_cs *cs_info, |
| unsigned int *lpcm_ca) |
| { |
| bool is_multich = false; |
| unsigned int ca; |
| |
| if (coding_type == AUDIO_CODING_TYPE_MULTICH_32CH_LPCM || |
| coding_type == AUDIO_CODING_TYPE_MULTICH_16CH_LPCM || |
| coding_type == AUDIO_CODING_TYPE_MULTICH_8CH_LPCM || |
| coding_type == AUDIO_CODING_TYPE_MULTICH_2CH_LPCM) { |
| is_multich = true; |
| |
| if (*lpcm_ca) { |
| ca = *lpcm_ca; |
| } else { |
| ca = get_cs_ca(coding_type); |
| *lpcm_ca = ca; |
| } |
| } else { |
| /* Default Channel Allocation */ |
| ca = get_cs_ca(coding_type); |
| } |
| |
| /* fmt */ |
| earctx_set_cs_fmt(dmac_map, cs_info->fmt); |
| |
| /* Multi Channels */ |
| earctx_set_cs_multich(dmac_map, is_multich); |
| /* category code */ |
| earctx_set_cs_category(dmac_map, cs_info->category_code); |
| /* sample frequency */ |
| earctx_set_cs_freq(dmac_map, cs_info->sampling_freq); |
| /* audio layout */ |
| earctx_update_cs_layout(dmac_map, coding_type); |
| /* channel alloacation */ |
| earctx_set_cs_ca(dmac_map, ca); |
| } |
| |
| enum cmdc_st earctx_cmdc_get_state(struct regmap *cmdc_map) |
| { |
| int val = mmio_read(cmdc_map, EARC_TX_CMDC_STATUS0); |
| enum cmdc_st state = (enum cmdc_st)(val & 0x7); |
| |
| return state; |
| } |
| |
| enum attend_type earctx_cmdc_get_attended_type(struct regmap *cmdc_map) |
| { |
| int val = mmio_read(cmdc_map, EARC_TX_CMDC_STATUS0); |
| enum cmdc_st state = (enum cmdc_st)(val & 0x7); |
| enum attend_type tx_type = ATNDTYP_DISCNCT; |
| |
| if ((val & (1 << 0x3)) && state == CMDC_ST_ARC) |
| tx_type = ATNDTYP_ARC; |
| else if ((val & (1 << 0x4)) && (state == CMDC_ST_EARC)) |
| tx_type = ATNDTYP_EARC; |
| |
| return tx_type; |
| } |
| |
| void earctx_cdmc_clr_irqs(struct regmap *top_map, int clr) |
| { |
| mmio_write(top_map, EARCTX_CMDC_INT_PENDING, clr); |
| } |
| |
| int earctx_cdmc_get_irqs(struct regmap *top_map) |
| { |
| return mmio_read(top_map, EARCTX_CMDC_INT_PENDING); |
| } |
| |
| void earctx_dmac_clr_irqs(struct regmap *top_map, int clr) |
| { |
| mmio_write(top_map, EARCTX_DMAC_INT_PENDING, clr); |
| } |
| |
| int earctx_dmac_get_irqs(struct regmap *top_map) |
| { |
| return mmio_read(top_map, EARCTX_DMAC_INT_PENDING); |
| } |
| |
| void earctx_compressed_enable(struct regmap *dmac_map, |
| enum attend_type type, |
| enum audio_coding_types coding_type, |
| bool enable) |
| { |
| /* |
| * bch generate must be disabled if type is ARC |
| * otherwise there is no sound from ARC |
| */ |
| if (type == ATNDTYP_ARC) |
| mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL3, |
| BIT(29), |
| 0x0); |
| |
| if (type != ATNDTYP_EARC) |
| return; |
| |
| if (audio_coding_is_non_lpcm(coding_type)) { |
| mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL3, |
| 0x1 << 29, |
| enable << 29); |
| |
| mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL4, |
| 0x1 << 22, |
| enable << 22 /* valid Bit value */ |
| ); |
| |
| } else { |
| mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL3, |
| 0x1 << 29, |
| 0x0 << 29); |
| |
| mmio_update_bits(dmac_map, EARCTX_ERR_CORRT_CTRL4, |
| 0x1 << 22, |
| 0x0 << 22 /* valid Bit value */ |
| ); |
| } |
| |
| mmio_update_bits(dmac_map, EARCTX_FE_CTRL0, |
| 0x1 << 30, |
| enable << 30); |
| } |
| |
| bool get_earctx_enable(struct regmap *cmdc_map, struct regmap *dmac_map) |
| { |
| enum attend_type type = earctx_cmdc_get_attended_type(cmdc_map); |
| |
| if (type == ATNDTYP_DISCNCT) |
| return false; |
| |
| if (mmio_read(dmac_map, EARCTX_SPDIFOUT_CTRL0) & 0x1 << 28) |
| return true; |
| |
| return false; |
| } |
| |
| void earctx_enable(struct regmap *top_map, |
| struct regmap *cmdc_map, |
| struct regmap *dmac_map, |
| enum audio_coding_types coding_type, |
| bool enable, |
| bool rterm_on) |
| { |
| enum attend_type type = earctx_cmdc_get_attended_type(cmdc_map); |
| |
| if (type == ATNDTYP_DISCNCT) |
| return; |
| |
| if (enable) { |
| int offset, mask, val; |
| |
| if (rterm_on) { |
| offset = 19; |
| mask = 0x1f; |
| val = 0x10; |
| } else { |
| offset = 20; |
| mask = 0xf; |
| val = 0x8; |
| } |
| if (type == ATNDTYP_ARC) { |
| mmio_update_bits(top_map, |
| EARCTX_ANA_CTRL0, |
| mask << offset, |
| (val + 1) << offset); |
| } else if (type == ATNDTYP_EARC) { |
| mmio_update_bits(top_map, |
| EARCTX_ANA_CTRL0, |
| mask << offset, |
| val << offset); |
| } |
| |
| mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL0, |
| 0x1 << 29, /* afifo out reset */ |
| 0x1 << 29); |
| mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL0, |
| 0x1 << 28, /* afifo in reset */ |
| 0x1 << 28); |
| } else { |
| mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL0, |
| 0x1 << 30, /* biphase work clear */ |
| 0x1 << 30); |
| |
| mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL0, |
| 0x3 << 28, |
| 0x0 << 28); |
| } |
| |
| mmio_update_bits(dmac_map, EARCTX_SPDIFOUT_CTRL0, |
| 0x1 << 31, |
| enable << 31); |
| |
| mmio_update_bits(dmac_map, EARC_RX_CMDC_BIPHASE_CTRL1, |
| 0x1 << 30, |
| enable << 30); |
| |
| if (enable) |
| mmio_write(top_map, EARCTX_DMAC_INT_MASK, |
| (0x1 << 4) | /* fe_modulation c_hold_clr */ |
| (0x1 << 3) | /* fe_modulation c_hold_start */ |
| (0x1 << 2) | /* err_correct c_fifo_thd_less_pass */ |
| (0x1 << 1) | /* err_correct r_fifo_overflow_set */ |
| (0x1 << 0) /* err_correct c_fifo_empty_set */ |
| ); |
| else |
| mmio_write(top_map, EARCTX_DMAC_INT_MASK, |
| 0x0 |
| ); |
| |
| earctx_compressed_enable(dmac_map, |
| type, |
| coding_type, |
| enable); |
| } |
| |
| static void earcrx_cmdc_get_reg(struct regmap *cmdc_map, int dev_id, int offset, |
| u8 *data, int bytes) |
| { |
| int i; |
| |
| mmio_update_bits(cmdc_map, EARC_RX_CMDC_DEVICE_ID_CTRL, |
| 0x1 << 31 | /* apb_write */ |
| 0x1 << 30 | /* apb_read */ |
| 0x1 << 29 | /* apb_w_r_done */ |
| 0xff << 8 | /* apb_rwid */ |
| 0xff << 0, /* apbrw_start_addr */ |
| 0x0 << 31 | |
| 0x1 << 30 | |
| 0x0 << 29 | |
| dev_id << 8 | |
| offset << 0); |
| |
| for (i = 0; i < bytes; i++) |
| data[i] = mmio_read(cmdc_map, EARC_RX_CMDC_DEVICE_RDATA); |
| |
| mmio_update_bits(cmdc_map, EARC_RX_CMDC_DEVICE_ID_CTRL, |
| 0x1 << 29, 0x1 << 29); |
| mmio_update_bits(cmdc_map, EARC_RX_CMDC_DEVICE_ID_CTRL, |
| 0x1 << 29, 0x0 << 29); |
| } |
| |
| static void earcrx_cmdc_set_reg(struct regmap *cmdc_map, int dev_id, int offset, |
| u8 *data, int bytes) |
| { |
| int i; |
| |
| mmio_update_bits(cmdc_map, EARC_RX_CMDC_DEVICE_ID_CTRL, |
| 0x1 << 31 | /* apb_write */ |
| 0x1 << 30 | /* apb_read */ |
| 0x1 << 29 | /* apb_w_r_done */ |
| 0xff << 8 | /* apb_rwid */ |
| 0xff << 0, /* apbrw_start_addr */ |
| 0x1 << 31 | |
| 0x0 << 30 | |
| 0x0 << 29 | |
| dev_id << 8 | |
| offset << 0); |
| |
| for (i = 0; i < bytes; i++) |
| mmio_write(cmdc_map, EARC_RX_CMDC_DEVICE_WDATA, data[i]); |
| |
| mmio_update_bits(cmdc_map, EARC_RX_CMDC_DEVICE_ID_CTRL, |
| 0x1 << 29, 0x1 << 29); |
| mmio_update_bits(cmdc_map, EARC_RX_CMDC_DEVICE_ID_CTRL, |
| 0x1 << 29, 0x0 << 29); |
| } |
| |
| /* Latency */ |
| void earcrx_cmdc_get_latency(struct regmap *cmdc_map, u8 *latency) |
| { |
| earcrx_cmdc_get_reg(cmdc_map, |
| STAT_CTRL_DEV_ID, |
| ERX_LATENCY_REG, |
| latency, |
| 1); |
| } |
| |
| void earcrx_cmdc_set_latency(struct regmap *cmdc_map, u8 *latency) |
| { |
| u8 stat = (0x1 << STAT_CHNG) | earcrx_cmdc_get_rx_stat_bits(cmdc_map); |
| |
| earcrx_cmdc_set_reg(cmdc_map, |
| STAT_CTRL_DEV_ID, |
| ERX_LATENCY_REG, |
| latency, |
| 1); |
| |
| /* set STAT_CHNG to Notify eARC TX */ |
| earcrx_cmdc_set_reg(cmdc_map, |
| STAT_CTRL_DEV_ID, |
| EARCRX_STAT_REG, |
| &stat, |
| 0x1); |
| } |
| |
| void earcrx_cmdc_get_cds(struct regmap *cmdc_map, u8 *cds) |
| { |
| earcrx_cmdc_get_reg(cmdc_map, |
| CAP_DEV_ID, |
| 0x0, |
| cds, |
| CDS_MAX_BYTES); |
| } |
| |
| void earcrx_cmdc_set_cds(struct regmap *cmdc_map, u8 *cds) |
| { |
| u8 cap_chng = 0x1 << CAP_CHNG | |
| 0x1 << EARC_HPD | |
| earcrx_cmdc_get_rx_stat_bits(cmdc_map); |
| |
| earcrx_cmdc_set_reg(cmdc_map, |
| CAP_DEV_ID, |
| 0x0, |
| cds, |
| CDS_MAX_BYTES); |
| |
| /* set CAP_CHNG and EARC_HPD to Notify eARC TX to re-read CDS */ |
| earcrx_cmdc_set_reg(cmdc_map, |
| STAT_CTRL_DEV_ID, |
| EARCRX_STAT_REG, |
| &cap_chng, |
| 0x1); |
| } |
| |
| static int earctx_cmdc_get_reg(struct regmap *cmdc_map, int dev_id, int offset, |
| u8 *data, int bytes) |
| { |
| int val = 0, i; |
| int ret = -1; |
| |
| mmio_update_bits(cmdc_map, EARC_TX_CMDC_MASTER_CTRL, |
| 0x1 << 31 | /* master_cmd_rw, read */ |
| 0x1 << 30 | /* master_hb_ignore */ |
| 0xf << 24 | /* hb_cmd_val_th */ |
| 0xff << 16 | /* master_cmd_count */ |
| 0xff << 8 | /* master_cmd_id */ |
| 0xff << 0, /* master_cmd_address */ |
| 0x0 << 31 | |
| 0x1 << 30 | |
| 0x4 << 24 | |
| (bytes - 1) << 16 | |
| dev_id << 8 | |
| offset << 0); |
| |
| /* wait read from rx done */ |
| do { |
| usleep_range(500, 1500); |
| val = mmio_read(cmdc_map, EARC_TX_CMDC_MASTER_CTRL); |
| } while (!(val & (1 << 29))); |
| |
| mmio_update_bits(cmdc_map, EARC_TX_CMDC_DEVICE_ID_CTRL, |
| 0x1 << 31 | /* apb_write */ |
| 0x1 << 30 | /* apb_read */ |
| 0x1 << 29 | /* apb_rw_done */ |
| 0x1 << 16 | /* hpb_rst_enable */ |
| 0xff << 8 | /* apb_rwid */ |
| 0xff << 0, /* apbrw_start_addr */ |
| 0x0 << 31 | |
| 0x1 << 30 | |
| 0x0 << 29 | |
| 0x1 << 16 | |
| dev_id << 8 | |
| offset << 0); |
| |
| for (i = 0; i < bytes; i++) |
| data[i] = mmio_read(cmdc_map, EARC_TX_CMDC_DEVICE_RDATA); |
| |
| mmio_update_bits(cmdc_map, EARC_TX_CMDC_DEVICE_ID_CTRL, |
| 0x1 << 29, 0x1 << 29); |
| mmio_update_bits(cmdc_map, EARC_TX_CMDC_DEVICE_ID_CTRL, |
| 0x1 << 29, 0x0 << 29); |
| |
| if (val & (1 << 29)) |
| ret = 0; |
| |
| return ret; |
| } |
| |
| static int earctx_cmdc_set_reg(struct regmap *cmdc_map, int dev_id, int offset, |
| u8 *data, int bytes) |
| { |
| int val = 0, i; |
| int ret = -1; |
| |
| mmio_update_bits(cmdc_map, EARC_TX_CMDC_DEVICE_ID_CTRL, |
| 0x1 << 31 | /* apb_write */ |
| 0x1 << 30 | /* apb_read */ |
| 0x1 << 29 | /* apb_rw_done */ |
| 0x1 << 16 | /* hpb_rst_enable */ |
| 0xff << 8 | /* apb_rwid */ |
| 0xff << 0, /* apbrw_start_addr */ |
| 0x1 << 31 | |
| 0x0 << 30 | |
| 0x0 << 29 | |
| 0x1 << 16 | |
| dev_id << 8 | |
| offset << 0); |
| |
| for (i = 0; i < bytes; i++) |
| mmio_update_bits(cmdc_map, EARC_TX_CMDC_DEVICE_WDATA, |
| 0xff << 0, |
| data[i] << 0); |
| |
| mmio_update_bits(cmdc_map, EARC_TX_CMDC_MASTER_CTRL, |
| 0x1 << 31 | /* master_cmd_rw, write */ |
| 0x1 << 30 | /* master_hb_ignore */ |
| 0xf << 24 | /* hb_cmd_cal_th */ |
| 0xff << 16 | /* master_cmd_count */ |
| 0xff << 8 | /* master_cmd_id */ |
| 0xff << 0, /* master_cmd_address */ |
| 0x1 << 31 | |
| 0x1 << 30 | |
| 4 << 24 | |
| (bytes - 1) << 16 | |
| dev_id << 8 | |
| offset << 0); |
| |
| /* wait write done */ |
| do { |
| usleep_range(500, 1500); |
| val = mmio_read(cmdc_map, EARC_TX_CMDC_MASTER_CTRL); |
| } while (!(val & (1 << 29))); |
| |
| mmio_update_bits(cmdc_map, EARC_TX_CMDC_DEVICE_ID_CTRL, |
| 0x1 << 29, 0x1 << 29); |
| mmio_update_bits(cmdc_map, EARC_TX_CMDC_DEVICE_ID_CTRL, |
| 0x1 << 29, 0x0 << 29); |
| |
| if (val & (1 << 29)) |
| ret = 0; |
| |
| return ret; |
| } |
| |
| int earctx_cmdc_get_stat_bits(struct regmap *cmdc_map) |
| { |
| u8 stat_bits; |
| |
| earctx_cmdc_get_reg(cmdc_map, |
| STAT_CTRL_DEV_ID, |
| EARCTX_STAT_REG, |
| &stat_bits, |
| 1); |
| |
| return (int)stat_bits; |
| } |
| |
| void earctx_cmdc_clr_stat_bits(struct regmap *cmdc_map, int stat_bits) |
| { |
| u8 clr_bits, reg_data = 0; |
| |
| earctx_cmdc_get_reg(cmdc_map, |
| STAT_CTRL_DEV_ID, |
| EARCTX_STAT_REG, |
| ®_data, |
| 1); |
| |
| clr_bits = reg_data & (~stat_bits); |
| |
| earctx_cmdc_set_reg(cmdc_map, |
| STAT_CTRL_DEV_ID, |
| EARCTX_STAT_REG, |
| &clr_bits, |
| 1); |
| } |
| |
| void earctx_cmdc_set_hdmi_hpd_bit(struct regmap *cmdc_map, bool is_high) |
| { |
| u8 hpd_bits; |
| |
| if (is_high) |
| hpd_bits = 0x1 << HDMI_HPD; |
| else |
| hpd_bits = 0x0 << HDMI_HPD; |
| |
| earctx_cmdc_set_reg(cmdc_map, |
| STAT_CTRL_DEV_ID, |
| EARCTX_STAT_REG, |
| &hpd_bits, |
| 1); |
| } |
| |
| void earctx_cmdc_set_hb_valid_bit(struct regmap *cmdc_map, bool hb_valid) |
| { |
| u8 valid; |
| |
| if (hb_valid) |
| valid = 0x1 << EARC_VALID; |
| else |
| valid = 0x0 << EARC_VALID; |
| |
| earctx_cmdc_set_reg(cmdc_map, |
| STAT_CTRL_DEV_ID, |
| EARCTX_STAT_REG, |
| &valid, |
| 1); |
| } |
| |
| /* Latency */ |
| void earctx_cmdc_get_latency(struct regmap *cmdc_map, u8 *latency) |
| { |
| earctx_cmdc_get_reg(cmdc_map, |
| STAT_CTRL_DEV_ID, |
| ERX_LATENCY_REG, |
| latency, |
| 1); |
| } |
| |
| void earctx_cmdc_set_latency(struct regmap *cmdc_map, u8 *latency) |
| { |
| earctx_cmdc_set_reg(cmdc_map, |
| STAT_CTRL_DEV_ID, |
| ERX_LATENCY_REQ_REG, |
| latency, |
| 1); |
| } |
| |
| /* Capability Data Structure, fetch CDS from RX */ |
| void earctx_cmdc_get_cds(struct regmap *cmdc_map, u8 *cds) |
| { |
| earctx_cmdc_get_reg(cmdc_map, |
| CAP_DEV_ID, |
| 0x0, |
| cds, |
| CDS_MAX_BYTES); |
| } |
| |
| /* eARC RX analog auto calibration */ |
| void earcrx_ana_auto_cal(struct regmap *top_map) |
| { |
| int stat0 = 0; |
| |
| mmio_update_bits(top_map, |
| EARCRX_ANA_CTRL1, |
| 0x3 << 30, /* earcrx_rterm_cal_rstn & enable */ |
| 0x3 << 30); |
| |
| do { |
| usleep_range(10, 30); |
| stat0 = mmio_read(top_map, EARCRX_ANA_STAT0); |
| } while (!(stat0 & (1 << 31))); |
| |
| mmio_update_bits(top_map, |
| EARCRX_ANA_CTRL0, |
| 0x1f << 15, |
| (stat0 & 0x1f) << 15); |
| } |
| |
| /* eARC RX analog auto calibration */ |
| void earctx_ana_auto_cal(struct regmap *top_map) |
| { |
| int stat0 = 0; |
| |
| mmio_update_bits(top_map, |
| EARCTX_ANA_CTRL1, |
| 0x3 << 30, /* earctx_rterm_cal_rstn & enable */ |
| 0x3 << 30); |
| |
| do { |
| usleep_range(10, 30); |
| stat0 = mmio_read(top_map, EARCTX_ANA_STAT0); |
| } while (!(stat0 & (1 << 31))); |
| |
| mmio_update_bits(top_map, |
| EARCTX_ANA_CTRL0, |
| 0x1f << 12, |
| (stat0 & 0x1f) << 12); |
| } |
| |
| bool earxrx_get_pll_valid(struct regmap *top_map) |
| { |
| int stat0 = 0; |
| unsigned int value = 0; |
| |
| value = mmio_read(top_map, EARCRX_PLL_STAT0); |
| |
| stat0 = (value & 0x80000000) >> 31; |
| |
| return stat0; |
| } |
| |
| bool earxrx_get_pll_valid_auto(struct regmap *top_map) |
| { |
| int stat0 = 0; |
| unsigned int value = 0; |
| |
| value = mmio_read(top_map, EARCRX_PLL_STAT0); |
| |
| stat0 = (value & 0x40000000) >> 30; |
| |
| return stat0; |
| } |
| |
| u8 earcrx_cmdc_get_rx_stat_bits(struct regmap *cmdc_map) |
| { |
| u8 stat_bits; |
| |
| earcrx_cmdc_get_reg(cmdc_map, |
| STAT_CTRL_DEV_ID, |
| EARCRX_STAT_REG, |
| &stat_bits, |
| 1); |
| return stat_bits; |
| } |
| |
| void earctx_cmdc_earc_mode(struct regmap *cmdc_map, bool enable) |
| { |
| if (enable) { |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_VSM_CTRL0, |
| 0xf << 28 | 0x3 << 8, |
| 0x0); |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_VSM_CTRL0, |
| 0x1 << 26, |
| 0x1 << 26); |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_VSM_CTRL0, |
| 0x1 << 26, |
| 0x0); |
| } else { |
| mmio_update_bits(cmdc_map, |
| EARC_TX_CMDC_VSM_CTRL0, |
| 0xf << 28 | 0x3 << 8, |
| 0xe << 28 | 0x3 << 8); |
| } |
| } |