[no subject]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> +
> +               val &= ~(C444_C422_CONFIG_ENABLE | C422_C420_CONFIG_ENABLE);
> +               val &= ~C422_C420_CONFIG_OUT_CB_OR_CR;
> +               val |= C422_C420_CONFIG_BYPASS;
> +               regmap_write(hdmi->regs, VID_DOWNSAMPLE_CONFIG, val);
> +
> +               regmap_clear_bits(hdmi->regs, VID_OUT_FORMAT, OUTPUT_FORMAT_DEMUX_420_ENABLE);
> +       }
> +}
> +
> +static int mtk_hdmi_v2_setup_audio_infoframe(struct mtk_hdmi *hdmi)
> +{
> +       struct hdmi_codec_params *params = &hdmi->aud_param.codec_params;
> +       struct hdmi_audio_infoframe frame;
> +       u8 buffer[14];
> +       ssize_t ret;
> +
> +       memcpy(&frame, &params->cea, sizeof(frame));
> +
> +       ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer));
> +       if (ret < 0)
> +               return ret;
> +
> +       mtk_hdmi_v2_hw_write_audio_infoframe(hdmi, buffer);
> +
> +       return 0;
> +}
> +
> +static inline void mtk_hdmi_v2_hw_reset_av_mute_regs(struct mtk_hdmi *hdmi)
> +{

This function is called only by mtk_hdmi_v2_hw_av_mute(), so merge this function into mtk_hdmi_v2_hw_av_mute().

> +       /* GCP packet */
> +       regmap_clear_bits(hdmi->regs, TOP_CFG01, CP_CLR_MUTE_EN | CP_SET_MUTE_EN);
> +       regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, CP_RPT_EN);

This would finally be set, why clear?

> +       regmap_clear_bits(hdmi->regs, TOP_INFO_EN, CP_EN | CP_EN_WR);

Ditto.

> +}
> +
> +static inline void mtk_hdmi_v2_hw_av_mute(struct mtk_hdmi *hdmi, bool mute)
> +{
> +       mtk_hdmi_v2_hw_reset_av_mute_regs(hdmi);
> +
> +       if (mute)
> +               regmap_set_bits(hdmi->regs, TOP_CFG01, CP_SET_MUTE_EN);
> +       else
> +               regmap_set_bits(hdmi->regs, TOP_CFG01, CP_CLR_MUTE_EN);
> +
> +       regmap_set_bits(hdmi->regs, TOP_INFO_RPT, CP_RPT_EN);
> +       regmap_set_bits(hdmi->regs, TOP_INFO_EN, CP_EN | CP_EN_WR);
> +}
> +
> +static void mtk_hdmi_v2_hw_ncts_enable(struct mtk_hdmi *hdmi, bool enable)
> +{
> +       if (enable)
> +               regmap_set_bits(hdmi->regs, AIP_CTRL, CTS_SW_SEL);
> +       else
> +               regmap_clear_bits(hdmi->regs, AIP_CTRL, CTS_SW_SEL);
> +}
> +
> +static void mtk_hdmi_v2_hw_aud_set_channel_status(struct mtk_hdmi *hdmi)
> +{
> +       u8 *ch_status = hdmi->aud_param.codec_params.iec.status;
> +
> +       /* Only the first 5 to 7 bytes of Channel Status contain useful information */
> +       regmap_write(hdmi->regs, AIP_I2S_CHST0, mtk_hdmi_v2_format_hw_packet(&ch_status[0], 4));
> +       regmap_write(hdmi->regs, AIP_I2S_CHST1, mtk_hdmi_v2_format_hw_packet(&ch_status[4], 3));
> +}
> +
> +static void mtk_hdmi_v2_hw_aud_set_ncts(struct mtk_hdmi *hdmi,
> +                                    unsigned int sample_rate,
> +                                    unsigned int clock)
> +{
> +       unsigned int n, cts;
> +
> +       mtk_hdmi_get_ncts(sample_rate, clock, &n, &cts);
> +
> +       regmap_write(hdmi->regs, AIP_N_VAL, n);
> +       regmap_write(hdmi->regs, AIP_CTS_SVAL, cts);
> +}
> +
> +static void mtk_hdmi_v2_hw_aud_enable(struct mtk_hdmi *hdmi, bool enable)
> +{
> +       if (enable)
> +               regmap_clear_bits(hdmi->regs, AIP_TXCTRL, AUD_PACKET_DROP);
> +       else
> +               regmap_set_bits(hdmi->regs, AIP_TXCTRL, AUD_PACKET_DROP);
> +}
> +
> +static u32 mtk_hdmi_v2_aud_output_channel_map(u8 sd0, u8 sd1, u8 sd2, u8 sd3,
> +                                             u8 sd4, u8 sd5, u8 sd6, u8 sd7)
> +{
> +       u32 val;
> +
> +       /*
> +        * Each of the Output Channels (0-7) can be mapped to get their input
> +        * from any of the available Input Channels (0-7): this function
> +        * takes input channel numbers and formats a value that must then
> +        * be written to the TOP_AUD_MAP hardware register by the caller.
> +        */
> +       val = FIELD_PREP(SD0_MAP, sd0) | FIELD_PREP(SD1_MAP, sd1);
> +       val |= FIELD_PREP(SD2_MAP, sd2) | FIELD_PREP(SD3_MAP, sd3);
> +       val |= FIELD_PREP(SD4_MAP, sd4) | FIELD_PREP(SD5_MAP, sd5);
> +       val |= FIELD_PREP(SD6_MAP, sd6) | FIELD_PREP(SD7_MAP, sd7);
> +
> +       return val;
> +}
> +
> +static void mtk_hdmi_audio_dsd_config(struct mtk_hdmi *hdmi,
> +                                     unsigned char chnum, bool dsd_bypass)
> +{
> +       u32 channel_map;
> +
> +       regmap_update_bits(hdmi->regs, AIP_CTRL, SPDIF_EN | DSD_EN | HBRA_ON, DSD_EN);
> +       regmap_set_bits(hdmi->regs, AIP_TXCTRL, DSD_MUTE_EN);
> +
> +       if (dsd_bypass)
> +               channel_map = mtk_hdmi_v2_aud_output_channel_map(0, 2, 4, 6, 1, 3, 5, 7);
> +       else
> +               channel_map = mtk_hdmi_v2_aud_output_channel_map(0, 5, 1, 0, 3, 2, 4, 0);
> +
> +       regmap_write(hdmi->regs, TOP_AUD_MAP, channel_map);
> +       regmap_clear_bits(hdmi->regs, AIP_SPDIF_CTRL, I2S2DSD_EN);
> +}
> +
> +static inline void mtk_hdmi_v2_hw_i2s_fifo_map(struct mtk_hdmi *hdmi, u32 fifo_mapping)
> +{
> +       regmap_update_bits(hdmi->regs, AIP_I2S_CTRL,
> +                          FIFO0_MAP | FIFO1_MAP | FIFO2_MAP | FIFO3_MAP, fifo_mapping);
> +}
> +
> +static inline void mtk_hdmi_v2_hw_i2s_ch_number(struct mtk_hdmi *hdmi, u8 chnum)
> +{
> +       regmap_update_bits(hdmi->regs, AIP_CTRL, I2S_EN, FIELD_PREP(I2S_EN, chnum));
> +}
> +
> +static void mtk_hdmi_v2_hw_i2s_ch_mapping(struct mtk_hdmi *hdmi, u8 chnum, u8 mapping)
> +{
> +       u32 fifo_map;
> +       u8 bdata;
> +
> +       switch (chnum) {
> +       default:
> +       case 2:
> +               bdata = 0x1;
> +               break;
> +       case 3:
> +               bdata = 0x3;
> +               break;
> +       case 6:
> +               if (mapping == 0x0e) {
> +                       bdata = 0xf;
> +                       break;
> +               }
> +               fallthrough;
> +       case 5:
> +               bdata = 0x7;
> +               break;
> +       case 7:
> +       case 8:
> +               bdata = 0xf;
> +               break;
> +       }
> +
> +       /* Assign default FIFO mapping: SD0 to FIFO0, SD1 to FIFO1, etc. */
> +       fifo_map = FIELD_PREP(FIFO0_MAP, 0) | FIELD_PREP(FIFO1_MAP, 1);
> +       fifo_map |= FIELD_PREP(FIFO2_MAP, 2) | FIELD_PREP(FIFO3_MAP, 3);
> +       mtk_hdmi_v2_hw_i2s_fifo_map(hdmi, fifo_map);
> +       mtk_hdmi_v2_hw_i2s_ch_number(hdmi, bdata);
> +
> +       /*
> +        * Set HDMI Audio packet layout indicator:
> +        * Layout 0 is for two channels
> +        * Layout 1 is for up to eight channels
> +        */
> +       if (chnum == 2)
> +               regmap_set_bits(hdmi->regs, AIP_TXCTRL, AUD_LAYOUT_1);
> +       else
> +               regmap_clear_bits(hdmi->regs, AIP_TXCTRL, AUD_LAYOUT_1);
> +}
> +
> +static void mtk_hdmi_i2s_data_fmt(struct mtk_hdmi *hdmi, unsigned char fmt)
> +{
> +       u32 val;
> +
> +       regmap_read(hdmi->regs, AIP_I2S_CTRL, &val);
> +       val &= ~(WS_HIGH | I2S_1ST_BIT_NOSHIFT | JUSTIFY_RIGHT);
> +
> +       switch (fmt) {
> +       case HDMI_I2S_MODE_RJT_24BIT:
> +       case HDMI_I2S_MODE_RJT_16BIT:
> +               val |= (WS_HIGH | I2S_1ST_BIT_NOSHIFT | JUSTIFY_RIGHT);
> +               break;
> +       case HDMI_I2S_MODE_LJT_24BIT:
> +       case HDMI_I2S_MODE_LJT_16BIT:
> +               val |= (WS_HIGH | I2S_1ST_BIT_NOSHIFT);
> +               break;
> +       case HDMI_I2S_MODE_I2S_24BIT:
> +       case HDMI_I2S_MODE_I2S_16BIT:
> +       default:
> +               break;
> +       }
> +
> +       regmap_write(hdmi->regs, AIP_I2S_CTRL, val);
> +}
> +
> +static inline void mtk_hdmi_i2s_sck_edge_rise(struct mtk_hdmi *hdmi, bool rise)

rise is always true, so drop it.

> +{
> +       if (rise)
> +               regmap_set_bits(hdmi->regs, AIP_I2S_CTRL, SCK_EDGE_RISE);
> +       else
> +               regmap_clear_bits(hdmi->regs, AIP_I2S_CTRL, SCK_EDGE_RISE);
> +}
> +
> +static inline void mtk_hdmi_i2s_cbit_order(struct mtk_hdmi *hdmi, unsigned int cbit)

cbit is always CBIT_ORDER_SAME, so drop it.

> +{
> +       regmap_update_bits(hdmi->regs, AIP_I2S_CTRL, CBIT_ORDER_SAME, cbit);
> +}
> +
> +static inline void mtk_hdmi_i2s_vbit(struct mtk_hdmi *hdmi, unsigned int vbit)

vbit is always 0, so drop it.

> +{
> +       /* V bit: 0 for PCM, 1 for Compressed data */
> +       regmap_update_bits(hdmi->regs, AIP_I2S_CTRL, VBIT_COMPRESSED, vbit);
> +}
> +
> +static inline void mtk_hdmi_i2s_data_direction(struct mtk_hdmi *hdmi, unsigned int is_lsb)

is_lsb is always 0, so drop it.

> +{
> +       regmap_update_bits(hdmi->regs, AIP_I2S_CTRL, I2S_DATA_DIR_LSB, is_lsb);
> +}
> +
> +static inline void mtk_hdmi_v2_hw_audio_type(struct mtk_hdmi *hdmi, unsigned int spdif_i2s)

spdif_is2 is always HDMI_AUD_INPUT_I2S, so drop it.

> +{
> +       regmap_update_bits(hdmi->regs, AIP_CTRL, SPDIF_EN, FIELD_PREP(SPDIF_EN, spdif_i2s));
> +}

There is so many function just write one register,
and these function is called only when audio input type is default.
I think it's better to merge these function into one function for default audio input type.

> +
> +static u8 mtk_hdmi_v2_get_i2s_ch_mapping(struct mtk_hdmi *hdmi, u8 channel_type)
> +{
> +       switch (channel_type) {
> +       case HDMI_AUD_CHAN_TYPE_1_1:
> +       case HDMI_AUD_CHAN_TYPE_2_1:
> +               return 0x01;
> +       case HDMI_AUD_CHAN_TYPE_3_0:
> +               return 0x02;
> +       case HDMI_AUD_CHAN_TYPE_3_1:
> +               return 0x03;
> +       case HDMI_AUD_CHAN_TYPE_3_0_LRS:
> +       case HDMI_AUD_CHAN_TYPE_4_0:
> +               return 0x08;
> +       case HDMI_AUD_CHAN_TYPE_5_1:
> +               return 0x0b;
> +       case HDMI_AUD_CHAN_TYPE_4_1_CLRS:
> +       case HDMI_AUD_CHAN_TYPE_6_0:
> +       case HDMI_AUD_CHAN_TYPE_6_0_CS:
> +       case HDMI_AUD_CHAN_TYPE_6_0_CH:
> +       case HDMI_AUD_CHAN_TYPE_6_0_OH:
> +       case HDMI_AUD_CHAN_TYPE_6_0_CHR:
> +               return 0x0e;
> +       case HDMI_AUD_CHAN_TYPE_1_0:
> +       case HDMI_AUD_CHAN_TYPE_2_0:
> +       case HDMI_AUD_CHAN_TYPE_3_1_LRS:
> +       case HDMI_AUD_CHAN_TYPE_4_1:
> +       case HDMI_AUD_CHAN_TYPE_5_0:
> +       case HDMI_AUD_CHAN_TYPE_4_0_CLRS:
> +       case HDMI_AUD_CHAN_TYPE_6_1:
> +       case HDMI_AUD_CHAN_TYPE_6_1_CS:
> +       case HDMI_AUD_CHAN_TYPE_6_1_CH:
> +       case HDMI_AUD_CHAN_TYPE_6_1_OH:
> +       case HDMI_AUD_CHAN_TYPE_6_1_CHR:
> +       case HDMI_AUD_CHAN_TYPE_7_0:
> +       case HDMI_AUD_CHAN_TYPE_7_0_LH_RH:
> +       case HDMI_AUD_CHAN_TYPE_7_0_LSR_RSR:
> +       case HDMI_AUD_CHAN_TYPE_7_0_LC_RC:
> +       case HDMI_AUD_CHAN_TYPE_7_0_LW_RW:
> +       case HDMI_AUD_CHAN_TYPE_7_0_LSD_RSD:
> +       case HDMI_AUD_CHAN_TYPE_7_0_LSS_RSS:
> +       case HDMI_AUD_CHAN_TYPE_7_0_LHS_RHS:
> +       case HDMI_AUD_CHAN_TYPE_7_0_CS_CH:
> +       case HDMI_AUD_CHAN_TYPE_7_0_CS_OH:
> +       case HDMI_AUD_CHAN_TYPE_7_0_CS_CHR:
> +       case HDMI_AUD_CHAN_TYPE_7_0_CH_OH:
> +       case HDMI_AUD_CHAN_TYPE_7_0_CH_CHR:
> +       case HDMI_AUD_CHAN_TYPE_7_0_OH_CHR:
> +       case HDMI_AUD_CHAN_TYPE_7_0_LSS_RSS_LSR_RSR:
> +       case HDMI_AUD_CHAN_TYPE_8_0_LH_RH_CS:
> +       case HDMI_AUD_CHAN_TYPE_7_1:
> +       case HDMI_AUD_CHAN_TYPE_7_1_LH_RH:
> +       case HDMI_AUD_CHAN_TYPE_7_1_LSR_RSR:
> +       case HDMI_AUD_CHAN_TYPE_7_1_LC_RC:
> +       case HDMI_AUD_CHAN_TYPE_7_1_LW_RW:
> +       case HDMI_AUD_CHAN_TYPE_7_1_LSD_RSD:
> +       case HDMI_AUD_CHAN_TYPE_7_1_LSS_RSS:
> +       case HDMI_AUD_CHAN_TYPE_7_1_LHS_RHS:
> +       case HDMI_AUD_CHAN_TYPE_7_1_CS_CH:
> +       case HDMI_AUD_CHAN_TYPE_7_1_CS_OH:
> +       case HDMI_AUD_CHAN_TYPE_7_1_CS_CHR:
> +       case HDMI_AUD_CHAN_TYPE_7_1_CH_OH:
> +       case HDMI_AUD_CHAN_TYPE_7_1_CH_CHR:
> +       case HDMI_AUD_CHAN_TYPE_7_1_OH_CHR:
> +       case HDMI_AUD_CHAN_TYPE_7_1_LSS_RSS_LSR_RSR:
> +       default:
> +               return 0;
> +       }
> +
> +       return 0;
> +}
> +
> +static inline void mtk_hdmi_v2_hw_i2s_ch_swap(struct mtk_hdmi *hdmi, unsigned char swapbit)
> +{

swapbit is constant. So drop it.

> +       regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, MAX_2UI_I2S_HI_WRITE,
> +                          FIELD_PREP(MAX_2UI_I2S_HI_WRITE, swapbit));
> +}
> +
> +static void mtk_hdmi_hbr_config(struct mtk_hdmi *hdmi, bool dsd_bypass)
> +{
> +       const u32 hbr_mask = SPDIF_EN | DSD_EN | HBRA_ON;
> +
> +       if (dsd_bypass) {
> +               regmap_update_bits(hdmi->regs, AIP_CTRL, hbr_mask, HBRA_ON);
> +               regmap_set_bits(hdmi->regs, AIP_CTRL, I2S_EN);
> +       } else {
> +               regmap_update_bits(hdmi->regs, AIP_CTRL, hbr_mask, SPDIF_EN);
> +               regmap_set_bits(hdmi->regs, AIP_CTRL, SPDIF_INTERNAL_MODULE);
> +               regmap_set_bits(hdmi->regs, AIP_CTRL, HBR_FROM_SPDIF);
> +               regmap_set_bits(hdmi->regs, AIP_CTRL, CTS_CAL_N4);
> +       }
> +}
> +
> +static inline void mtk_hdmi_v2_hw_spdif_config(struct mtk_hdmi *hdmi)
> +{
> +       regmap_clear_bits(hdmi->regs, AIP_SPDIF_CTRL, WR_1UI_LOCK);
> +       regmap_clear_bits(hdmi->regs, AIP_SPDIF_CTRL, FS_OVERRIDE_WRITE);
> +       regmap_clear_bits(hdmi->regs, AIP_SPDIF_CTRL, WR_2UI_LOCK);
> +
> +       regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, MAX_1UI_WRITE,
> +                          FIELD_PREP(MAX_1UI_WRITE, 4));
> +       regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, MAX_2UI_SPDIF_WRITE,
> +                          FIELD_PREP(MAX_2UI_SPDIF_WRITE, 9));
> +       regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, AUD_ERR_THRESH,
> +                          FIELD_PREP(AUD_ERR_THRESH, 4));
> +
> +       regmap_set_bits(hdmi->regs, AIP_SPDIF_CTRL, I2S2DSD_EN);
> +}
> +
> +static void mtk_hdmi_v2_aud_set_input(struct mtk_hdmi *hdmi)
> +{
> +       struct hdmi_audio_param *aud_param = &hdmi->aud_param;
> +       struct hdmi_codec_params *codec_params = &aud_param->codec_params;
> +       u8 i2s_ch_map;
> +       u32 out_ch_map;
> +
> +       /* Write the default output channel map. CH0 maps to SD0, CH1 maps to SD1, etc */
> +       out_ch_map = mtk_hdmi_v2_aud_output_channel_map(0, 1, 2, 3, 4, 5, 6, 7);
> +       regmap_write(hdmi->regs, TOP_AUD_MAP, out_ch_map);
> +
> +       regmap_update_bits(hdmi->regs, AIP_SPDIF_CTRL, MAX_2UI_I2S_HI_WRITE, 0);
> +       regmap_clear_bits(hdmi->regs, AIP_CTRL,
> +                         SPDIF_EN | DSD_EN | HBRA_ON | CTS_CAL_N4 |
> +                         HBR_FROM_SPDIF | SPDIF_INTERNAL_MODULE);
> +       regmap_clear_bits(hdmi->regs, AIP_TXCTRL, DSD_MUTE_EN | AUD_LAYOUT_1);
> +
> +       if (aud_param->aud_input_type == HDMI_AUD_INPUT_I2S) {
> +               switch (aud_param->aud_codec) {
> +               case HDMI_AUDIO_CODING_TYPE_DTS_HD:
> +               case HDMI_AUDIO_CODING_TYPE_MLP:
> +                       mtk_hdmi_i2s_data_fmt(hdmi, aud_param->aud_i2s_fmt);
> +                       mtk_hdmi_hbr_config(hdmi, true);
> +                       break;
> +               case HDMI_AUDIO_CODING_TYPE_DSD:
> +                       mtk_hdmi_audio_dsd_config(hdmi, codec_params->channels, 0);
> +                       mtk_hdmi_v2_hw_i2s_ch_mapping(hdmi, codec_params->channels, 1);
> +                       break;
> +               default:
> +                       mtk_hdmi_i2s_data_fmt(hdmi, aud_param->aud_i2s_fmt);
> +                       mtk_hdmi_i2s_sck_edge_rise(hdmi, true);
> +                       mtk_hdmi_i2s_cbit_order(hdmi, CBIT_ORDER_SAME);
> +                       mtk_hdmi_i2s_vbit(hdmi, 0); /* PCM data */
> +                       mtk_hdmi_i2s_data_direction(hdmi, 0); /* MSB first */
> +                       mtk_hdmi_v2_hw_audio_type(hdmi, HDMI_AUD_INPUT_I2S);
> +                       i2s_ch_map = mtk_hdmi_v2_get_i2s_ch_mapping(hdmi,
> +                                               aud_param->aud_input_chan_type);
> +                       mtk_hdmi_v2_hw_i2s_ch_mapping(hdmi, codec_params->channels, i2s_ch_map);
> +                       mtk_hdmi_v2_hw_i2s_ch_swap(hdmi, MAX_2UI_I2S_LFE_CC_SWAP);
> +               }
> +       } else {
> +               if (codec_params->sample_rate == 768000 &&
> +                   (aud_param->aud_codec == HDMI_AUDIO_CODING_TYPE_DTS_HD ||
> +                    aud_param->aud_codec == HDMI_AUDIO_CODING_TYPE_MLP)) {
> +                       mtk_hdmi_hbr_config(hdmi, false);
> +               } else {
> +                       mtk_hdmi_v2_hw_spdif_config(hdmi);
> +                       mtk_hdmi_v2_hw_i2s_ch_mapping(hdmi, 2, 0);
> +               }
> +       }
> +}
> +
> +static void mtk_hdmi_v2_aud_set_sw_ncts(struct mtk_hdmi *hdmi,
> +                                       struct drm_display_mode *display_mode)
> +{
> +       mtk_hdmi_v2_hw_ncts_enable(hdmi, false);

This function is called only by mtk_hdmi_v2_aud_output_config(),
and mtk_hdmi_v2_aud_output_config() calls mtk_hdmi_v2_hw_ncts_enable(hdmi, true);
so I think this mtk_hdmi_v2_hw_ncts_enable(hdmi, false) should also place in mtk_hdmi_v2_aud_output_config().
After this, this function seems does only one thing and mtk_hdmi_v2_aud_output_config() should directly call mtk_hdmi_v2_hw_aud_set_ncts() and drop this function.

> +       mtk_hdmi_v2_hw_aud_set_ncts(hdmi, hdmi->aud_param.codec_params.sample_rate,
> +                                display_mode->clock);
> +}
> +
> +static inline void mtk_hdmi_v2_hw_audio_input_enable(struct mtk_hdmi *hdmi, bool ena)
> +{

ena is always true, so drop it.

> +       if (ena)
> +               regmap_set_bits(hdmi->regs, AIP_CTRL, AUD_IN_EN);
> +       else
> +               regmap_clear_bits(hdmi->regs, AIP_CTRL, AUD_IN_EN);
> +}
> +
> +static void mtk_hdmi_v2_aip_ctrl_init(struct mtk_hdmi *hdmi)
> +{
> +       regmap_set_bits(hdmi->regs, AIP_CTRL,
> +                       AUD_SEL_OWRT | NO_MCLK_CTSGEN_SEL | MCLK_EN | CTS_REQ_EN);
> +       regmap_clear_bits(hdmi->regs, AIP_TPI_CTRL, TPI_AUDIO_LOOKUP_EN);
> +}
> +
> +static void mtk_hdmi_v2_audio_reset(struct mtk_hdmi *hdmi, bool reset)
> +{
> +       const u32 arst_bits = RST4AUDIO | RST4AUDIO_FIFO | RST4AUDIO_ACR;
> +
> +       if (reset)
> +               regmap_set_bits(hdmi->regs, AIP_TXCTRL, arst_bits);
> +       else
> +               regmap_clear_bits(hdmi->regs, AIP_TXCTRL, arst_bits);
> +}
> +
> +static void mtk_hdmi_v2_aud_output_config(struct mtk_hdmi *hdmi,
> +                                         struct drm_display_mode *display_mode)
> +{
> +       mtk_hdmi_v2_hw_aud_mute(hdmi, true);
> +       mtk_hdmi_v2_hw_aud_enable(hdmi, false);
> +       mtk_hdmi_v2_audio_reset(hdmi, true);
> +       mtk_hdmi_v2_aip_ctrl_init(hdmi);
> +       mtk_hdmi_v2_aud_set_input(hdmi);
> +       mtk_hdmi_v2_hw_aud_set_channel_status(hdmi);
> +       mtk_hdmi_v2_setup_audio_infoframe(hdmi);
> +       mtk_hdmi_v2_hw_audio_input_enable(hdmi, true);
> +       mtk_hdmi_v2_audio_reset(hdmi, false);
> +       mtk_hdmi_v2_aud_set_sw_ncts(hdmi, display_mode);
> +
> +       /* Wait for the HW to apply settings */
> +       usleep_range(25, 50);
> +
> +       mtk_hdmi_v2_hw_ncts_enable(hdmi, true);
> +       mtk_hdmi_v2_hw_aud_enable(hdmi, true);

In audio_startup() and audio_shutdown() also call mtk_hdmi_v2_hw_aud_enable(),
and would them conflict?
In v1 audio enable/disable is done in audio_startup() and audio_shutdown().
Maybe removing audio enable/disable here would prevent conflict.

> +       mtk_hdmi_v2_hw_aud_mute(hdmi, false);
> +}
> +
> +static void mtk_hdmi_v2_change_video_resolution(struct mtk_hdmi *hdmi)
> +{
> +       mtk_hdmi_v2_hw_reset(hdmi);
> +       mtk_hdmi_v2_set_sw_hpd(hdmi, true);
> +       udelay(2);
> +
> +       regmap_write(hdmi->regs, HDCP_TOP_CTRL, 0);
> +
> +       /* Enable HDCP reauthentication interrupt */
> +       regmap_set_bits(hdmi->regs, TOP_INT_ENABLE00, HDCP2X_RX_REAUTH_REQ_DDCM_INT);

In isr, I does not see any thing about reauthentication, so this is not necessary to enable this interrupt.

> +
> +       /* Enable hotplug and pord interrupts */
> +       mtk_hdmi_v2_enable_hpd_pord_irq(hdmi, true);
> +
> +       /* Force enabling HDCP HPD */
> +       regmap_set_bits(hdmi->regs, HDCP2X_CTRL_0, HDCP2X_HPD_OVR);
> +       regmap_set_bits(hdmi->regs, HDCP2X_CTRL_0, HDCP2X_HPD_SW);
> +
> +       /* Set 8 bits per pixel */
> +       regmap_update_bits(hdmi->regs, TOP_CFG00, TMDS_PACK_MODE,
> +                          FIELD_PREP(TMDS_PACK_MODE, TMDS_PACK_MODE_8BPP));
> +       /* Disable generating deepcolor packets */
> +       regmap_clear_bits(hdmi->regs, TOP_CFG00, DEEPCOLOR_PKT_EN);
> +       /* Disable adding deepcolor information to the general packet */
> +       regmap_clear_bits(hdmi->regs, TOP_MISC_CTLR, DEEP_COLOR_ADD);
> +
> +       if (hdmi->curr_conn->display_info.is_hdmi)
> +               regmap_set_bits(hdmi->regs, TOP_CFG00, HDMI_MODE_HDMI);
> +       else
> +               regmap_clear_bits(hdmi->regs, TOP_CFG00, HDMI_MODE_HDMI);
> +
> +       udelay(5);
> +       mtk_hdmi_v2_hw_vid_mute(hdmi, true);
> +       mtk_hdmi_v2_hw_aud_mute(hdmi, true);
> +       mtk_hdmi_v2_hw_av_mute(hdmi, false);

I'm confused with these three statement.
mtk_hdmi_v2_hw_vid_mute(true) would mute video.
mtk_hdmi_v2_hw_aud_mute(hdmi, true) would mute audio.
mtk_hdmi_v2_hw_av_mute(hdmi, false) would let video and audio unmute?
This looks weird.
Add comment to describe why doing this.

> +
> +       regmap_update_bits(hdmi->regs, TOP_CFG01,
> +                          NULL_PKT_VSYNC_HIGH_EN | NULL_PKT_EN, NULL_PKT_VSYNC_HIGH_EN);
> +       usleep_range(100, 150);
> +
> +       /* Enable scrambling if tmds clock is 340MHz or more */
> +       mtk_hdmi_v2_enable_scrambling(hdmi, hdmi->mode.clock >= 340 * KILO);
> +
> +       /* Disable YUV420 downsampling */
> +       mtk_hdmi_yuv420_downsampling(hdmi, false);
> +}
> +
> +static void mtk_hdmi_v2_output_set_display_mode(struct mtk_hdmi *hdmi,
> +                                               struct drm_display_mode *mode)
> +{
> +       union phy_configure_opts opts = {
> +               .dp = { .link_rate = hdmi->mode.clock * KILO }
> +       };
> +       int ret;
> +
> +       ret = phy_configure(hdmi->phy, &opts);
> +       if (ret)
> +               dev_err(hdmi->dev, "Setting clock=%d failed: %d", mode->clock, ret);
> +
> +       mtk_hdmi_v2_change_video_resolution(hdmi);
> +       mtk_hdmi_v2_aud_output_config(hdmi, mode);
> +}
> +
> +static int mtk_hdmi_v2_clk_enable(struct mtk_hdmi *hdmi)
> +{
> +       int ret;
> +
> +       ret = clk_prepare_enable(hdmi->clk[MTK_HDMI_V2_CLK_HDCP_SEL]);
> +       if (ret)
> +               return ret;
> +
> +       ret = clk_prepare_enable(hdmi->clk[MTK_HDMI_V2_CLK_HDCP_24M_SEL]);
> +       if (ret)
> +               goto disable_hdcp_clk;
> +
> +       ret = clk_prepare_enable(hdmi->clk[MTK_HDMI_V2_CLK_HDMI_APB_SEL]);
> +       if (ret)
> +               goto disable_hdcp_24m_clk;
> +
> +       ret = clk_prepare_enable(hdmi->clk[MTK_HDMI_V2_CLK_VPP_SPLIT_HDMI]);
> +       if (ret)
> +               goto disable_bus_clk;
> +
> +       return 0;
> +
> +disable_bus_clk:
> +       clk_disable_unprepare(hdmi->clk[MTK_HDMI_V2_CLK_HDMI_APB_SEL]);
> +disable_hdcp_24m_clk:
> +       clk_disable_unprepare(hdmi->clk[MTK_HDMI_V2_CLK_HDCP_24M_SEL]);
> +disable_hdcp_clk:
> +       clk_disable_unprepare(hdmi->clk[MTK_HDMI_V2_CLK_HDCP_SEL]);
> +
> +       return ret;
> +}
> +
> +static void mtk_hdmi_v2_clk_disable(struct mtk_hdmi *hdmi)
> +{
> +       clk_disable_unprepare(hdmi->clk[MTK_HDMI_V2_CLK_VPP_SPLIT_HDMI]);
> +       clk_disable_unprepare(hdmi->clk[MTK_HDMI_V2_CLK_HDMI_APB_SEL]);
> +       clk_disable_unprepare(hdmi->clk[MTK_HDMI_V2_CLK_HDCP_24M_SEL]);
> +       clk_disable_unprepare(hdmi->clk[MTK_HDMI_V2_CLK_HDCP_SEL]);
> +}
> +
> +static void mtk_hdmi_hpd_event(enum hdmi_hpd_state hpd, struct device *dev)
> +{
> +       struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
> +
> +       if (hdmi && hdmi->bridge.encoder && hdmi->bridge.encoder->dev)
> +               drm_helper_hpd_irq_event(hdmi->bridge.encoder->dev);

This function just do one thing and is called only by isr thread, so merge this function into isr thread.

> +}
> +
> +static enum hdmi_hpd_state mtk_hdmi_v2_hpd_pord_status(struct mtk_hdmi *hdmi)
> +{
> +       u8 hpd_pin_sta, pord_pin_sta;
> +       u32 hpd_status;
> +
> +       regmap_read(hdmi->regs, HPD_DDC_STATUS, &hpd_status);
> +       hpd_pin_sta = FIELD_GET(HPD_PIN_STA, hpd_status);
> +       pord_pin_sta = FIELD_GET(PORD_PIN_STA, hpd_status);
> +
> +       if (hpd_pin_sta && pord_pin_sta)
> +               return HDMI_PLUG_IN_AND_SINK_POWER_ON;
> +       else if (hpd_pin_sta)
> +               return HDMI_PLUG_IN_ONLY;

I'm not sure why need this state?
HDMI_PLUG_IN_ONLY is plugged in or not plugged in?
In audio_hook_plugged_cb, HDMI_PLUG_IN_ONLY is not plugged.
In bridge_detect, it's connected (plugged in)
This is really confused.
I think we just need two status: one for plug in and one for plug out.

> +       else
> +               return HDMI_PLUG_OUT;
> +}
> +
> +static irqreturn_t mtk_hdmi_v2_isr(int irq, void *arg)
> +{
> +       struct mtk_hdmi *hdmi = arg;
> +       unsigned int irq_sta;
> +       int ret = IRQ_HANDLED;
> +
> +       regmap_read(hdmi->regs, TOP_INT_STA00, &irq_sta);
> +
> +       /* Handle Hotplug Detection interrupt */
> +       if (irq_sta & (HTPLG_R_INT | HTPLG_F_INT | PORD_F_INT | PORD_R_INT)) {

if (irq_sta & HPD_PORD_HW_IRQS)

> +               mtk_hdmi_v2_enable_hpd_pord_irq(hdmi, false);

I think you should not dynamic enable/disable hotplug interrupt.
In one case that user plug in, isr is called and disable interrupt here,
then in __mtk_hdmi_v2_isr_thread(), call mtk_hdmi_v2_hpd_pord_status() and status is plug in,
but then user plug out immediately before tk_hdmi_v2_enable_hpd_pord_irq(hdmi, true),
so the plug out interrupt is missed and driver thought it's plug in.
Generally, in probe function enable the interrupt and not dynamically enable/disable it.

> +               ret = IRQ_WAKE_THREAD;
> +       }
> +
> +       /*
> +        * Clear all 32 + 19 interrupts in CLR00 and CLR01: this is important
> +        * to avoid unwanted retriggering of any interrupts
> +        */
> +       regmap_write(hdmi->regs, TOP_INT_CLR00, GENMASK(31, 0));
> +       regmap_write(hdmi->regs, TOP_INT_CLR01, GENMASK(18, 0));

You never enable interrupt in TOP_INT_ENABLE01,
so it's not necessary to clear TOP_INT_CLR01.

> +
> +       /* Restore interrupt clearing registers to zero */
> +       regmap_write(hdmi->regs, TOP_INT_CLR00, 0);
> +       regmap_write(hdmi->regs, TOP_INT_CLR01, 0);
> +
> +       return ret;
> +}
> +
> +static irqreturn_t __mtk_hdmi_v2_isr_thread(struct mtk_hdmi *hdmi)
> +{
> +       enum hdmi_hpd_state hpd;
> +
> +       hpd = mtk_hdmi_v2_hpd_pord_status(hdmi);
> +       if (hpd != hdmi->hpd) {
> +               hdmi->hpd = hpd;
> +               mtk_hdmi_hpd_event(hpd, hdmi->dev);
> +       }
> +
> +       mtk_hdmi_v2_enable_hpd_pord_irq(hdmi, true);
> +       return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t mtk_hdmi_v2_isr_thread(int irq, void *arg)
> +{
> +       struct mtk_hdmi *hdmi = arg;
> +
> +       /*
> +        * Debounce HDMI monitor HPD status.
> +        * Empirical testing shows that 30ms is enough wait
> +        */
> +       msleep(30);
> +
> +       return __mtk_hdmi_v2_isr_thread(hdmi);
> +}
> +
> +static int mtk_hdmi_v2_enable(struct mtk_hdmi *hdmi)
> +{
> +       bool was_active = pm_runtime_active(hdmi->dev);

When will it enable twice?

> +       int ret;
> +
> +       ret = pm_runtime_resume_and_get(hdmi->dev);
> +       if (ret) {
> +               dev_err(hdmi->dev, "Cannot resume HDMI\n");
> +               return ret;
> +       }
> +
> +       mtk_hdmi_v2_clk_enable(hdmi);

Check return value.

> +       if (!was_active) {
> +               mtk_hdmi_v2_hw_reset(hdmi);
> +               mtk_hdmi_v2_set_sw_hpd(hdmi, true);
> +       }
> +
> +       return 0;
> +}
> +
> +static void mtk_hdmi_v2_disable(struct mtk_hdmi *hdmi)
> +{
> +       mtk_hdmi_v2_clk_disable(hdmi);
> +       pm_runtime_put_sync(hdmi->dev);
> +}
> +
> +/*
> + * Bridge callbacks
> + */
> +
> +static int mtk_hdmi_v2_bridge_attach(struct drm_bridge *bridge,
> +                                    enum drm_bridge_attach_flags flags)
> +{
> +       struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
> +       int ret;
> +
> +       if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
> +               DRM_ERROR("The flag DRM_BRIDGE_ATTACH_NO_CONNECTOR must be supplied\n");
> +               return -EINVAL;
> +       }
> +       if (hdmi->next_bridge) {
> +               ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge, bridge, flags);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       ret = mtk_hdmi_v2_enable(hdmi);
> +       if (ret)
> +               return ret;
> +
> +       /* Enable Hotplug and Pord pins internal debouncing */
> +       regmap_set_bits(hdmi->regs, HPD_DDC_CTRL,
> +                       HPD_DDC_HPD_DBNC_EN | HPD_DDC_PORD_DBNC_EN);
> +
> +       irq_clear_status_flags(hdmi->irq, IRQ_NOAUTOEN);
> +       enable_irq(hdmi->irq);
> +
> +       /*
> +        * Check if any HDMI monitor was connected before probing this driver
> +        * and/or attaching the bridge, without debouncing: if so, we want to
> +        * notify the DRM so that we start outputting an image ASAP.
> +        * Note that calling the ISR thread function will also perform a HW
> +        * registers write that enables both the HPD and Pord interrupts.
> +        */
> +       __mtk_hdmi_v2_isr_thread(hdmi);
> +
> +       mtk_hdmi_v2_disable(hdmi);
> +
> +       return 0;
> +}
> +
> +static void mtk_hdmi_v2_bridge_detach(struct drm_bridge *bridge)
> +{
> +       struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
> +
> +       WARN_ON(pm_runtime_active(hdmi->dev));
> +
> +       /* The controller is already powered off, just disable irq here */
> +       disable_irq(hdmi->irq);
> +}
> +
> +static void mtk_hdmi_v2_handle_plugged_change(struct mtk_hdmi *hdmi, bool plugged)
> +{
> +       mutex_lock(&hdmi->update_plugged_status_lock);
> +       if (hdmi->plugged_cb && hdmi->codec_dev)
> +               hdmi->plugged_cb(hdmi->codec_dev, plugged);
> +       mutex_unlock(&hdmi->update_plugged_status_lock);
> +}
> +
> +static void mtk_hdmi_v2_bridge_pre_enable(struct drm_bridge *bridge,
> +                                         struct drm_bridge_state *old_state)
> +{
> +       struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
> +       struct drm_atomic_state *state = old_state->base.state;
> +       struct drm_connector_state *conn_state;
> +       union phy_configure_opts opts = {
> +               .dp = { .link_rate = hdmi->mode.clock * KILO }
> +       };
> +       int ret;
> +
> +       /* Power on the controller before trying to write to registers */
> +       ret = mtk_hdmi_v2_enable(hdmi);

In bridge attach, it already call mtk_hdmi_v2_enable(), so it's not necessary to call it here.

> +       if (WARN_ON(ret))
> +               return;
> +
> +       /* Retrieve the connector through the atomic state */
> +       hdmi->curr_conn = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
> +
> +       conn_state = drm_atomic_get_new_connector_state(state, hdmi->curr_conn);
> +       if (WARN_ON(!conn_state))
> +               return;
> +
> +       /*
> +        * Preconfigure the HDMI controller and the HDMI PHY at pre_enable
> +        * stage to make sure that this IP is ready and clocked before the
> +        * mtk_dpi gets powered on and before it enables the output.
> +        */
> +       mtk_hdmi_v2_output_set_display_mode(hdmi, &hdmi->mode);
> +
> +       /* Reconfigure phy clock link with appropriate rate */
> +       phy_configure(hdmi->phy, &opts);
> +
> +       /* Power on the PHY here to make sure that DPI_HDMI is clocked */
> +       phy_power_on(hdmi->phy);
> +
> +       hdmi->powered = true;
> +}
> +
> +static void mtk_hdmi_v2_bridge_enable(struct drm_bridge *bridge,
> +                                     struct drm_bridge_state *old_state)
> +{
> +       struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
> +       struct drm_atomic_state *state = old_state->base.state;
> +       int ret;
> +
> +       if (WARN_ON(!hdmi->powered))
> +               return;
> +
> +       ret = drm_atomic_helper_connector_hdmi_update_infoframes(hdmi->curr_conn, state);
> +       if (ret)
> +               dev_err(hdmi->dev, "Could not update infoframes: %d\n", ret);
> +
> +       mtk_hdmi_v2_hw_vid_mute(hdmi, false);
> +
> +       /* signal the connect event to audio codec */
> +       mtk_hdmi_v2_handle_plugged_change(hdmi, true);

Why plugged parameter is true?

> +
> +       hdmi->enabled = true;
> +}
> +
> +static void mtk_hdmi_v2_bridge_disable(struct drm_bridge *bridge,
> +                                      struct drm_bridge_state *old_bridge_state)
> +{
> +       struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
> +
> +       if (!hdmi->enabled)
> +               return;
> +
> +       mtk_hdmi_v2_hw_av_mute(hdmi, true);
> +       msleep(50);
> +       mtk_hdmi_v2_hw_vid_mute(hdmi, true);
> +       mtk_hdmi_v2_hw_aud_mute(hdmi, true);
> +       mtk_hdmi_v2_disable_hdcp_encrypt(hdmi);

You never enable encrypt, why disable it?
So drop this.

> +       msleep(50);
> +
> +       hdmi->enabled = false;
> +}
> +
> +static void mtk_hdmi_v2_bridge_post_disable(struct drm_bridge *bridge,
> +                                           struct drm_bridge_state *old_state)
> +{
> +       struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
> +
> +       if (!hdmi->powered)
> +               return;
> +
> +       /* Disable VSync interrupt */
> +       regmap_clear_bits(hdmi->regs, TOP_INT_ENABLE00, HDMI_VSYNC_INT);

You never enable vsync interrupt, so this disable is redundant.

> +
> +       phy_power_off(hdmi->phy);
> +       hdmi->powered = false;
> +
> +       /* signal the disconnect event to audio codec */
> +       mtk_hdmi_v2_handle_plugged_change(hdmi, false);
> +
> +       /* Power off */
> +       mtk_hdmi_v2_disable(hdmi);
> +}
> +
> +static enum drm_connector_status mtk_hdmi_v2_bridge_detect(struct drm_bridge *bridge)
> +{
> +       struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
> +
> +       return hdmi->hpd != HDMI_PLUG_OUT ?
> +              connector_status_connected : connector_status_disconnected;
> +}
> +
> +static const struct drm_edid *mtk_hdmi_v2_bridge_edid_read(struct drm_bridge *bridge,
> +                                                          struct drm_connector *connector)
> +{
> +       return drm_edid_read(connector);
> +}
> +
> +static void mtk_hdmi_v2_hpd_enable(struct drm_bridge *bridge)
> +{
> +       struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
> +       int ret;
> +
> +       ret = mtk_hdmi_v2_enable(hdmi);
> +       if (ret) {
> +               dev_err(hdmi->dev, "Cannot power on controller for HPD: %d\n", ret);
> +               return;
> +       }
> +
> +       mtk_hdmi_v2_enable_hpd_pord_irq(hdmi, true);
> +}
> +
> +static void mtk_hdmi_v2_hpd_disable(struct drm_bridge *bridge)
> +{
> +       struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
> +
> +       mtk_hdmi_v2_enable_hpd_pord_irq(hdmi, false);
> +       mtk_hdmi_v2_disable(hdmi);
> +}
> +
> +static int mtk_hdmi_v2_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
> +                                                const struct drm_display_mode *mode,
> +                                                unsigned long long tmds_rate)
> +{
> +       if (mode->clock < MTK_HDMI_V2_CLOCK_MIN)
> +               return MODE_CLOCK_LOW;
> +       else if (mode->clock > MTK_HDMI_V2_CLOCK_MAX)
> +               return MODE_CLOCK_HIGH;
> +       else
> +               return MODE_OK;
> +}
> +
> +static int mtk_hdmi_v2_hdmi_clear_infoframe(struct drm_bridge *bridge,
> +                                           enum hdmi_infoframe_type type)
> +{
> +       struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
> +
> +       switch (type) {
> +       case HDMI_INFOFRAME_TYPE_AUDIO:
> +               regmap_clear_bits(hdmi->regs, TOP_INFO_EN, AUD_EN_WR | AUD_EN);
> +               regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, AUD_RPT_EN);
> +               break;
> +       case HDMI_INFOFRAME_TYPE_AVI:
> +               regmap_clear_bits(hdmi->regs, TOP_INFO_EN, AVI_EN_WR | AVI_EN);
> +               regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, AVI_RPT_EN);
> +               break;
> +       case HDMI_INFOFRAME_TYPE_SPD:
> +               regmap_clear_bits(hdmi->regs, TOP_INFO_EN, SPD_EN_WR | SPD_EN);
> +               regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, SPD_RPT_EN);
> +               break;
> +       case HDMI_INFOFRAME_TYPE_VENDOR:
> +               regmap_clear_bits(hdmi->regs, TOP_INFO_EN, VSIF_EN_WR | VSIF_EN);
> +               regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, VSIF_RPT_EN);
> +               break;
> +       case HDMI_INFOFRAME_TYPE_DRM:
> +       default:
> +               break;
> +       };
> +
> +       return 0;
> +}
> +
> +static int mtk_hdmi_v2_hdmi_write_infoframe(struct drm_bridge *bridge,
> +                                           enum hdmi_infoframe_type type,
> +                                           const u8 *buffer, size_t len)
> +{
> +       struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
> +
> +       switch (type) {
> +       case HDMI_INFOFRAME_TYPE_AUDIO:
> +               mtk_hdmi_v2_hw_write_audio_infoframe(hdmi, buffer);
> +               break;
> +       case HDMI_INFOFRAME_TYPE_AVI:
> +               mtk_hdmi_v2_hw_write_avi_infoframe(hdmi, buffer);
> +               break;
> +       case HDMI_INFOFRAME_TYPE_SPD:
> +               mtk_hdmi_v2_hw_write_spd_infoframe(hdmi, buffer);
> +               break;
> +       case HDMI_INFOFRAME_TYPE_VENDOR:
> +               mtk_hdmi_v2_hw_write_vendor_infoframe(hdmi, buffer);
> +               break;
> +       case HDMI_INFOFRAME_TYPE_DRM:
> +       default:
> +               dev_err(hdmi->dev, "Unsupported HDMI infoframe type %u\n", type);
> +               break;
> +       };
> +
> +       return 0;
> +}
> +
> +static const struct drm_bridge_funcs mtk_v2_hdmi_bridge_funcs = {
> +       .attach = mtk_hdmi_v2_bridge_attach,
> +       .detach = mtk_hdmi_v2_bridge_detach,
> +       .mode_fixup = mtk_hdmi_bridge_mode_fixup,
> +       .mode_set = mtk_hdmi_bridge_mode_set,
> +       .atomic_pre_enable = mtk_hdmi_v2_bridge_pre_enable,
> +       .atomic_enable = mtk_hdmi_v2_bridge_enable,
> +       .atomic_disable = mtk_hdmi_v2_bridge_disable,
> +       .atomic_post_disable = mtk_hdmi_v2_bridge_post_disable,
> +       .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> +       .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
> +       .atomic_reset = drm_atomic_helper_bridge_reset,
> +       .detect = mtk_hdmi_v2_bridge_detect,
> +       .edid_read = mtk_hdmi_v2_bridge_edid_read,
> +       .hpd_enable = mtk_hdmi_v2_hpd_enable,
> +       .hpd_disable = mtk_hdmi_v2_hpd_disable,
> +       .hdmi_tmds_char_rate_valid = mtk_hdmi_v2_hdmi_tmds_char_rate_valid,
> +       .hdmi_clear_infoframe = mtk_hdmi_v2_hdmi_clear_infoframe,
> +       .hdmi_write_infoframe = mtk_hdmi_v2_hdmi_write_infoframe,
> +};
> +
> +/*
> + * HDMI audio codec callbacks
> + */
> +static int mtk_hdmi_v2_audio_hook_plugged_cb(struct device *dev, void *data,
> +                                            hdmi_codec_plugged_cb fn,
> +                                            struct device *codec_dev)
> +{
> +       struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
> +       bool plugged;
> +
> +       if (!hdmi)
> +               return -ENODEV;
> +
> +       mtk_hdmi_audio_set_plugged_cb(hdmi, fn, codec_dev);
> +       plugged = (hdmi->hpd == HDMI_PLUG_IN_AND_SINK_POWER_ON);
> +       mtk_hdmi_v2_handle_plugged_change(hdmi, plugged);
> +
> +       return 0;
> +}
> +
> +static int mtk_hdmi_v2_audio_hw_params(struct device *dev, void *data,
> +                                      struct hdmi_codec_daifmt *daifmt,
> +                                      struct hdmi_codec_params *params)
> +{
> +       struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
> +
> +       if (hdmi->audio_enable) {
> +               mtk_hdmi_audio_params(hdmi, daifmt, params);
> +               mtk_hdmi_v2_aud_output_config(hdmi, &hdmi->mode);
> +       }
> +       return 0;
> +}
> +
> +static int mtk_hdmi_v2_audio_startup(struct device *dev, void *data)
> +{
> +       struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
> +
> +       mtk_hdmi_v2_hw_aud_enable(hdmi, true);
> +       hdmi->audio_enable = true;
> +
> +       return 0;
> +}
> +
> +static void mtk_hdmi_v2_audio_shutdown(struct device *dev, void *data)
> +{
> +       struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
> +
> +       hdmi->audio_enable = false;
> +       mtk_hdmi_v2_hw_aud_enable(hdmi, false);
> +}
> +
> +static int mtk_hdmi_v2_audio_mute(struct device *dev, void *data, bool enable, int dir)
> +{
> +       struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
> +
> +       mtk_hdmi_v2_hw_aud_mute(hdmi, enable);
> +
> +       return 0;
> +}
> +
> +static const struct hdmi_codec_ops mtk_hdmi_v2_audio_codec_ops = {
> +       .hw_params = mtk_hdmi_v2_audio_hw_params,
> +       .audio_startup = mtk_hdmi_v2_audio_startup,
> +       .audio_shutdown = mtk_hdmi_v2_audio_shutdown,
> +       .mute_stream = mtk_hdmi_v2_audio_mute,
> +       .get_eld = mtk_hdmi_audio_get_eld,
> +       .hook_plugged_cb = mtk_hdmi_v2_audio_hook_plugged_cb,
> +};
> +
> +static __maybe_unused int mtk_hdmi_v2_suspend(struct device *dev)
> +{
> +       struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
> +
> +       mtk_hdmi_v2_disable(hdmi);
> +
> +       return 0;
> +}
> +
> +static __maybe_unused int mtk_hdmi_v2_resume(struct device *dev)
> +{
> +       struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
> +       int ret;
> +
> +       pm_runtime_get_sync(dev);
> +
> +       ret = mtk_hdmi_v2_clk_enable(hdmi);
> +       if (ret)
> +               return ret;
> +
> +       mtk_hdmi_v2_enable_hpd_pord_irq(hdmi, true);

I expect the things in suspend and resume would symmetric.
Suspend does only mtk_hdmi_v2_disable(), so resume should only mtk_hdmi_v2_enable().

Regards,
CK

> +
> +       return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(mtk_hdmi_v2_pm_ops, mtk_hdmi_v2_suspend, mtk_hdmi_v2_resume);
> +
> +static const struct mtk_hdmi_ver_conf mtk_hdmi_conf_v2 = {
> +       .bridge_funcs = &mtk_v2_hdmi_bridge_funcs,
> +       .codec_ops = &mtk_hdmi_v2_audio_codec_ops,
> +       .mtk_hdmi_clock_names = mtk_hdmi_v2_clk_names,
> +       .num_clocks = MTK_HDMI_V2_CLK_COUNT,
> +};
> +
> +static const struct mtk_hdmi_conf mtk_hdmi_conf_mt8188 = {
> +       .ver_conf = &mtk_hdmi_conf_v2,
> +       .reg_hdmi_tx_cfg = HDMITX_CONFIG_MT8188
> +};
> +
> +static const struct mtk_hdmi_conf mtk_hdmi_conf_mt8195 = {
> +       .ver_conf = &mtk_hdmi_conf_v2,
> +       .reg_hdmi_tx_cfg = HDMITX_CONFIG_MT8195
> +};
> +
> +static int mtk_hdmi_v2_probe(struct platform_device *pdev)
> +{
> +       struct mtk_hdmi *hdmi;
> +       int ret;
> +
> +       hdmi = mtk_hdmi_common_probe(pdev);
> +       if (IS_ERR(hdmi))
> +               return PTR_ERR(hdmi);
> +
> +       hdmi->hpd = HDMI_PLUG_OUT;
> +
> +       /*
> +        * Disable all HW interrupts at probe stage and install the ISR
> +        * but keep it disabled, as the rest of the interrupts setup is
> +        * done in the .bridge_attach() callback, which will enable both
> +        * the right HW IRQs and the ISR.
> +        */
> +       mtk_hdmi_v2_hwirq_disable(hdmi);
> +       irq_set_status_flags(hdmi->irq, IRQ_NOAUTOEN);
> +       ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq, mtk_hdmi_v2_isr,
> +                                       mtk_hdmi_v2_isr_thread,
> +                                       IRQ_TYPE_LEVEL_HIGH,
> +                                       dev_name(&pdev->dev), hdmi);
> +       if (ret)
> +               return dev_err_probe(&pdev->dev, ret, "Cannot request IRQ\n");
> +
> +       ret = devm_pm_runtime_enable(&pdev->dev);
> +       if (ret)
> +               return dev_err_probe(&pdev->dev, ret, "Cannot enable Runtime PM\n");
> +
> +       return 0;
> +}
> +
> +static void mtk_hdmi_v2_remove(struct platform_device *pdev)
> +{
> +       struct mtk_hdmi *hdmi = platform_get_drvdata(pdev);
> +
> +       i2c_put_adapter(hdmi->ddc_adpt);
> +}
> +
> +static const struct of_device_id mtk_drm_hdmi_v2_of_ids[] = {
> +       { .compatible = "mediatek,mt8188-hdmi-tx", .data = &mtk_hdmi_conf_mt8188 },
> +       { .compatible = "mediatek,mt8195-hdmi-tx", .data = &mtk_hdmi_conf_mt8195 },
> +       { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, mtk_drm_hdmi_v2_of_ids);
> +
> +static struct platform_driver mtk_hdmi_v2_driver = {
> +       .probe = mtk_hdmi_v2_probe,
> +       .remove = mtk_hdmi_v2_remove,
> +       .driver = {
> +               .name = "mediatek-drm-hdmi-v2",
> +               .of_match_table = mtk_drm_hdmi_v2_of_ids,
> +               .pm = &mtk_hdmi_v2_pm_ops,
> +       },
> +};
> +module_platform_driver(mtk_hdmi_v2_driver);
> +
> +MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@xxxxxxxxxxxxx>>");
> +MODULE_DESCRIPTION("MediaTek HDMIv2 Driver");
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("DRM_MTK_HDMI");
> --
> 2.48.1
> 





[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux