/* * 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 *
*/
/** * apply_front_porch_workaround() - This is a workaround for a bug that has * existed since R5xx and has not been fixed * keep Front porch at minimum 2 for Interlaced * mode or 1 for progressive. * * @timing: Timing parameters used to configure DCN blocks.
*/ staticvoid apply_front_porch_workaround(struct dc_crtc_timing *timing)
{ if (timing->flags.INTERLACE == 1) { if (timing->v_front_porch < 2)
timing->v_front_porch = 2;
} else { if (timing->v_front_porch < 1)
timing->v_front_porch = 1;
}
}
void optc1_program_global_sync( struct timing_generator *optc, int vready_offset, int vstartup_start, int vupdate_offset, int vupdate_width, int pstate_keepout)
{ struct optc *optc1 = DCN10TG_FROM_TG(optc);
/* In case of V_TOTAL_CONTROL is on, make sure OTG_V_TOTAL_MAX and * OTG_V_TOTAL_MIN are equal to V_TOTAL.
*/
optc->funcs->set_vtotal_min_max(optc, v_total, v_total);
/* Interlace */ if (REG(OTG_INTERLACE_CONTROL)) { if (patched_crtc_timing.flags.INTERLACE == 1)
REG_UPDATE(OTG_INTERLACE_CONTROL,
OTG_INTERLACE_ENABLE, 1); else
REG_UPDATE(OTG_INTERLACE_CONTROL,
OTG_INTERLACE_ENABLE, 0);
}
/* VTG enable set to 0 first VInit */
REG_UPDATE(CONTROL,
VTG0_ENABLE, 0);
/* original code is using VTG offset to address OTG reg, seems wrong */
REG_UPDATE_2(OTG_CONTROL,
OTG_START_POINT_CNTL, start_point,
OTG_FIELD_NUMBER_CNTL, field_num);
/* TODO * patched_crtc_timing.flags.HORZ_COUNT_BY_TWO == 1 * program_horz_count_by_2 * for DVI 30bpp mode, 0 otherwise * program_horz_count_by_2(optc, &patched_crtc_timing);
*/
/* Enable stereo - only when we need to pack 3D frame. Other types * of stereo handled in explicit call
*/ if (optc->funcs->is_two_pixels_per_container(&patched_crtc_timing) || optc1->opp_count == 2)
h_div = H_TIMING_DIV_BY2;
/** * optc1_set_vtg_params - Set Vertical Timing Generator (VTG) parameters * * @optc: timing_generator struct used to extract the optc parameters * @dc_crtc_timing: Timing parameters configured * @program_fp2: Boolean value indicating if FP2 will be programmed or not * * OTG is responsible for generating the global sync signals, including * vertical timing information for each HUBP in the dcfclk domain. Each VTG is * associated with one OTG that provides HUBP with vertical timing information * (i.e., there is 1:1 correspondence between OTG and VTG). This function is * responsible for setting the OTG parameters to the VTG during the pipe * programming.
*/ void optc1_set_vtg_params(struct timing_generator *optc, conststruct dc_crtc_timing *dc_crtc_timing, bool program_fp2)
{ struct dc_crtc_timing patched_crtc_timing;
uint32_t asic_blank_end;
uint32_t v_init;
uint32_t v_fp2 = 0;
int32_t vertical_line_start;
/* VCOUNT_INIT is the start of blank */
v_init = patched_crtc_timing.v_total - patched_crtc_timing.v_front_porch;
/* end of blank = v_init - active */
asic_blank_end = v_init -
patched_crtc_timing.v_border_bottom -
patched_crtc_timing.v_addressable -
patched_crtc_timing.v_border_top;
/* if VSTARTUP is before VSYNC, FP2 is the offset, otherwise 0 */
vertical_line_start = asic_blank_end - optc1->vstartup_start + 1; if (vertical_line_start < 0)
v_fp2 = -vertical_line_start;
/* Interlace */ if (REG(OTG_INTERLACE_CONTROL)) { if (patched_crtc_timing.flags.INTERLACE == 1) {
v_init = v_init / 2; if ((optc1->vstartup_start/2)*2 > asic_blank_end)
v_fp2 = v_fp2 / 2;
}
}
/* W/A for automated testing * Automated testing will fail underflow test as there * sporadic underflows which occur during the optc blank * sequence. As a w/a, clear underflow on unblank. * This prevents the failure, but will not mask actual * underflow that affect real use cases.
*/
optc1_clear_optc_underflow(optc);
}
/** * optc1_blank_crtc() - Call ASIC Control Object to Blank CRTC. * * @optc: timing_generator instance.
*/
//last chance to clear underflow, otherwise, it will always there due to clock is off. if (optc->funcs->is_optc_underflow_occurred(optc) == true)
optc->funcs->clear_optc_underflow(optc);
/* opp instance for OTG. For DCN1.0, ODM is remoed. * OPP and OPTC should 1:1 mapping
*/
REG_UPDATE(OPTC_DATA_SOURCE_SELECT,
OPTC_SRC_SEL, optc->inst);
/* VTG enable first is for HW workaround */
REG_UPDATE(CONTROL,
VTG0_ENABLE, 1);
/* disable otg request until end of the first line * in the vertical blank region
*/
REG_UPDATE_2(OTG_CONTROL,
OTG_DISABLE_POINT_CNTL, 3,
OTG_MASTER_EN, 0);
/* Temporarily blocking interlacing mode until it's supported */ if (timing->flags.INTERLACE == 1) returnfalse;
/* Check maximum number of pixels supported by Timing Generator * (Currently will never fail, in order to fail needs display which * needs more than 8192 horizontal and * more than 8192 vertical total pixels)
*/ if (timing->h_total > optc1->max_h_total ||
timing->v_total > optc1->max_v_total) returnfalse;
if (h_blank < optc1->min_h_blank) returnfalse;
if (timing->h_sync_width < optc1->min_h_sync_width ||
timing->v_sync_width < optc1->min_v_sync_width) returnfalse;
/* * get_vblank_counter * * @brief * Get counter for vertical blanks. use register CRTC_STATUS_FRAME_COUNT which * holds the counter of frames. * * @param * struct timing_generator *optc - [in] timing generator which controls the * desired CRTC * * @return * Counter of frames, which should equal to number of vblanks.
*/
uint32_t optc1_get_vblank_counter(struct timing_generator *optc)
{ struct optc *optc1 = DCN10TG_FROM_TG(optc);
uint32_t frame_count;
if (falling_edge)
REG_SET_3(OTG_TRIGA_CNTL, 0, /* vsync signal from selected OTG pipe based * on OTG_TRIG_SOURCE_PIPE_SELECT setting
*/
OTG_TRIGA_SOURCE_SELECT, 20,
OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst, /* always detect falling edge */
OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 1); else
REG_SET_3(OTG_TRIGA_CNTL, 0, /* vsync signal from selected OTG pipe based * on OTG_TRIG_SOURCE_PIPE_SELECT setting
*/
OTG_TRIGA_SOURCE_SELECT, 20,
OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst, /* always detect rising edge */
OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1);
REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0, /* force H count to H_TOTAL and V count to V_TOTAL in * progressive mode and V_TOTAL-1 in interlaced mode
*/
OTG_FORCE_COUNT_NOW_MODE, 2);
}
case CRTC_EVENT_VSYNC_RISING:
rising_edge = 1; break;
case CRTC_EVENT_VSYNC_FALLING:
falling_edge = 1; break;
}
REG_SET_4(OTG_TRIGA_CNTL, 0, /* vsync signal from selected OTG pipe based * on OTG_TRIG_SOURCE_PIPE_SELECT setting
*/
OTG_TRIGA_SOURCE_SELECT, 20,
OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst, /* always detect falling edge */
OTG_TRIGA_RISING_EDGE_DETECT_CNTL, rising_edge,
OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, falling_edge);
switch (crtc_tp->delay) { case TRIGGER_DELAY_NEXT_LINE:
REG_SET(OTG_VERT_SYNC_CONTROL, 0,
OTG_AUTO_FORCE_VSYNC_MODE, 1); break; case TRIGGER_DELAY_NEXT_PIXEL:
REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0, /* force H count to H_TOTAL and V count to V_TOTAL in * progressive mode and V_TOTAL-1 in interlaced mode
*/
OTG_FORCE_COUNT_NOW_MODE, 2); break;
}
}
switch (state) { case CRTC_STATE_VBLANK:
REG_WAIT(OTG_STATUS,
OTG_V_BLANK, 1,
1, 100000); /* 1 vupdate at 10hz */ break;
case CRTC_STATE_VACTIVE:
REG_WAIT(OTG_STATUS,
OTG_V_ACTIVE_DISP, 1,
1, 100000); /* 1 vupdate at 10hz */ break;
default: break;
}
}
void optc1_set_early_control( struct timing_generator *optc,
uint32_t early_cntl)
{ /* asic design change, do not need this control * empty for share caller logic
*/
}
// By register spec, it only takes 8 bit value if (num_frames > 0xFF)
num_frames = 0xFF;
/* Bit 8 is no longer applicable in RV for PSR case, * set bit 8 to 0 if given
*/ if ((event_triggers & STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN)
!= 0)
event_triggers = event_triggers &
~STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN;
case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS: case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS:
{
mode = (test_pattern ==
CONTROLLER_DP_TEST_PATTERN_VERTICALBARS ?
TEST_PATTERN_MODE_VERTICALBARS :
TEST_PATTERN_MODE_HORIZONTALBARS);
switch (bit_depth) { case TEST_PATTERN_COLOR_FORMAT_BPC_6:
dst_bpc = 6; break; case TEST_PATTERN_COLOR_FORMAT_BPC_8:
dst_bpc = 8; break; case TEST_PATTERN_COLOR_FORMAT_BPC_10:
dst_bpc = 10; break; default:
dst_bpc = 8; break;
}
/* adjust color to the required colorFormat */ for (index = 0; index < 6; index++) { /* dst = 2^dstBpc * src / 2^srcBpc = src >> * (srcBpc - dstBpc);
*/
dst_color[index] =
src_color[index] >> (src_bpc - dst_bpc); /* CRTC_TEST_PATTERN_DATA has 16 bits, * lowest 6 are hardwired to ZERO * color bits should be left aligned to MSB * XXXXXXXXXX000000 for 10 bit, * XXXXXXXX00000000 for 8 bit and XXXXXX0000000000 for 6
*/
dst_color[index] <<= (16 - dst_bpc);
}
REG_WRITE(OTG_TEST_PATTERN_PARAMETERS, 0);
/* We have to write the mask before data, similar to pipeline. * For example, for 8 bpc, if we want RGB0 to be magenta, * and RGB1 to be cyan, * we need to make 7 writes: * MASK DATA * 000001 00000000 00000000 set mask to R0 * 000010 11111111 00000000 R0 255, 0xFF00, set mask to G0 * 000100 00000000 00000000 G0 0, 0x0000, set mask to B0 * 001000 11111111 00000000 B0 255, 0xFF00, set mask to R1 * 010000 00000000 00000000 R1 0, 0x0000, set mask to G1 * 100000 11111111 00000000 G1 255, 0xFF00, set mask to B1 * 100000 11111111 00000000 B1 255, 0xFF00 * * we will make a loop of 6 in which we prepare the mask, * then write, then prepare the color for next write. * first iteration will write mask only, * but each next iteration color prepared in * previous iteration will be written within new mask, * the last component will written separately, * mask is not changing between 6th and 7th write * and color will be prepared by last iteration
*/
/* write color, color values mask in CRTC_TEST_PATTERN_MASK * is B1, G1, R1, B0, G0, R0
*/
pattern_data = 0; for (index = 0; index < 6; index++) { /* prepare color mask, first write PATTERN_DATA * will have all zeros
*/
pattern_mask = (1 << index);
/* prepare next color component, * will be written in the next iteration
*/
pattern_data = dst_color[index];
} /* write last color component, * it's been already prepared in the loop
*/
REG_SET_2(OTG_TEST_PATTERN_COLOR, 0,
OTG_TEST_PATTERN_MASK, pattern_mask,
OTG_TEST_PATTERN_DATA, pattern_data);
switch (bit_depth) { case TEST_PATTERN_COLOR_FORMAT_BPC_6:
dst_bpc = 6; break; case TEST_PATTERN_COLOR_FORMAT_BPC_8:
dst_bpc = 8; break; case TEST_PATTERN_COLOR_FORMAT_BPC_10:
dst_bpc = 10; break; default:
dst_bpc = 8; break;
}
/* increment for the first ramp for one color gradation * 1 gradation for 6-bit color is 2^10 * gradations in 16-bit color
*/
inc_base = (src_bpc - dst_bpc);
/* Cannot configure crc on a CRTC that is disabled */ if (!optc1_is_tg_enabled(optc)) returnfalse;
if (!params->enable || params->reset)
REG_WRITE(OTG_CRC_CNTL, 0);
if (!params->enable) returntrue;
/* Program frame boundaries */ switch (params->crc_eng_inst) { case 0: /* Window A x axis start and end. */
REG_UPDATE_2(OTG_CRC0_WINDOWA_X_CONTROL,
OTG_CRC0_WINDOWA_X_START, params->windowa_x_start,
OTG_CRC0_WINDOWA_X_END, params->windowa_x_end);
/* Window A y axis start and end. */
REG_UPDATE_2(OTG_CRC0_WINDOWA_Y_CONTROL,
OTG_CRC0_WINDOWA_Y_START, params->windowa_y_start,
OTG_CRC0_WINDOWA_Y_END, params->windowa_y_end);
/* Window B x axis start and end. */
REG_UPDATE_2(OTG_CRC0_WINDOWB_X_CONTROL,
OTG_CRC0_WINDOWB_X_START, params->windowb_x_start,
OTG_CRC0_WINDOWB_X_END, params->windowb_x_end);
/* Window B y axis start and end. */
REG_UPDATE_2(OTG_CRC0_WINDOWB_Y_CONTROL,
OTG_CRC0_WINDOWB_Y_START, params->windowb_y_start,
OTG_CRC0_WINDOWB_Y_END, params->windowb_y_end);
/* Set crc mode and selection, and enable.*/
REG_UPDATE_3(OTG_CRC_CNTL,
OTG_CRC_CONT_EN, params->continuous_mode ? 1 : 0,
OTG_CRC0_SELECT, params->selection,
OTG_CRC_EN, 1); break; case 1: /* Window A x axis start and end. */
REG_UPDATE_2(OTG_CRC1_WINDOWA_X_CONTROL,
OTG_CRC1_WINDOWA_X_START, params->windowa_x_start,
OTG_CRC1_WINDOWA_X_END, params->windowa_x_end);
/* Window A y axis start and end. */
REG_UPDATE_2(OTG_CRC1_WINDOWA_Y_CONTROL,
OTG_CRC1_WINDOWA_Y_START, params->windowa_y_start,
OTG_CRC1_WINDOWA_Y_END, params->windowa_y_end);
/* Window B x axis start and end. */
REG_UPDATE_2(OTG_CRC1_WINDOWB_X_CONTROL,
OTG_CRC1_WINDOWB_X_START, params->windowb_x_start,
OTG_CRC1_WINDOWB_X_END, params->windowb_x_end);
/* Window B y axis start and end. */
REG_UPDATE_2(OTG_CRC1_WINDOWB_Y_CONTROL,
OTG_CRC1_WINDOWB_Y_START, params->windowb_y_start,
OTG_CRC1_WINDOWB_Y_END, params->windowb_y_end);
/* Set crc mode and selection, and enable.*/
REG_UPDATE_3(OTG_CRC_CNTL,
OTG_CRC_CONT_EN, params->continuous_mode ? 1 : 0,
OTG_CRC1_SELECT, params->selection,
OTG_CRC_EN, 1); break; default: returnfalse;
}
returntrue;
}
/** * optc1_get_crc - Capture CRC result per component * * @optc: timing_generator instance. * @idx: index of crc engine to get CRC from * @r_cr: 16-bit primary CRC signature for red data. * @g_y: 16-bit primary CRC signature for green data. * @b_cb: 16-bit primary CRC signature for blue data. * * This function reads the CRC signature from the OPTC registers. Notice that * we have three registers to keep the CRC result per color component (RGB). * * Returns: * If CRC is disabled, return false; otherwise, return true, and the CRC * results in the parameters.
*/ bool optc1_get_crc(struct timing_generator *optc, uint8_t idx,
uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb)
{
uint32_t field = 0; struct optc *optc1 = DCN10TG_FROM_TG(optc);
REG_GET(OTG_CRC_CNTL, OTG_CRC_EN, &field);
/* Early return if CRC is not enabled for this CRTC */ if (!field) returnfalse;
switch (idx) { case 0: /* OTG_CRC0_DATA_RG has the CRC16 results for the red and green component */
REG_GET_2(OTG_CRC0_DATA_RG,
CRC0_R_CR, r_cr,
CRC0_G_Y, g_y);
/* OTG_CRC0_DATA_B has the CRC16 results for the blue component */
REG_GET(OTG_CRC0_DATA_B,
CRC0_B_CB, b_cb); break; case 1: /* OTG_CRC1_DATA_RG has the CRC16 results for the red and green component */
REG_GET_2(OTG_CRC1_DATA_RG,
CRC1_R_CR, r_cr,
CRC1_G_Y, g_y);
/* OTG_CRC1_DATA_B has the CRC16 results for the blue component */
REG_GET(OTG_CRC1_DATA_B,
CRC1_B_CB, b_cb); break; default: returnfalse;
}
returntrue;
}
/* "Container" vs. "pixel" is a concept within HW blocks, mostly those closer to the back-end. It works like this: * * - In most of the formats (RGB or YCbCr 4:4:4, 4:2:2 uncompressed and DSC 4:2:2 Simple) pixel rate is the same as * container rate. * * - In 4:2:0 (DSC or uncompressed) there are two pixels per container, hence the target container rate has to be * halved to maintain the correct pixel rate. * * - Unlike 4:2:2 uncompressed, DSC 4:2:2 Native also has two pixels per container (this happens when DSC is applied * to it) and has to be treated the same as 4:2:0, i.e. target containter rate has to be halved in this case as well. *
*/ bool optc1_is_two_pixels_per_container(conststruct dc_crtc_timing *timing)
{ bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420;
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.