/* * Copyright 2012-15 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: AMD *
*/
staticvoid dce110_update_generic_info_packet( struct dce110_stream_encoder *enc110,
uint32_t packet_index, conststruct dc_info_packet *info_packet)
{ /* TODOFPGA Figure out a proper number for max_retries polling for lock * use 50 for now.
*/
uint32_t max_retries = 50;
/*we need turn on clock before programming AFMT block*/ if (REG(AFMT_CNTL))
REG_UPDATE(AFMT_CNTL, AFMT_AUDIO_CLOCK_EN, 1);
if (REG(AFMT_VBI_PACKET_CONTROL1)) { if (packet_index >= 8)
ASSERT(0);
/* poll dig_update_lock is not locked -> asic internal signal * assume otg master lock will unlock it
*/ /* REG_WAIT(AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_LOCK_STATUS,
0, 10, max_retries);*/
/* HW does is not reading GSP memory not reading too long -> * something wrong. clear GPS memory access and notify? * hw SW is writing to GSP memory
*/
REG_UPDATE(AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_CONFLICT_CLR, 1);
} /* choose which generic packet to use */
{
REG_READ(AFMT_VBI_PACKET_CONTROL);
REG_UPDATE(AFMT_VBI_PACKET_CONTROL,
AFMT_GENERIC_INDEX, packet_index);
}
if (info_packet->valid) {
dce110_update_generic_info_packet(
enc110,
packet_index,
info_packet);
/* enable transmission of packet(s) -
* packet transmission begins on the next frame */
cont = 1; /* send packet(s) every frame */
send = 1; /* select line number to send packets on */
line = 2;
} else {
cont = 0;
send = 0;
line = 0;
}
/* choose which generic packet control to use */ switch (packet_index) { case 0:
REG_UPDATE_3(HDMI_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC0_CONT, cont,
HDMI_GENERIC0_SEND, send,
HDMI_GENERIC0_LINE, line); break; case 1:
REG_UPDATE_3(HDMI_GENERIC_PACKET_CONTROL0,
HDMI_GENERIC1_CONT, cont,
HDMI_GENERIC1_SEND, send,
HDMI_GENERIC1_LINE, line); break; case 2:
REG_UPDATE_3(HDMI_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC0_CONT, cont,
HDMI_GENERIC0_SEND, send,
HDMI_GENERIC0_LINE, line); break; case 3:
REG_UPDATE_3(HDMI_GENERIC_PACKET_CONTROL1,
HDMI_GENERIC1_CONT, cont,
HDMI_GENERIC1_SEND, send,
HDMI_GENERIC1_LINE, line); break; case 4: if (REG(HDMI_GENERIC_PACKET_CONTROL2))
REG_UPDATE_3(HDMI_GENERIC_PACKET_CONTROL2,
HDMI_GENERIC0_CONT, cont,
HDMI_GENERIC0_SEND, send,
HDMI_GENERIC0_LINE, line); break; case 5: if (REG(HDMI_GENERIC_PACKET_CONTROL2))
REG_UPDATE_3(HDMI_GENERIC_PACKET_CONTROL2,
HDMI_GENERIC1_CONT, cont,
HDMI_GENERIC1_SEND, send,
HDMI_GENERIC1_LINE, line); break; case 6: if (REG(HDMI_GENERIC_PACKET_CONTROL3))
REG_UPDATE_3(HDMI_GENERIC_PACKET_CONTROL3,
HDMI_GENERIC0_CONT, cont,
HDMI_GENERIC0_SEND, send,
HDMI_GENERIC0_LINE, line); break; case 7: if (REG(HDMI_GENERIC_PACKET_CONTROL3))
REG_UPDATE_3(HDMI_GENERIC_PACKET_CONTROL3,
HDMI_GENERIC1_CONT, cont,
HDMI_GENERIC1_SEND, send,
HDMI_GENERIC1_LINE, line); break; default: /* invalid HW packet index */
DC_LOG_WARNING( "Invalid HW packet index: %s()\n",
__func__); return;
}
}
struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); struct dc_crtc_timing hw_crtc_timing = *crtc_timing; if (hw_crtc_timing.flags.INTERLACE) { /*the input timing is in VESA spec format with Interlace flag =1*/
hw_crtc_timing.v_total /= 2;
hw_crtc_timing.v_border_top /= 2;
hw_crtc_timing.v_addressable /= 2;
hw_crtc_timing.v_border_bottom /= 2;
hw_crtc_timing.v_front_porch /= 2;
hw_crtc_timing.v_sync_width /= 2;
} /* set pixel encoding */ switch (hw_crtc_timing.pixel_encoding) { case PIXEL_ENCODING_YCBCR422:
REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING,
DP_PIXEL_ENCODING_TYPE_YCBCR422); break; case PIXEL_ENCODING_YCBCR444:
REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING,
DP_PIXEL_ENCODING_TYPE_YCBCR444);
if (hw_crtc_timing.flags.Y_ONLY) if (hw_crtc_timing.display_color_depth != COLOR_DEPTH_666) /* HW testing only, no use case yet. * Color depth of Y-only could be
* 8, 10, 12, 16 bits */
REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING,
DP_PIXEL_ENCODING_TYPE_Y_ONLY); /* Note: DP_MSA_MISC1 bit 7 is the indicator * of Y-only mode. * This bit is set in HW if register
* DP_PIXEL_ENCODING is programmed to 0x4 */ break; case PIXEL_ENCODING_YCBCR420:
REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING,
DP_PIXEL_ENCODING_TYPE_YCBCR420); if (enc110->se_mask->DP_VID_M_DOUBLE_VALUE_EN)
REG_UPDATE(DP_VID_TIMING, DP_VID_M_DOUBLE_VALUE_EN, 1);
switch (hw_crtc_timing.display_color_depth) { case COLOR_DEPTH_666:
colorimetry_bpc = 0; break; case COLOR_DEPTH_888:
colorimetry_bpc = 1; break; case COLOR_DEPTH_101010:
colorimetry_bpc = 2; break; case COLOR_DEPTH_121212:
colorimetry_bpc = 3; break; default:
colorimetry_bpc = 0; break;
}
misc0 = colorimetry_bpc << 5;
if (REG(DP_MSA_TIMING_PARAM1)) { switch (output_color_space) { case COLOR_SPACE_SRGB:
misc0 = misc0 | 0x0;
misc1 = misc1 & ~0x80; /* bit7 = 0*/
dynamic_range_rgb = 0; /*full range*/ break; case COLOR_SPACE_SRGB_LIMITED:
misc0 = misc0 | 0x8; /* bit3=1 */
misc1 = misc1 & ~0x80; /* bit7 = 0*/
dynamic_range_rgb = 1; /*limited range*/ break; case COLOR_SPACE_YCBCR601: case COLOR_SPACE_YCBCR601_LIMITED:
misc0 = misc0 | 0x8; /* bit3=1, bit4=0 */
misc1 = misc1 & ~0x80; /* bit7 = 0*/
dynamic_range_ycbcr = 0; /*bt601*/ if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */ elseif (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR444)
misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */ break; case COLOR_SPACE_YCBCR709: case COLOR_SPACE_YCBCR709_LIMITED: case COLOR_SPACE_YCBCR709_BLACK:
misc0 = misc0 | 0x18; /* bit3=1, bit4=1 */
misc1 = misc1 & ~0x80; /* bit7 = 0*/
dynamic_range_ycbcr = 1; /*bt709*/ if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */ elseif (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR444)
misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */ break; case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
dynamic_range_rgb = 1; /*limited range*/ break; case COLOR_SPACE_2020_RGB_FULLRANGE: case COLOR_SPACE_2020_YCBCR_LIMITED: case COLOR_SPACE_XR_RGB: case COLOR_SPACE_MSREF_SCRGB: case COLOR_SPACE_ADOBERGB: case COLOR_SPACE_DCIP3: case COLOR_SPACE_XV_YCC_709: case COLOR_SPACE_XV_YCC_601: case COLOR_SPACE_DISPLAYNATIVE: case COLOR_SPACE_DOLBYVISION: case COLOR_SPACE_APPCTRL: case COLOR_SPACE_CUSTOMPOINTS: case COLOR_SPACE_UNKNOWN: default: /* do nothing */ break;
} if (enc110->se_mask->DP_DYN_RANGE && enc110->se_mask->DP_YCBCR_RANGE)
REG_UPDATE_2(
DP_PIXEL_FORMAT,
DP_DYN_RANGE, dynamic_range_rgb,
DP_YCBCR_RANGE, dynamic_range_ycbcr);
if (REG(DP_MSA_COLORIMETRY))
REG_SET(DP_MSA_COLORIMETRY, 0, DP_MSA_MISC0, misc0);
if (REG(DP_MSA_MISC))
REG_WRITE(DP_MSA_MISC, misc1); /* MSA_MISC1 */
/* dcn new register * dc_crtc_timing is vesa dmt struct. data from edid
*/ if (REG(DP_MSA_TIMING_PARAM1))
REG_SET_2(DP_MSA_TIMING_PARAM1, 0,
DP_MSA_HTOTAL, hw_crtc_timing.h_total,
DP_MSA_VTOTAL, hw_crtc_timing.v_total);
/* calcuate from vesa timing parameters * h_active_start related to leading edge of sync
*/
/* start at begining of left border */ if (REG(DP_MSA_TIMING_PARAM2))
REG_SET_2(DP_MSA_TIMING_PARAM2, 0,
DP_MSA_HSTART, h_active_start,
DP_MSA_VSTART, v_active_start);
if (enc110->se_mask->HDMI_DATA_SCRAMBLE_EN) { if (actual_pix_clk_khz >= HDMI_CLOCK_CHANNEL_RATE_MORE_340M) { /* enable HDMI data scrambler * HDMI_CLOCK_CHANNEL_RATE_MORE_340M * Clock channel frequency is 1/4 of character rate.
*/
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DATA_SCRAMBLE_EN, 1,
HDMI_CLOCK_CHANNEL_RATE, 1);
} elseif (crtc_timing->flags.LTE_340MCSC_SCRAMBLE) {
/* TODO: New feature for DCE11, still need to implement */
/* enable HDMI data scrambler * HDMI_CLOCK_CHANNEL_FREQ_EQUAL_TO_CHAR_RATE * Clock channel frequency is the same * as character rate
*/
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DATA_SCRAMBLE_EN, 1,
HDMI_CLOCK_CHANNEL_RATE, 0);
}
}
/* wait for update to be completed on the link */ /* i.e. DP_MSE_RATE_UPDATE_PENDING field (read only) */ /* is reset to 0 (not pending) */
REG_WAIT(DP_MSE_RATE_UPDATE, DP_MSE_RATE_UPDATE_PENDING,
0,
10, DP_MST_UPDATE_MAX_RETRY);
}
if (enc110->se_mask->HDMI_AVI_INFO_CONT &&
enc110->se_mask->HDMI_AVI_INFO_SEND) {
if (info_frame->avi.valid) { const uint32_t *content =
(const uint32_t *) &info_frame->avi.sb[0]; /*we need turn on clock before programming AFMT block*/ if (REG(AFMT_CNTL))
REG_UPDATE(AFMT_CNTL, AFMT_AUDIO_CLOCK_EN, 1);
if (enc110->se_mask->HDMI_DB_DISABLE) { /* for bring up, disable dp double TODO */ if (REG(HDMI_DB_CONTROL))
REG_UPDATE(HDMI_DB_CONTROL, HDMI_DB_DISABLE, 1);
if (info_frame->vsc.valid)
dce110_update_generic_info_packet(
enc110,
0, /* packetIndex */
&info_frame->vsc);
if (info_frame->spd.valid)
dce110_update_generic_info_packet(
enc110,
2, /* packetIndex */
&info_frame->spd);
if (info_frame->hdrsmd.valid)
dce110_update_generic_info_packet(
enc110,
3, /* packetIndex */
&info_frame->hdrsmd);
/* enable/disable transmission of packet(s). * If enabled, packet transmission begins on the next frame
*/
REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP0_ENABLE, info_frame->vsc.valid);
REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP2_ENABLE, info_frame->spd.valid);
REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP3_ENABLE, info_frame->hdrsmd.valid);
/* This bit is the master enable bit. * When enabling secondary stream engine, * this master bit must also be set. * This register shared with audio info frame. * Therefore we need to enable master bit * if at least on of the fields is not 0
*/
value = REG_READ(DP_SEC_CNTL); if (value)
REG_UPDATE(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1);
}
/* this register shared with audio info frame. * therefore we need to keep master enabled
* if at least one of the fields is not 0 */
value = REG_READ(DP_SEC_CNTL); if (value)
REG_UPDATE(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1);
/* Note: For CZ, we are changing driver default to disable * stream deferred to next VBLANK. If results are positive, we * will make the same change to all DCE versions. There are a * handful of panels that cannot handle disable stream at * HBLANK and will result in a white line flash across the
* screen on stream disable. */
REG_GET(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, ®1); if ((reg1 & 0x1) == 0) /*stream not enabled*/ return; /* Specify the video stream disable point
* (2 = start of the next vertical blank) */
REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_DIS_DEFER, 2); /* Larger delay to wait until VBLANK - use max retry of * 10us*3000=30ms. This covers 16.6ms of typical 60 Hz mode + * a little more because we may not trust delay accuracy.
*/
max_retries = DP_BLANK_MAX_RETRY * 150;
/* Tell the DP encoder to ignore timing from CRTC, must be done after * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is * complete, stream status will be stuck in video stream enabled state, * i.e. DP_VID_STREAM_STATUS stuck at 1.
*/
/* wait 100us for DIG/DP logic to prime * (i.e. a few video lines)
*/
udelay(100);
/* the hardware would start sending video at the start of the next DP * frame (i.e. rising edge of the vblank). * NOTE: We used to program DP_VID_STREAM_DIS_DEFER = 2 here, but this * register has no effect on enable transition! HW always guarantees * VID_STREAM enable at start of next frame, and this is not * programmable
*/
/* these are one to one */
cea_channels.channels.FL = speaker_flags.FL_FR;
cea_channels.channels.FR = speaker_flags.FL_FR;
cea_channels.channels.LFE = speaker_flags.LFE;
cea_channels.channels.FC = speaker_flags.FC;
/* if Rear Left and Right exist move RC speaker to channel 7 * otherwise to channel 5
*/ if (speaker_flags.RL_RR) {
cea_channels.channels.RL_RC = speaker_flags.RL_RR;
cea_channels.channels.RR = speaker_flags.RL_RR;
cea_channels.channels.RC_RLC_FLC = speaker_flags.RC;
} else {
cea_channels.channels.RL_RC = speaker_flags.RC;
}
/* FRONT Left Right Center and REAR Left Right Center are exclusive */ if (speaker_flags.FLC_FRC) {
cea_channels.channels.RC_RLC_FLC = speaker_flags.FLC_FRC;
cea_channels.channels.RRC_FRC = speaker_flags.FLC_FRC;
} else {
cea_channels.channels.RC_RLC_FLC = speaker_flags.RLC_RRC;
cea_channels.channels.RRC_FRC = speaker_flags.RLC_RRC;
}
if (crtc_info->pixel_repetition)
max_packets_per_line *= crtc_info->pixel_repetition;
/* for other hdmi features */
max_packets_per_line -= 58; /* for Control Period */
max_packets_per_line -= 16; /* Number of Audio Packets per Line */
max_packets_per_line /= 32;
if (clock_info != NULL) { /* search for exact pixel clock in table */ for (index = 0; index < audio_array_size; index++) { if (clock_info[index].pixel_clock_in_10khz >
crtc_pixel_clock_in_10khz) break; /* not match */ elseif (clock_info[index].pixel_clock_in_10khz ==
crtc_pixel_clock_in_10khz) { /* match found */
*audio_clock_info = clock_info[index]; return;
}
}
}
/* not found */ if (actual_pixel_clock_100Hz == 0)
actual_pixel_clock_100Hz = crtc_pixel_clock_100Hz;
/* See HDMI spec the table entry under
* pixel clock of "Other". */
audio_clock_info->pixel_clock_in_10khz =
actual_pixel_clock_100Hz / 100;
audio_clock_info->cts_32khz = actual_pixel_clock_100Hz / 10;
audio_clock_info->cts_44khz = actual_pixel_clock_100Hz / 10;
audio_clock_info->cts_48khz = actual_pixel_clock_100Hz / 10;
/* For now still do calculation, although this field is ignored when
above HDMI_PACKET_GEN_VERSION set to 1 */
max_packets_per_line = calc_max_audio_packets_per_line(crtc_info);
/* Video driver cannot know in advance which sample rate will be used by HD Audio driver HDMI_ACR_PACKET_CONTROL__HDMI_ACR_N_MULTIPLE field is
programmed below in interruppt callback */
/* AFMT_AUDIO_PACKET_CONTROL2 */ /* Program the ATP and AIP next */
REG_UPDATE_2(AFMT_AUDIO_PACKET_CONTROL2,
AFMT_AUDIO_LAYOUT_OVRD, 0,
AFMT_60958_OSF_OVRD, 0);
/* wait for AFMT clock to turn on, * expectation: this should complete in 1-2 reads * * REG_WAIT(AFMT_CNTL, AFMT_AUDIO_CLOCK_ON, !!enable, 1, 10); * * TODO: wait for clock_on does not work well. May need HW * program sequence. But audio seems work normally even without wait * for clock_on status change
*/
}
/* This register shared with encoder info frame. Therefore we need to
keep master enabled if at least on of the fields is not 0 */
value = REG_READ(DP_SEC_CNTL); if (value != 0)
REG_UPDATE(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.