// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2024 Rockchip Electronics Co., Ltd. * Author: Jason Zhang */ #include #include #include "it6621.h" #include "it6621-clk.h" #include "it6621-earc.h" #include "it6621-reg-bank0.h" #include "it6621-reg-bank1.h" #include "it6621-reg-cec.h" #include "it6621-uapi.h" int it6621_set_channel_status(struct it6621_priv *priv) { unsigned int layout = 0; unsigned int ca = 0; unsigned int fmt = 0; unsigned int wl = 0; unsigned int fs = 0; /* NOTE: Add for Category code */ regmap_update_bits(priv->regmap, IT6621_REG_TX_CH_ST1, 0xff, IEC958_AES1_CON_PCM_CODER); /* Refer to HDMI2.1 spec table 9-23 and ICE60958-3 p9 */ if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && (priv->audio_ch == 2) && (priv->audio_enc == 0) && (priv->mch_lpcm_enabled == IT6621_TX_MCH_LPCM_DIS) && (priv->i2s_nlpcm_enabled == IT6621_TX_NLPCM_I2S_DIS)) fmt = HDMI_AUDIO_FMT_UN_2CH_LPCM; else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && (priv->audio_ch == 2) && (priv->audio_enc == 0) && (priv->mch_lpcm_enabled == IT6621_TX_MCH_LPCM_EN)) fmt = HDMI_AUDIO_FMT_UN_MCH_LPCM; else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && (priv->audio_ch > 2) && (priv->audio_enc == 0)) fmt = HDMI_AUDIO_FMT_UN_MCH_LPCM; else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) && (priv->audio_enc == 0)) fmt = HDMI_AUDIO_FMT_UN_XCH_DSD; else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && (priv->audio_enc == 0)) fmt = HDMI_AUDIO_FMT_UN_2CH_NLPCM; else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && (priv->audio_enc == 1)) fmt = HDMI_AUDIO_FMT_EN_2CH_NLPCM; else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && (priv->audio_enc == 1)) fmt = HDMI_AUDIO_FMT_EN_MCH_NLPCM; else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) && (priv->audio_enc == 1)) fmt = HDMI_AUDIO_FMT_EN_XCH_DSD; else dev_err(priv->dev, "invalid audio format\n"); /* * NOTE: Software for which copyright is asserted, Channel status mode * is set to mode 0, and audio format is set with fmt. */ regmap_write(priv->regmap, IT6621_REG_TX_CH_ST0, ((fmt & 0x1c) << 1) | (fmt & 0x03)); /* Refer to IEC60958-3 p12 */ if (priv->audio_src == IT6621_AUD_SRC_DSD) wl = IEC958_AES4_CON_WORDLEN_NOTID; else if (priv->audio_type == IT6621_AUD_TYPE_NLPCM) wl = IEC958_AES4_CON_WORDLEN_20_16; else wl = priv->i2s_wl; /* NOTE: Set sample word length */ regmap_update_bits(priv->regmap, IT6621_REG_TX_CH_ST4, 0x0f, wl); /* Refer to HDMI2.1 spec table 9-25 and IEC60958-3 p12 */ if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && (priv->audio_ch <= 2)) layout = HDMI_AUDIO_LAYOUT_LPCM_2CH; else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && (priv->audio_ch <= 8)) layout = HDMI_AUDIO_LAYOUT_LPCM_8CH; else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) && (priv->audio_ch <= 16)) layout = HDMI_AUDIO_LAYOUT_LPCM_16CH; else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && (priv->audio_ch <= 2)) layout = HDMI_AUDIO_LAYOUT_NLPCM_2CH; else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) && (priv->audio_ch <= 8)) layout = HDMI_AUDIO_LAYOUT_NLPCM_8CH; else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) && (priv->audio_ch <= 6)) layout = HDMI_AUDIO_LAYOUT_DSD_6CH; else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) && (priv->audio_ch <= 12)) layout = HDMI_AUDIO_LAYOUT_DSD_12CH; else dev_err(priv->dev, "invalid layout\n"); regmap_write(priv->regmap, IT6621_REG_TX_CH_ST5, layout << 4); /* Refer to HDMI2.0 spec, IEC60958-3 p11 and p12 */ if ((layout == HDMI_AUDIO_LAYOUT_LPCM_2CH) || (layout == HDMI_AUDIO_LAYOUT_NLPCM_2CH)) { fs = priv->audio_fs; } else if ((layout == HDMI_AUDIO_LAYOUT_LPCM_8CH) || (layout == HDMI_AUDIO_LAYOUT_NLPCM_8CH)) { if (priv->audio_fs == IEC958_AES3_CON_FS_32000) fs = IT6621_AES3_CON_FS_128000; else if (priv->audio_fs == IEC958_AES3_CON_FS_44100) fs = IEC958_AES3_CON_FS_176400; else if (priv->audio_fs == IEC958_AES3_CON_FS_48000) fs = IEC958_AES3_CON_FS_192000; else if (priv->audio_fs == IT6621_AES3_CON_FS_64000) fs = IT6621_AES3_CON_FS_256000; else if (priv->audio_fs == IEC958_AES3_CON_FS_88200) fs = IT6621_AES3_CON_FS_352000; else if (priv->audio_fs == IEC958_AES3_CON_FS_96000) fs = IT6621_AES3_CON_FS_384000; else if (priv->audio_fs == IT6621_AES3_CON_FS_128000) fs = IT6621_AES3_CON_FS_512000; else if (priv->audio_fs == IEC958_AES3_CON_FS_176400) fs = IT6621_AES3_CON_FS_705000; else if (priv->audio_fs == IEC958_AES3_CON_FS_192000) fs = IEC958_AES3_CON_FS_768000; else dev_err(priv->dev, "invalid fs and channel\n"); } else if ((layout == HDMI_AUDIO_LAYOUT_LPCM_16CH) || (layout == HDMI_AUDIO_LAYOUT_DSD_6CH)) { if (priv->audio_fs == IEC958_AES3_CON_FS_32000) fs = IT6621_AES3_CON_FS_256000; else if (priv->audio_fs == IEC958_AES3_CON_FS_44100) fs = IT6621_AES3_CON_FS_352000; else if (priv->audio_fs == IEC958_AES3_CON_FS_48000) fs = IT6621_AES3_CON_FS_384000; else if (priv->audio_fs == IT6621_AES3_CON_FS_64000) fs = IT6621_AES3_CON_FS_512000; else if (priv->audio_fs == IEC958_AES3_CON_FS_88200) fs = IT6621_AES3_CON_FS_705000; else if (priv->audio_fs == IEC958_AES3_CON_FS_96000) fs = IEC958_AES3_CON_FS_768000; else dev_err(priv->dev, "invalid fs and channel\n"); } else if (layout == HDMI_AUDIO_LAYOUT_DSD_12CH) { if (priv->audio_fs == IEC958_AES3_CON_FS_32000) fs = IT6621_AES3_CON_FS_512000; else if (priv->audio_fs == IEC958_AES3_CON_FS_44100) fs = IT6621_AES3_CON_FS_705000; else if (priv->audio_fs == IEC958_AES3_CON_FS_48000) fs = IEC958_AES3_CON_FS_768000; else dev_err(priv->dev, "invalid fs and channel\n"); } regmap_write(priv->regmap, IT6621_REG_TX_CH_ST3, ((fs & 0x30) << 2) + (fs & 0x0f)); /* Refer to HDMI2.1 spec table 9-28 and CTA861-G table 28~30 */ /* Audio InfoFrame */ if (priv->audio_ch > 8) { #ifdef _1QD980ATC_ // for 5-1-60 ca = 0x00; #else /* * CTA-861-G spec. Section 6.6.3: Delivery According to the * Speaker Mask (Byte 4 = 0xFE). */ ca = 0xfe; #endif } else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) || (priv->mch_lpcm_enabled == IT6621_TX_MCH_LPCM_EN) || (priv->layout_2ch_enabled == IT6621_TX_2CH_LAYOUT_EN)) { ca = 0x00; } else { /* * CTA-861-G spec. Table 35 Audio InfoFrame Data Byte 4. * 0x00: FR/FL * 0x01: FR/FL/LFE1 * 0x03: FR/FL/LFE1/FC * 0x07: FR/FL/LFE1/FC/BC * 0x0B: FR/FL/LFE1/FC/LS/RS * 0x0F: FR/FL/LFE1/FC/LS/RS/BC * 0x13: FR/FL/LFE1/FC/LS/RS/RLC/RRC * 0xff: Channels delivered according to Channel Index */ switch (priv->audio_ch) { case 0: ca = 0xff; break; // no audio case 2: ca = 0x00; break; case 3: ca = 0x01; break; // 0x01,0x02,0x04 case 4: ca = 0x03; break; // 0x03,0x05,0x06,0x08,0x14 case 5: ca = 0x07; break; // 0x07,0x09,0x0A,0x0C,0x15,0x16,0x18 case 6: ca = 0x0B; break; // 0x0B,0x0D,0x0E,0x10,0x17,0x19,0x1A,0x1C case 7: ca = 0x0f; break; // 0x0F,0x11,0x12,0x1B,0x1D,0x1E case 8: ca = 0x13; break; // 0x13,0x1F default: break; } } /* For allocation test 5-1-34, can't use on normal LPCM test */ if (priv->force_ca & 0x80) { switch (priv->force_ca) { case 0x80: ca = 0x00; break; // 2ch case 0x81: ca = 0x01; break; // 4ch case 0x82: ca = 0x0B; break; // 6ch case 0x83: ca = 0x13; break; // 8ch default: break; } /* Clear for test */ priv->force_ca = 0; } /* NOTE: Set channel allocation. */ regmap_write(priv->regmap, IT6621_REG_TX_CH_ST9, ca); /* * NOTE: DM_INH = 0, permitted or no information about any assertion * of the down mixed stereo output. * * LSV3 = 0, LSV2 = 0, LSV1 = 0, LSV1 = 0, Level Shift Value is 0dB. * * LFEPBL1 = 0, LFEPBL0 = 0, unknown or refer to other information for * LFE playback level comparing with other channel signal. */ regmap_write(priv->regmap, IT6621_REG_TX_CH_ST10, 0x00); if (priv->audio_ch > 8) { /* * CTA-861-G spec. Table 29: Audio InfoFrame Format When Byte 4 * is 0xFE. * * Byte 6: FLW/ RLC/ FLC/ BC BL/ FC LFE1 FL/ * FRW RRC FRC BR FR * Byte 7: TpSiL/ SiL/ TpBC LFE2 LS/ TpFC TpC TpFL/ * TpSiR SiR RS TpFR * Byte 8: F87=0 F86=0 F85=0 F84=0 TpLS/ BtFL/ BtFC TpBL/ * TpRS BtFR TpBR */ /* Set HDMI2.1 channel status */ regmap_write(priv->regmap, IT6621_REG_TX_CH_ST11, 0x6f); regmap_write(priv->regmap, IT6621_REG_TX_CH_ST12, 0x0f); regmap_write(priv->regmap, IT6621_REG_TX_CH_ST13, 0x0c); } else { /* Reserved in CTA-861-G spec when Byte 4 is less than 0x32. */ regmap_write(priv->regmap, IT6621_REG_TX_CH_ST11, 0x00); regmap_write(priv->regmap, IT6621_REG_TX_CH_ST12, 0x00); regmap_write(priv->regmap, IT6621_REG_TX_CH_ST13, 0x00); } /* Reserved in CTA-861-G spec. */ regmap_write(priv->regmap, IT6621_REG_TX_CH_ST14, 0x00); regmap_write(priv->regmap, IT6621_REG_TX_CH_ST15, 0x00); return 0; } int it6621_set_arc_enabled(struct it6621_priv *priv, bool enabled) { priv->arc_enabled = enabled ? IT6621_TX_ARC_EN : IT6621_TX_ARC_DIS; regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, IT6621_TX_ARC_SEL, priv->arc_enabled); return 0; } int it6621_set_earc_enabled(struct it6621_priv *priv, bool enabled) { priv->earc_enabled = enabled ? IT6621_TX_EARC_EN : IT6621_TX_EARC_DIS; regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, IT6621_TX_EARC_SEL, priv->earc_enabled); return 0; } int it6621_set_enter_arc(struct it6621_priv *priv, bool enabled) { unsigned int state; if (enabled) { regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, IT6621_TX_ARC_NOW_SEL, IT6621_TX_ARC_NOW_EN); it6621_get_ddfsm_state(priv, &state); if (state != IT6621_TX_ARC_MODE) { dev_err(priv->dev, "not in ARC mode\n"); return -EAGAIN; } /* NOTE: ARC only support SPDIF */ regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_SRC_SEL, IT6621_TX_AUD_SRC, IT6621_AUD_SRC_SPDIF); /* Common mode ARC */ regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, IT6621_TX_IN_ARC_MODE_SEL, IT6621_TX_IN_ARC_COMMON_MODE); regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, IT6621_TX_DRV_CSW_SEL, IT6621_TX_DRV_CSW_7); dev_dbg(priv->dev, "ARC now enabled\n"); } else { regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, IT6621_TX_ARC_NOW_SEL, IT6621_TX_ARC_NOW_DIS); /* Signal mode ARC */ regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, IT6621_TX_IN_ARC_MODE_SEL, IT6621_TX_IN_ARC_SIGNAL_MODE); regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, IT6621_TX_DRV_CSW_SEL, IT6621_TX_DRV_CSW_4); dev_dbg(priv->dev, "ARC now disabled\n"); } return 0; } static int it6621_toggle_real_hpd(struct it6621_priv *priv) { /* toggle real HPD at least 100ms */ /* Set HPDB low */ regmap_update_bits(priv->regmap, IT6621_REG_SYS_CTRL1, IT6621_TX_FORCE_HPDB_LOW_SEL, IT6621_TX_FORCE_HPDB_LOW_EN); msleep(120); /* Set HPDB high */ regmap_update_bits(priv->regmap, IT6621_REG_SYS_CTRL1, IT6621_TX_FORCE_HPDB_LOW_SEL, IT6621_TX_FORCE_HPDB_LOW_DIS); return 0; } static int it6621_set_auto_mode(struct it6621_priv *priv) { /* auto mode , eARC auto detect */ regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3, IT6621_TX_FORCE_ARC_MODE_SEL, IT6621_TX_FORCE_ARC_MODE_DIS); it6621_set_enter_arc(priv, false); return it6621_toggle_real_hpd(priv); } static int it6621_force_arc_mode(struct it6621_priv *priv) { /* * Force ARC mode , close eARC mode. * Please recover to this HDMI RX's original EDID. */ regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3, IT6621_TX_FORCE_ARC_MODE_SEL, IT6621_TX_FORCE_ARC_MODE_EN); return it6621_toggle_real_hpd(priv); } int it6621_get_ddfsm_state(struct it6621_priv *priv, unsigned int *state) { int ret; ret = regmap_read(priv->regmap, IT6621_REG_TX_DD2, state); *state &= IT6621_TX_DD_FSM_STATE; return ret; } static int it6621_wait_cmdc_bus(struct it6621_priv *priv) { unsigned int status; unsigned int cmdc_state; unsigned int dd_state; unsigned int val; int ret; ret = regmap_read_poll_timeout(priv->regmap, IT6621_REG_INT_STATUS1, status, status & (IT6621_TX_CMD_FAIL | IT6621_TX_CMD_DONE), 1000, 10000); if (ret) { it6621_get_ddfsm_state(priv, &dd_state); regmap_read(priv->regmap, IT6621_REG_CMDC1, &val); cmdc_state = val & IT6621_TX_CMDC_STATE; dev_err(priv->dev, "timeout! TXDDFSM: %d, TXCMDFSM: %d\n", dd_state, cmdc_state); } if (status & IT6621_TX_CMD_DONE) { /* TX init done interrupt */ regmap_write(priv->regmap, IT6621_REG_INT_STATUS1, IT6621_TX_CMD_DONE); return 0; } if (status & IT6621_TX_CMD_FAIL) { regmap_write(priv->regmap, IT6621_REG_INT_STATUS1, IT6621_TX_CMD_FAIL); dev_err(priv->dev, "TX CMD failed\n"); regmap_read(priv->regmap, IT6621_REG_CMDC1, &val); if (val & IT6621_TX_FAIL_STATE_NO_RESP) dev_err(priv->dev, "no response\n"); if (val & IT6621_TX_FAIL_STATE_UNEXP_RESP) dev_err(priv->dev, "unexpected response\n"); if (val & IT6621_TX_FAIL_STATE_ECC_ERR) dev_err(priv->dev, "uncorrectable ECC error\n"); if (val & IT6621_TX_FAIL_STATE_TIMEOUT) { if (priv->cmd_to_enabled) dev_err(priv->dev, "NACK/RETRY 256 times timeout\n"); else dev_err(priv->dev, "NACK command state\n"); } } return -EAGAIN; } static int it6621_read_cmdc_cmd(struct it6621_priv *priv, unsigned int devid, unsigned int offset, unsigned int *cmd) { unsigned int state; it6621_get_ddfsm_state(priv, &state); if (state != IT6621_TX_EARC_MODE) { dev_err(priv->dev, "abort CMDC read\n"); return -EAGAIN; } /* Data FIFO Clear */ regmap_update_bits(priv->regmap, IT6621_REG_CMDC3, IT6621_TX_DATA_FIFO_CLEAR, IT6621_TX_DATA_FIFO_CLEAR); /* TxCmd DevID */ regmap_write(priv->regmap, IT6621_REG_TX_DEV_ID, devid); /* TxCmd Offset */ regmap_write(priv->regmap, IT6621_REG_TX_OFFSET, offset); /* Read Trigger (1-byte) */ regmap_write(priv->regmap, IT6621_REG_CMDC2, IT6621_TX_READ_TRIGGER); it6621_wait_cmdc_bus(priv); return regmap_read(priv->regmap, IT6621_REG_TX_DATA_FIFO, cmd); } static void it6621_write_cmdc_cmd(struct it6621_priv *priv, unsigned int devid, unsigned int offset, unsigned int data) { unsigned int state; it6621_get_ddfsm_state(priv, &state); if (state != IT6621_TX_EARC_MODE) { dev_err(priv->dev, "abort CMDC write\n"); return; } /* Data FIFO Clear */ regmap_update_bits(priv->regmap, IT6621_REG_CMDC3, IT6621_TX_DATA_FIFO_CLEAR, IT6621_TX_DATA_FIFO_CLEAR); /* TxCmd DevID */ regmap_write(priv->regmap, IT6621_REG_TX_DEV_ID, devid); /* TxCmd Offset */ regmap_write(priv->regmap, IT6621_REG_TX_OFFSET, offset); /* TxCmd WrData */ regmap_write(priv->regmap, IT6621_REG_TX_DATA_FIFO, data); /* Write Trigger (1-byte) */ regmap_write(priv->regmap, IT6621_REG_CMDC2, IT6621_TX_WRITE_TRIGGER); it6621_wait_cmdc_bus(priv); } static int it6621_read_cmdc_bulk(struct it6621_priv *priv, unsigned int devid, unsigned int offset, size_t len, void *data) { unsigned int state; int ret; it6621_get_ddfsm_state(priv, &state); if (state != IT6621_TX_EARC_MODE) { dev_err(priv->dev, "abort CMDC bulk read\n"); return -EAGAIN; } /* Data FIFO Clear */ regmap_update_bits(priv->regmap, IT6621_REG_CMDC3, IT6621_TX_DATA_FIFO_CLEAR, IT6621_TX_DATA_FIFO_CLEAR); /* TxCmd DevID */ regmap_write(priv->regmap, IT6621_REG_TX_DEV_ID, devid); /* TxCmd Offset */ regmap_write(priv->regmap, IT6621_REG_TX_OFFSET, offset); /* Read Trigger & Read ByteNum[4:0] */ regmap_write(priv->regmap, IT6621_REG_CMDC2, IT6621_TX_READ_TRIGGER | (len - 1)); ret = it6621_wait_cmdc_bus(priv); if (ret) return ret; regmap_noinc_read(priv->regmap, IT6621_REG_TX_DATA_FIFO, data, len); return 0; } /** * it6621_set_latency - eARC TX Set latency request * * @latency: latency in marco second, range from 0 to 250 ms. */ static void it6621_set_latency(struct it6621_priv *priv, unsigned int latency) { it6621_write_cmdc_cmd(priv, 0x74, 0xd3, latency); } /** * it6621_get_latency - Read eARC RX's Latency * * @latency: latency in marco second, range from 0 to 250 ms. */ static int it6621_get_latency(struct it6621_priv *priv, unsigned int *latency) { return it6621_read_cmdc_cmd(priv, 0x74, 0xd2, latency); } /** * it6621_reset_driver - should be set power down in ARC mode * * @on: power on/down differential mode signal. */ static void it6621_reset_driver(struct it6621_priv *priv, bool enabled) { dev_dbg(priv->dev, "set TX driver %s\n", enabled ? "on" : "off"); if (enabled) regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, IT6621_TX_DRV_RESET_SEL, IT6621_TX_DRV_RESET_DIS); else regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, IT6621_TX_DRV_RESET_SEL, IT6621_TX_DRV_RESET_EN); } static int it6621_check_audio(struct it6621_priv *priv) { unsigned int val; if (test_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag) && test_bit(IT6621_AUDIO_START, &priv->audio_flag)) { if (test_bit(IT6621_EARC_BCLK_OK, &priv->events)) { /* Need to be finetune at diff platform */ msleep(50); it6621_reset_driver(priv, true); clear_bit(IT6621_EARC_BCLK_OK, &priv->events); clear_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag); regmap_read(priv->regmap, IT6621_REG_TX_AFE2, &val); dev_dbg(priv->dev, "A2: 0x%02x\n", val); } if (priv->force_arc) it6621_set_enter_arc(priv, true); } return 0; } int it6621_earc_init(struct it6621_priv *priv) { priv->state = IT6621_EARC_IDLE; priv->rclk = 0; priv->aclk = 0; priv->bclk = 0; /* Enable GRCLK */ regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL0, IT6621_GATE_RCLK_SEL, IT6621_GATE_RCLK_DIS); /* TXAFE PLL Reset */ regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE0, IT6621_TX_XP_RESET_SEL, IT6621_TX_XP_RESET_ACTIVE); /* eARCTX Reset */ regmap_update_bits(priv->regmap, IT6621_REG_SYS_RESET, IT6621_SW_RCLK_RESET_SEL, IT6621_SW_RCLK_RESET_EN); regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL0, IT6621_RCLK_FREQ_SEL, priv->rclk_sel); regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, IT6621_ACLK_DET_EN_SEL, IT6621_ACLK_DET_DIS); regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, IT6621_UPDATE_AVG_EN_SEL, priv->update_avg_enabled); regmap_update_bits(priv->regmap, IT6621_REG_CMDC4, IT6621_TX_HB_RETRY_TIME_SEL | IT6621_TX_HB_RETRY_SEL, priv->hb_retry_sel | priv->hb_retry_enabled); /* NOTE: Disable to pass SL-870 HFR5-1-35/36/37 */ regmap_update_bits(priv->regmap, IT6621_REG_CMDC5, IT6621_TX_AUTO_WRITE_STATE_SEL, IT6621_TX_AUTO_WRITE_STATE_DIS); regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL0, IT6621_TX_ENC_OPT | IT6621_TX_ENC_SEL | IT6621_TX_ECC_OPT, priv->enc_opt | (priv->audio_enc << 3) | priv->ecc_opt); regmap_write(priv->regmap, IT6621_REG_TX_ENC_SEED_LOW, priv->enc_seed & 0xff); regmap_write(priv->regmap, IT6621_REG_TX_ENC_SEED_HIGH, (priv->enc_seed & 0xff00) >> 8); regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL1, IT6621_TX_U_BIT_OPT | IT6621_TX_C_CH_OPT | IT6621_TX_PKT3_EN_SEL | IT6621_TX_PKT2_EN_SEL | IT6621_TX_PKT1_EN_SEL, priv->ubit_opt | priv->c_ch_opt | priv->pkt3_enabled | priv->pkt2_enabled | priv->pkt1_enabled); regmap_update_bits(priv->regmap, IT6621_REG_CMDC6, IT6621_TX_RESYNC_OPT | IT6621_TX_FORCE_CMO_OPT | IT6621_TX_CMO_OPT, priv->resync_opt | priv->force_cmo_enabled | priv->cmo_opt); regmap_update_bits(priv->regmap, IT6621_REG_CMDC0, IT6621_TX_TURN_OVER_SEL | IT6621_TX_NEXT_PKT_TIMEOUT_SEL, priv->turn_over_sel | priv->nxt_pkt_to_sel); regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL10, IT6621_TX_2CH_LAYOUT_SEL | IT6621_TX_NLPCM_I2S_SEL | IT6621_TX_MCH_LPCM_SEL | IT6621_TX_EXT_MUTE_SEL, priv->layout_2ch_enabled | priv->i2s_nlpcm_enabled | priv->mch_lpcm_enabled | IT6621_TX_EXT_MUTE_DIS); regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL2, IT6621_BCLK_INV_SEL | IT6621_ACLK_INV_SEL, priv->bclk_inv_enabled | IT6621_ACLK_INV_DIS); regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, IT6621_TX_ARC_NOW_SEL | IT6621_TX_ARC_SEL | IT6621_TX_EARC_SEL, priv->enter_arc_now | priv->arc_enabled | priv->earc_enabled); if (priv->force_arc) regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3, IT6621_TX_FORCE_ARC_MODE_SEL, IT6621_TX_FORCE_ARC_MODE_EN); else regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3, IT6621_TX_FORCE_ARC_MODE_SEL, IT6621_TX_FORCE_ARC_MODE_DIS); /* test to disable TxXPLOCKChgInt */ regmap_write(priv->regmap, IT6621_REG_INT_EN0, IT6621_TX_RESYNC_ERR_EN | IT6621_TX_NO_AUD_CHANGE_EN | IT6621_TX_DISV_TIMEOUT_EN | IT6621_TX_HB_LOST_EN | IT6621_TX_STATE3_CHANGE_EN | IT6621_TX_HPDIO_OFF_EN | IT6621_TX_HPDIO_ON_EN); regmap_write(priv->regmap, IT6621_REG_INT_EN1, IT6621_TX_CMD_DONE_EN | IT6621_TX_CMD_FAIL_EN | IT6621_TX_READ_STATE_CHG_EN | IT6621_TX_CMDC_BP_ERR_EN | IT6621_TX_WRITE_STATE_CHG_EN | IT6621_TX_WRITE_CAP_CHG_EN | IT6621_TX_HB_FAIL_EN); regmap_write(priv->regmap, IT6621_REG_INT_EN2, IT6621_TX_MUTE_CHANGE_EN | IT6621_TX_SPDIF_CHANGE_EN | IT6621_TX_SPDIF_READY_EN | IT6621_TX_DEC_ERR_EN | IT6621_TX_FIFO_ERR_EN); /* enable RX HPD interrupt for HPDB interrupt */ regmap_write(priv->regmap, IT6621_REG_INT_EN3, IT6621_TX_HPDB_OFF_EN | IT6621_TX_HPDB_ON_EN); regmap_write(priv->regmap, IT6621_REG_INT_EN4, IT6621_DET_NO_BCLK_EN | IT6621_DET_BCLK_VALID_EN | IT6621_DET_BCLK_STABLE_EN | IT6621_DET_ACLK_VALID_EN | IT6621_DET_ACLK_STABLE_EN); regmap_update_bits(priv->regmap, 0xa9, 0xFF, 0xFD); it6621_calc_rclk(priv); /* enable ACLK detection */ regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7, IT6621_ACLK_DET_EN_SEL, IT6621_ACLK_DET_EN); /* RTxDbgFifoClr */ regmap_update_bits(priv->regmap, IT6621_REG_TX_DEBUG_FIFO2, IT6621_TX_DEBUG_FIFO_CLEAR_SEL, IT6621_TX_DEBUG_FIFO_CLEAR_EN); regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE1, IT6621_TX_XP_ER0_SEL | IT6621_TX_XP_DEI_SEL, IT6621_TX_XP_ER0_DIS | IT6621_TX_XP_DEI_DIS); if (priv->revid == IT6621_REVISION_VARIANT_C0) { /* * NOTE: In eARC mode, change DMAC back to B0 version, * DRV_OT_SEL set to 1 for C0,TX_HYS_SEL = 5 for C0 */ regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, IT6621_TX_DRV_OT_SEL | IT6621_TX_DRV_DSW_SEL | IT6621_TX_DRV_DC, IT6621_TX_DRV_OT_EN | IT6621_TX_DRV_DSW_4 | IT6621_TX_DRV_DC_SEL_DIS | IT6621_TX_DRV_DC_DIS); regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE4, IT6621_TX_HYS_SEL | IT6621_TX_VCM_SEL | IT6621_TX_RC_CK_SEL, IT6621_TX_HYS5 | priv->vcm_sel | IT6621_TX_RC_CK_DIS); } else if (priv->revid == IT6621_REVISION_VARIANT_D0) { regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, IT6621_TX_DRV_OT_SEL | IT6621_TX_DRV_DSW_SEL | IT6621_TX_DRV_DC, IT6621_TX_DRV_OT_EN | IT6621_TX_DRV_DSW_7 | IT6621_TX_DRV_DC_SEL_DIS | IT6621_TX_DRV_DC_DIS); regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE4, IT6621_TX_HYS_SEL | IT6621_TX_VCM_SEL | IT6621_TX_RC_CK_SEL, IT6621_TX_HYS5 | priv->vcm_sel | IT6621_TX_RC_CK_DIS); } else { /* * NOTE: DRV_OT_SEL set to 0 force TM tri-state in * ARC single mode (B0). */ regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, IT6621_TX_DRV_OT_SEL | IT6621_TX_DRV_DSW_SEL, IT6621_TX_DRV_OT_DIS | IT6621_TX_DRV_DSW_4); regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE4, IT6621_TX_HYS_SEL | IT6621_TX_VCM_SEL | IT6621_TX_RC_CK_SEL, IT6621_TX_HYS6 | priv->vcm_sel | IT6621_TX_RC_CK_DIS); } /* For D0 TX_DRV_CSR */ if (priv->revid == IT6621_REVISION_VARIANT_D0) regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, IT6621_TX_DRV_CSW_SEL | IT6621_TX_DRV_CSR_SEL, IT6621_TX_DRV_CSW_4 | IT6621_TX_DRV_CSR_2); else regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3, IT6621_TX_DRV_CSW_SEL | IT6621_TX_DRV_CSR_SEL, IT6621_TX_DRV_CSW_4 | IT6621_TX_DRV_CSR_4); regmap_update_bits(priv->regmap, IT6621_REG_SYS_RESET, IT6621_SW_RCCLK_RESET_SEL | IT6621_SW_TCCLK_RESET_SEL | IT6621_SW_BCLK_RESET_SEL | IT6621_SW_ACLK_RESET_SEL, IT6621_SW_RCCLK_RESET_DIS | IT6621_SW_TCCLK_RESET_DIS | IT6621_SW_BCLK_RESET_DIS | IT6621_SW_ACLK_RESET_DIS); /* Enable eARC TX Discovery and Disconnect FSM */ regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, IT6621_TX_DD_FSM_SEL, IT6621_TX_DD_FSM_EN); if (priv->force_arc) { dev_info(priv->dev, "force ARC mode\n"); it6621_force_arc_mode(priv); } if (priv->force_earc) { dev_info(priv->dev, "force eARC mode\n"); it6621_set_auto_mode(priv); } return 0; } static int it6621_read_rxcap(struct it6621_priv *priv) { u8 rxcap[IT6621_RX_CAP_MAX_LEN]; int i; int ret; /* Enable eARC TX Command Done/Fail Interrupt */ regmap_update_bits(priv->regmap, IT6621_REG_INT_EN1, IT6621_TX_CMD_FAIL_SEL | IT6621_TX_CMD_DONE_SEL, IT6621_TX_CMD_FAIL_EN | IT6621_TX_CMD_DONE_EN); for (i = 0; i < 255; i += IT6621_RXCAP_BULK_LEN) { ret = it6621_read_cmdc_bulk(priv, 0xa0, i, IT6621_RXCAP_BULK_LEN, &rxcap[i]); if (ret) { dev_err(priv->dev, "failed to read eARC RX Cap\n"); return ret; } } mutex_lock(&priv->rxcap_lock); if (memcmp(rxcap, priv->rxcap, sizeof(priv->rxcap))) { memcpy(priv->rxcap, rxcap, sizeof(priv->rxcap)); set_bit(IT6621_EARC_CAP_CHG, &priv->events); } mutex_unlock(&priv->rxcap_lock); return 0; } static void it6621_set_state(struct it6621_priv *priv, unsigned int state) { if (priv->state != state) { priv->state = state; it6621_uapi_msg(priv, IT6621_EVENT_STATE_CHANGE, &priv->state, sizeof(priv->state)); } } static int it6621_check_rxcap(struct it6621_priv *priv) { if (test_bit(IT6621_EARC_CAP_CHG, &priv->events)) { clear_bit(IT6621_EARC_CAP_CHG, &priv->events); it6621_uapi_msg(priv, IT6621_EVENT_AUDIO_CAP_CHANGE, priv->rxcap, sizeof(priv->rxcap)); cancel_work_sync(&priv->hpdio_work); schedule_work(&priv->hpdio_work); } return 0; } static int it6621_earc_irq(struct it6621_priv *priv) { unsigned int status0; unsigned int status1; unsigned int status2; unsigned int status3; unsigned int status4; unsigned int state; unsigned int val; unsigned int latency = 0; regmap_read(priv->regmap, IT6621_REG_INT_STATUS0, &status0); regmap_read(priv->regmap, IT6621_REG_INT_STATUS1, &status1); regmap_read(priv->regmap, IT6621_REG_INT_STATUS2, &status2); regmap_read(priv->regmap, IT6621_REG_INT_STATUS3, &status3); regmap_read(priv->regmap, IT6621_REG_INT_STATUS4, &status4); regmap_write(priv->regmap, IT6621_REG_INT_STATUS0, status0); regmap_write(priv->regmap, IT6621_REG_INT_STATUS1, status1); regmap_write(priv->regmap, IT6621_REG_INT_STATUS2, status2); status3 &= IT6621_TX_HPDB_OFF | IT6621_TX_HPDB_ON; regmap_write(priv->regmap, IT6621_REG_INT_STATUS3, status3); regmap_write(priv->regmap, IT6621_REG_INT_STATUS4, status4); /* Interrupt status0 */ if (status0 & IT6621_TX_HPDIO_ON) { dev_dbg(priv->dev, "HPD IO on\n"); /* Set HPDB low clear */ regmap_update_bits(priv->regmap, IT6621_REG_SYS_CTRL1, IT6621_TX_FORCE_HPDB_LOW_SEL, IT6621_TX_FORCE_HPDB_LOW_DIS); } if (status0 & IT6621_TX_HPDIO_OFF) { dev_dbg(priv->dev, "HPD IO off\n"); if (test_bit(IT6621_ARC_START, &priv->events)) it6621_set_enter_arc(priv, false); /* Set HPDB low */ if (!priv->toggle_by_edid) regmap_update_bits(priv->regmap, IT6621_REG_SYS_CTRL1, IT6621_TX_FORCE_HPDB_LOW_SEL, IT6621_TX_FORCE_HPDB_LOW_EN); else priv->toggle_by_edid = 0; clear_bit(IT6621_ARC_START, &priv->events); } if (status0 & IT6621_TX_STATE3_CHANGE) { dev_dbg(priv->dev, "eARC enable\n"); it6621_get_ddfsm_state(priv, &state); dev_dbg(priv->dev, "eARC stat3 change to %d\n", state & IT6621_TX_EARC_MODE ? 1 : 0); clear_bit(IT6621_ARC_START, &priv->events); if (state & IT6621_TX_EARC_MODE) it6621_set_state(priv, IT6621_EARC_CONNECTED); else regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, IT6621_TX_DRV_RESET_SEL, IT6621_TX_DRV_RESET_EN); } if (status0 & IT6621_TX_HB_LOST) { dev_dbg(priv->dev, "heartbeat lost\n"); regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, IT6621_TX_DRV_RESET_SEL, IT6621_TX_DRV_RESET_EN); } if (status0 & IT6621_TX_DISV_TIMEOUT) { dev_dbg(priv->dev, "discovery timeout\n"); priv->events = 0; set_bit(IT6621_ARC_START, &priv->events); it6621_set_state(priv, IT6621_ARC_PENDING); } if (status0 & IT6621_TX_NO_AUD_CHANGE) { regmap_read(priv->regmap, IT6621_REG_SYS_STATUS, &val); val &= IT6621_TX_NO_AUDIO; dev_dbg(priv->dev, "TX has %s audio stream\n", val ? "no" : ""); } if (status0 & IT6621_TX_XP_LOCK_CHANGE) { regmap_read(priv->regmap, IT6621_REG_SYS_STATUS, &val); val &= IT6621_TX_XP_LOCK; dev_dbg(priv->dev, "XP lock: %d\n", val >> 2); } if (status0 & IT6621_TX_RESYNC_ERR) dev_err(priv->dev, "CMDC resync error\n"); /* Interrupt status1 */ if (status1 & IT6621_TX_CMD_DONE) dev_dbg(priv->dev, "Cmd Done\n"); if (status1 & IT6621_TX_HB_DONE) dev_dbg(priv->dev, "heartbeat done\n"); if (status1 & IT6621_TX_READ_STATE_CHANGE) { regmap_read(priv->regmap, IT6621_REG_TX_READ_STATE, &val); dev_dbg(priv->dev, "RX state change to 0x%02X\n", val); val &= 0x18; regmap_update_bits(priv->regmap, IT6621_REG_CMDC5, 0x18, val); } if (status1 & IT6621_TX_CMDC_BP_ERR) dev_err(priv->dev, "CMDC bi-phase error\n"); if (status1 & IT6621_TX_WRITE_STATE_CHANGE) { it6621_get_latency(priv, &latency); dev_dbg(priv->dev, "auto write STAT_CHNG 1->0 done\n"); dev_dbg(priv->dev, "latency: 0x%02X ms\n", latency); } if (status1 & IT6621_TX_WRITE_CAP_CHANGE) { dev_dbg(priv->dev, "auto write CAP_CHNG 1->0 done\n"); it6621_read_rxcap(priv); if (priv->audio_enc) { it6621_write_cmdc_cmd(priv, 0x9c, 0x10, priv->enc_opt >> 4); it6621_write_cmdc_cmd(priv, 0x9c, 0x11, priv->enc_seed & 0xff); it6621_write_cmdc_cmd(priv, 0x9c, 0x12, (priv->enc_seed & 0xff00) >> 8); } /* Write 140ms to ERX_LATENCY_REQ */ it6621_set_latency(priv, 140); regmap_read(priv->regmap, IT6621_REG_TX_AFE2, &val); val &= IT6621_TX_DRV_RESET_SEL; dev_dbg(priv->dev, "TX driver reset: %d\n", val >> 1); } if (status1 & IT6621_TX_HB_FAIL) dev_dbg(priv->dev, "heartbeat fail\n"); /* Interrupt status2 */ if (status2 & IT6621_TX_FIFO_ERR) dev_dbg(priv->dev, "audio FIFO error\n"); if (status2 & IT6621_TX_DEC_ERR) dev_dbg(priv->dev, "audio decode error\n"); if (status2 & IT6621_TX_SPDIF_READY) dev_dbg(priv->dev, "SPDIF channel status is ready\n"); if (status2 & IT6621_TX_SPDIF_CHANGE) dev_dbg(priv->dev, "SPDIF channel status is changed\n"); if (status2 & IT6621_TX_MUTE_CHANGE) { regmap_read(priv->regmap, IT6621_REG_SYS_STATUS, &val); val &= IT6621_TX_MUTE; dev_dbg(priv->dev, "input is %s\n", val ? "muted" : "unmuted"); } /* Interrupt status3 */ if (status3 & IT6621_TX_HPDB_ON) { dev_dbg(priv->dev, "HPD bus on\n"); it6621_set_state(priv, IT6621_EARC_PENDING); } if (status3 & IT6621_TX_HPDB_OFF) { dev_dbg(priv->dev, "HPD bus off\n"); regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2, IT6621_TX_DRV_RESET_SEL, IT6621_TX_DRV_RESET_EN); if (test_bit(IT6621_ARC_START, &priv->events)) it6621_set_enter_arc(priv, false); clear_bit(IT6621_ARC_START, &priv->events); it6621_set_state(priv, IT6621_EARC_IDLE); } /* Interrupt status4 */ if (status4 & IT6621_DET_ACLK_STABLE) { dev_dbg(priv->dev, "ACLK is stable\n"); it6621_get_aclk(priv); it6621_force_pdiv(priv); } if (status4 & IT6621_DET_ACLK_VALID) dev_dbg(priv->dev, "ACLK is valid\n"); if (status4 & IT6621_DET_NO_BCLK) { dev_dbg(priv->dev, "BCLK is not present\n"); clear_bit(IT6621_EARC_BCLK_OK, &priv->events); it6621_reset_driver(priv, false); } if (status4 & IT6621_DET_BCLK_STABLE) { dev_dbg(priv->dev, "BCLK is stable\n"); it6621_get_bclk(priv); set_bit(IT6621_EARC_BCLK_OK, &priv->events); if (test_bit(IT6621_AUDIO_START, &priv->audio_flag)) set_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag); } if (status4 & IT6621_DET_BCLK_VALID) dev_dbg(priv->dev, "BCLK is valid\n"); return 0; } irqreturn_t it6621_irq(int irq, void *data) { struct it6621_priv *priv = data; it6621_earc_irq(priv); it6621_check_audio(priv); it6621_check_rxcap(priv); return IRQ_HANDLED; }