#include "dc_bios_types.h"
#include "dcn30/dcn30_dio_stream_encoder.h"
#include "dcn32/dcn32_dio_stream_encoder.h"
#include "dcn35/dcn35_dio_stream_encoder.h"
#include "dcn401/dcn401_dio_stream_encoder.h"
#include "dcn31/dcn31_apg.h"
#include "dcn42_dio_stream_encoder.h"
#include "reg_helper.h"
#include "hw_shared.h"
#include "link_service.h"
#include "dpcd_defs.h"
#define DC_LOGGER \
enc1->base.ctx->logger
#define REG(reg)\
(enc1->regs->reg)
#undef FN
#define FN(reg_name, field_name) \
(uint8_t)enc1->se_shift->field_name, enc1->se_mask->field_name
#define VBI_LINE_0 0
#define HDMI_CLOCK_CHANNEL_RATE_MORE_340M 340000
#define CTX \
enc1->base.ctx
static void enc42_stream_encoder_hdmi_set_stream_attribute(
struct stream_encoder *enc,
struct dc_crtc_timing *crtc_timing,
int actual_pix_clk_khz,
bool enable_audio)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
if (!enc->ctx->dc->debug.avoid_vbios_exec_table) {
struct bp_encoder_control cntl = {0};
cntl.action = ENCODER_CONTROL_SETUP;
cntl.engine_id = enc1->base.id;
cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A;
cntl.enable_dp_audio = enable_audio;
cntl.pixel_clock = actual_pix_clk_khz;
cntl.lanes_number = LANE_COUNT_FOUR;
if (enc1->base.bp->funcs->encoder_control(
enc1->base.bp, &cntl) != BP_RESULT_OK)
return;
} else {
REG_UPDATE(DIG_CLOCK_PATTERN, DIG_CLOCK_PATTERN, 0x1F);
}
enc401_stream_encoder_set_stream_attribute_helper(enc1, crtc_timing);
REG_UPDATE_4(HDMI_CONTROL,
HDMI_DEEP_COLOR_ENABLE, 0,
HDMI_DATA_SCRAMBLE_EN, 0,
HDMI_NO_EXTRA_NULL_PACKET_FILLED, 1,
HDMI_CLOCK_CHANNEL_RATE, 0);
switch (crtc_timing->display_color_depth) {
case COLOR_DEPTH_888:
REG_UPDATE(HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 0);
break;
case COLOR_DEPTH_101010:
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DEEP_COLOR_DEPTH, 1,
HDMI_DEEP_COLOR_ENABLE, 0);
} else {
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DEEP_COLOR_DEPTH, 1,
HDMI_DEEP_COLOR_ENABLE, 1);
}
break;
case COLOR_DEPTH_121212:
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DEEP_COLOR_DEPTH, 2,
HDMI_DEEP_COLOR_ENABLE, 0);
} else {
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DEEP_COLOR_DEPTH, 2,
HDMI_DEEP_COLOR_ENABLE, 1);
}
break;
case COLOR_DEPTH_161616:
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DEEP_COLOR_DEPTH, 3,
HDMI_DEEP_COLOR_ENABLE, 1);
break;
default:
break;
}
if (actual_pix_clk_khz >= HDMI_CLOCK_CHANNEL_RATE_MORE_340M) {
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DATA_SCRAMBLE_EN, 1,
HDMI_CLOCK_CHANNEL_RATE, 1);
} else if (crtc_timing->flags.LTE_340MCSC_SCRAMBLE) {
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DATA_SCRAMBLE_EN, 1,
HDMI_CLOCK_CHANNEL_RATE, 0);
}
REG_UPDATE_3(HDMI_VBI_PACKET_CONTROL,
HDMI_GC_CONT, 1,
HDMI_GC_SEND, 1,
HDMI_NULL_SEND, 1);
REG_UPDATE(HDMI_VBI_PACKET_CONTROL, HDMI_ACP_SEND, 0);
REG_UPDATE(HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_SEND, 1);
REG_UPDATE(HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_LINE,
VBI_LINE_0 + 2);
REG_UPDATE(HDMI_GC, HDMI_GC_AVMUTE, 0);
}
static void enc42_stream_encoder_stop_dp_info_packets(
struct stream_encoder *enc)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
uint32_t value = 0;
REG_SET_9(DP_SEC_CNTL, 0,
DP_SEC_GSP0_ENABLE, 0,
DP_SEC_GSP1_ENABLE, 0,
DP_SEC_GSP2_ENABLE, 0,
DP_SEC_GSP3_ENABLE, 0,
DP_SEC_GSP4_ENABLE, 0,
DP_SEC_GSP5_ENABLE, 0,
DP_SEC_GSP6_ENABLE, 0,
DP_SEC_GSP7_ENABLE, 0,
DP_SEC_STREAM_ENABLE, 0);
value = REG_READ(DP_SEC_CNTL);
if (value)
REG_UPDATE(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1);
}
static void enc42_stream_encoder_update_hdmi_info_packets(
struct stream_encoder *enc,
const struct encoder_info_frame *info_frame)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
REG_UPDATE(HDMI_DB_CONTROL, HDMI_DB_DISABLE, 1);
REG_UPDATE(DIG_FE_AUDIO_CNTL, APG_CLOCK_ENABLE, 1);
enc3_update_hdmi_info_packet(enc1, 0, &info_frame->avi);
enc3_update_hdmi_info_packet(enc1, 5, &info_frame->hfvsif);
enc3_update_hdmi_info_packet(enc1, 2, &info_frame->gamut);
enc3_update_hdmi_info_packet(enc1, 1, &info_frame->vendor);
enc3_update_hdmi_info_packet(enc1, 3, &info_frame->spd);
enc3_update_hdmi_info_packet(enc1, 4, &info_frame->hdrsmd);
enc3_update_hdmi_info_packet(enc1, 6, &info_frame->vtem);
}
static void enc42_dp_set_dsc_pps_info_packet(struct stream_encoder *enc,
bool enable,
uint8_t *dsc_packed_pps,
bool immediate_update)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
if (enable) {
struct dc_info_packet pps_sdp;
int i;
REG_UPDATE(DP_SEC_CNTL2, DP_SEC_GSP11_PPS, 1);
pps_sdp.valid = true;
pps_sdp.hb0 = 0;
pps_sdp.hb1 = DC_DP_INFOFRAME_TYPE_PPS;
pps_sdp.hb2 = 127;
pps_sdp.hb3 = 0;
for (i = 0; i < 4; i++) {
memcpy(pps_sdp.sb, &dsc_packed_pps[i * 32], 32);
enc1->base.vpg->funcs->update_generic_info_packet(
enc1->base.vpg,
11 + i,
&pps_sdp,
immediate_update);
}
REG_UPDATE(DP_GSP11_CNTL,
DP_SEC_GSP11_LINE_NUM, 2);
REG_UPDATE_2(DP_MSA_VBID_MISC,
DP_VBID6_LINE_REFERENCE, 0,
DP_VBID6_LINE_NUM, 3);
REG_UPDATE(DP_GSP11_CNTL,
DP_SEC_GSP11_ENABLE, 1);
REG_UPDATE(DP_SEC_CNTL,
DP_SEC_STREAM_ENABLE, 1);
} else {
REG_UPDATE(DP_GSP11_CNTL, DP_SEC_GSP11_ENABLE, 0);
REG_UPDATE(DP_SEC_CNTL2, DP_SEC_GSP11_PPS, 0);
}
}
static void enc42_se_dp_audio_setup(
struct stream_encoder *enc,
unsigned int az_inst,
struct audio_info *info)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
enc42_se_enable_audio_clock(enc, true);
REG_UPDATE(DIG_FE_AUDIO_CNTL,
DIG_FE_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, az_inst);
enc->apg->funcs->se_audio_setup(enc->apg, az_inst, info);
}
#define DP_SEC_AUD_N__DP_SEC_AUD_N__DEFAULT 0x8000
#define DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUTO_CALC 1
static void enc42_se_setup_dp_audio(
struct stream_encoder *enc)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
REG_SET(DP_SEC_AUD_N, 0,
DP_SEC_AUD_N, DP_SEC_AUD_N__DP_SEC_AUD_N__DEFAULT);
REG_SET(DP_SEC_TIMESTAMP, 0, DP_SEC_TIMESTAMP_MODE,
DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUTO_CALC);
}
static void enc42_se_dp_audio_enable(
struct stream_encoder *enc)
{
ASSERT (enc->apg);
enc42_se_enable_audio_clock(enc, true);
enc42_se_setup_dp_audio(enc);
enc1_se_enable_dp_audio(enc);
enc->apg->funcs->enable_apg(enc->apg);
}
static void enc42_se_disable_dp_audio(
struct stream_encoder *enc)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
uint32_t value = 0;
REG_UPDATE_5(DP_SEC_CNTL,
DP_SEC_ASP_ENABLE, 0,
DP_SEC_ATP_ENABLE, 0,
DP_SEC_AIP_ENABLE, 0,
DP_SEC_ACM_ENABLE, 0,
DP_SEC_STREAM_ENABLE, 0);
value = REG_READ(DP_SEC_CNTL);
if (value != 0)
REG_UPDATE(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1);
}
static void enc42_se_dp_audio_disable(
struct stream_encoder *enc)
{
enc->apg->funcs->disable_apg(enc->apg);
enc42_se_disable_dp_audio(enc);
enc42_se_enable_audio_clock(enc, false);
}
static void enc42_se_setup_hdmi_audio(
struct stream_encoder *enc,
const struct audio_crtc_info *crtc_info)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
struct audio_clock_info audio_clock_info = {0};
REG_UPDATE(HDMI_AUDIO_PACKET_CONTROL,
HDMI_AUDIO_DELAY_EN, 1);
REG_UPDATE_2(HDMI_ACR_PACKET_CONTROL,
HDMI_ACR_AUTO_SEND, 1,
HDMI_ACR_SOURCE, 0);
get_audio_clock_info(crtc_info->color_depth,
crtc_info->requested_pixel_clock_100Hz,
crtc_info->calculated_pixel_clock_100Hz,
&audio_clock_info);
DC_LOG_HW_AUDIO("\n%s:Input::requested_pixel_clock_100Hz = %d" \
"calculated_pixel_clock_100Hz = %d\n", __func__,\
crtc_info->requested_pixel_clock_100Hz, \
crtc_info->calculated_pixel_clock_100Hz);
REG_UPDATE(HDMI_ACR_32_0, HDMI_ACR_CTS_32, audio_clock_info.cts_32khz);
REG_UPDATE(HDMI_ACR_32_1, HDMI_ACR_N_32, audio_clock_info.n_32khz);
REG_UPDATE(HDMI_ACR_44_0, HDMI_ACR_CTS_44, audio_clock_info.cts_44khz);
REG_UPDATE(HDMI_ACR_44_1, HDMI_ACR_N_44, audio_clock_info.n_44khz);
REG_UPDATE(HDMI_ACR_48_0, HDMI_ACR_CTS_48, audio_clock_info.cts_48khz);
REG_UPDATE(HDMI_ACR_48_1, HDMI_ACR_N_48, audio_clock_info.n_48khz);
}
static void enc42_se_hdmi_audio_disable(
struct stream_encoder *enc)
{
ASSERT (enc->apg);
enc->apg->funcs->disable_apg(enc->apg);
enc42_se_enable_audio_clock(enc, false);
}
void enc42_se_enable_audio_clock(
struct stream_encoder *enc,
bool enable)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
REG_UPDATE(DIG_FE_AUDIO_CNTL, APG_CLOCK_ENABLE, enable);
}
static void enc42_se_hdmi_audio_setup(
struct stream_encoder *enc,
unsigned int az_inst,
struct audio_info *info,
struct audio_crtc_info *audio_crtc_info)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
ASSERT (enc->apg);
enc42_se_enable_audio_clock(enc, true);
enc42_se_setup_hdmi_audio(enc, audio_crtc_info);
REG_UPDATE(DIG_FE_AUDIO_CNTL,
DIG_FE_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, az_inst);
enc->apg->funcs->se_audio_setup(enc->apg, az_inst, info);
enc->apg->funcs->enable_apg(enc->apg);
}
static void enc42_audio_mute_control(
struct stream_encoder *enc,
bool mute)
{
if (mute)
enc->apg->funcs->disable_apg(enc->apg);
else
enc->apg->funcs->enable_apg(enc->apg);
}
void enc42_reset_hdmi_stream_attribute(
struct stream_encoder *enc)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
REG_UPDATE_3(HDMI_CONTROL,
HDMI_DEEP_COLOR_ENABLE, 0,
HDMI_DATA_SCRAMBLE_EN, 0,
HDMI_CLOCK_CHANNEL_RATE, 0);
}
bool enc42_dio_get_uncompressed_dp_pixel_format(
struct stream_encoder *enc,
enum dc_pixel_encoding *encoding,
enum dc_color_depth *depth)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
uint32_t is_compressed_pixel_format, uncompressed_component_depth, uncompressed_pixel_format, compressed_pixel_format;
if (enc == NULL || encoding == NULL || depth == NULL)
return false;
REG_GET_4(DP_PIXEL_FORMAT,
PIXEL_ENCODING_TYPE, &is_compressed_pixel_format,
UNCOMPRESSED_COMPONENT_DEPTH, &uncompressed_component_depth,
UNCOMPRESSED_PIXEL_FORMAT, &uncompressed_pixel_format,
COMPRESSED_PIXEL_FORMAT, &compressed_pixel_format);
if (!is_compressed_pixel_format) {
switch (uncompressed_component_depth) {
case DP_COMPONENT_PIXEL_DEPTH_6BPC:
*depth = COLOR_DEPTH_666;
break;
case DP_COMPONENT_PIXEL_DEPTH_8BPC:
*depth = COLOR_DEPTH_888;
break;
case DP_COMPONENT_PIXEL_DEPTH_10BPC:
*depth = COLOR_DEPTH_101010;
break;
case DP_COMPONENT_PIXEL_DEPTH_12BPC:
*depth = COLOR_DEPTH_121212;
break;
case DP_COMPONENT_PIXEL_DEPTH_16BPC:
*depth = COLOR_DEPTH_161616;
break;
default:
*depth = COLOR_DEPTH_UNDEFINED;
break;
}
switch (uncompressed_pixel_format) {
case DP_PIXEL_ENCODING_TYPE_RGB444:
*encoding = PIXEL_ENCODING_RGB;
break;
case DP_PIXEL_ENCODING_TYPE_YCBCR422:
*encoding = PIXEL_ENCODING_YCBCR422;
break;
case DP_PIXEL_ENCODING_TYPE_YCBCR444:
case DP_PIXEL_ENCODING_TYPE_Y_ONLY:
*encoding = PIXEL_ENCODING_YCBCR444;
break;
case DP_PIXEL_ENCODING_TYPE_YCBCR420:
*encoding = PIXEL_ENCODING_YCBCR420;
break;
default:
*encoding = PIXEL_ENCODING_UNDEFINED;
break;
}
}
return true;
}
static const struct stream_encoder_funcs dcn42_str_enc_funcs = {
.dp_set_stream_attribute =
enc401_stream_encoder_dp_set_stream_attribute,
.hdmi_set_stream_attribute =
enc42_stream_encoder_hdmi_set_stream_attribute,
.dvi_set_stream_attribute =
enc401_stream_encoder_dvi_set_stream_attribute,
.set_throttled_vcp_size =
enc1_stream_encoder_set_throttled_vcp_size,
.update_hdmi_info_packets =
enc42_stream_encoder_update_hdmi_info_packets,
.stop_hdmi_info_packets =
enc3_stream_encoder_stop_hdmi_info_packets,
.update_dp_info_packets_sdp_line_num =
enc3_stream_encoder_update_dp_info_packets_sdp_line_num,
.update_dp_info_packets =
enc3_stream_encoder_update_dp_info_packets,
.stop_dp_info_packets =
enc42_stream_encoder_stop_dp_info_packets,
.dp_blank =
enc1_stream_encoder_dp_blank,
.dp_unblank =
enc401_stream_encoder_dp_unblank,
.audio_mute_control = enc42_audio_mute_control,
.dp_audio_setup = enc42_se_dp_audio_setup,
.dp_audio_enable = enc42_se_dp_audio_enable,
.dp_audio_disable = enc42_se_dp_audio_disable,
.hdmi_audio_setup = enc42_se_hdmi_audio_setup,
.hdmi_audio_disable = enc42_se_hdmi_audio_disable,
.setup_stereo_sync = enc1_setup_stereo_sync,
.set_avmute = enc1_stream_encoder_set_avmute,
.dig_connect_to_otg = enc1_dig_connect_to_otg,
.dig_source_otg = enc1_dig_source_otg,
.dp_get_pixel_format = enc42_dio_get_uncompressed_dp_pixel_format,
.enc_read_state = enc401_read_state,
.dp_set_dsc_config = NULL,
.dp_set_dsc_pps_info_packet = enc42_dp_set_dsc_pps_info_packet,
.set_dynamic_metadata = enc401_set_dynamic_metadata,
.hdmi_reset_stream_attribute = enc42_reset_hdmi_stream_attribute,
.enable_stream = enc401_stream_encoder_enable,
.set_input_mode = enc401_set_dig_input_mode,
.enable_fifo = enc35_enable_fifo,
.disable_fifo = enc35_disable_fifo,
.map_stream_to_link = enc401_stream_encoder_map_to_link,
};
void dcn42_dio_stream_encoder_construct(
struct dcn10_stream_encoder *enc1,
struct dc_context *ctx,
struct dc_bios *bp,
enum engine_id eng_id,
struct vpg *vpg,
struct apg *apg,
const struct dcn10_stream_enc_registers *regs,
const struct dcn10_stream_encoder_shift *se_shift,
const struct dcn10_stream_encoder_mask *se_mask)
{
enc1->base.funcs = &dcn42_str_enc_funcs;
enc1->base.ctx = ctx;
enc1->base.id = eng_id;
enc1->base.bp = bp;
enc1->base.vpg = vpg;
enc1->base.apg = apg;
enc1->regs = regs;
enc1->se_shift = se_shift;
enc1->se_mask = se_mask;
enc1->base.stream_enc_inst = vpg->inst;
}