/* * Copyright 2015 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 *
*/
/* * All values are in milliseconds; * For eDP, after power-up/power/down, * 300/500 msec max. delay from LCDVCC to black video generation
*/ #define PANEL_POWER_UP_TIMEOUT 300 #define PANEL_POWER_DOWN_TIMEOUT 500 #define HPD_CHECK_INTERVAL 10 #define OLED_POST_T7_DELAY 100 #define OLED_PRE_T11_DELAY 150
/* Revert MASTER_UPDATE_MODE to 0 because bios sets it 2 * by default when command table is called * * Bios parser accepts controller_id = 6 as indicative of * underlay pipe in dce110. But we do not support more * than 3.
*/ if (controller_id < CONTROLLER_ID_MAX - 1)
dm_write_reg(ctx,
HW_REG_CRTC(mmCRTC_MASTER_UPDATE_MODE, controller_id),
0);
}
if (power_gating != PIPE_GATING_CONTROL_ENABLE)
dce110_init_pte(ctx);
if (bp_result == BP_RESULT_OK) returntrue; else returnfalse;
}
switch (plane_state->format) { case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
prescale_params->scale = 0x2082; break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
prescale_params->scale = 0x2020; break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
prescale_params->scale = 0x2008; break; case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
prescale_params->scale = 0x2000; break; default:
ASSERT(false); break;
}
}
if (output_tf->tf == TRANSFER_FUNCTION_PQ) { /* 16 segments * segments are from 2^-11 to 2^5
*/
region_start = -11;
region_end = region_start + NUMBER_REGIONS;
for (i = 0; i < NUMBER_REGIONS; i++)
seg_distr[i] = 4;
} else { /* 10 segments * segment is from 2^-10 to 2^1 * We include an extra segment for range [2^0, 2^1). This is to * ensure that colors with normalized values of 1 don't miss the * LUT.
*/
region_start = -10;
region_end = 1;
/* see comment above, m_arrPoints[1].y should be the Y value for the * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1)
*/
y3_max = dc_fixpt_max(y_r, dc_fixpt_max(y_g, y_b));
arr_points[1].y = y3_max;
arr_points[1].slope = dc_fixpt_zero;
if (output_tf->tf == TRANSFER_FUNCTION_PQ) { /* for PQ, we want to have a straight line from last HW X point, * and the slope to be such that we hit 1.0 at 10000 nits.
*/ conststruct fixed31_32 end_value = dc_fixpt_from_int(125);
while (i != hw_points + 1) { if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
rgb_plus_1->red = rgb->red; if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
rgb_plus_1->green = rgb->green; if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
rgb_plus_1->blue = rgb->blue;
/* enable early control to avoid corruption on DP monitor*/
active_total_with_borders =
timing->h_addressable
+ timing->h_border_left
+ timing->h_border_right;
if (lane_count != 0)
early_control = active_total_with_borders % lane_count;
if (early_control == 0)
early_control = lane_count;
/* Send VBIOS command to prompt eDP panel power */ if (power_up) { /* edp requires a min of 500ms from LCDVDD off to on */ unsignedlonglong remaining_min_edp_poweroff_time_ms = 500;
/* add time defined by a patch, if any (usually patch extra_t12_ms is 0) */ if (link->local_sink != NULL)
remaining_min_edp_poweroff_time_ms +=
link->panel_config.pps.extra_t12_ms;
/* Adjust remaining_min_edp_poweroff_time_ms if this is not the first time. */ if (ctx->dc->link_srv->dp_trace_get_edp_poweroff_timestamp(link) != 0) { if (time_since_edp_poweroff_ms < remaining_min_edp_poweroff_time_ms)
remaining_min_edp_poweroff_time_ms =
remaining_min_edp_poweroff_time_ms - time_since_edp_poweroff_ms; else
remaining_min_edp_poweroff_time_ms = 0;
}
if (remaining_min_edp_poweroff_time_ms) {
DC_LOG_HW_RESUME_S3( "%s: remaining_min_edp_poweroff_time_ms=%llu: begin wait.\n",
__func__, remaining_min_edp_poweroff_time_ms);
msleep(remaining_min_edp_poweroff_time_ms);
DC_LOG_HW_RESUME_S3( "%s: remaining_min_edp_poweroff_time_ms=%llu: end wait.\n",
__func__, remaining_min_edp_poweroff_time_ms);
dm_output_to_console("%s: wait %lld ms to power on eDP.\n",
__func__, remaining_min_edp_poweroff_time_ms);
} else {
DC_LOG_HW_RESUME_S3( "%s: remaining_min_edp_poweroff_time_ms=%llu: no wait required.\n",
__func__, remaining_min_edp_poweroff_time_ms);
}
}
/* For eDP, the following delays might need to be considered * after link training completed: * idle period - min. accounts for required BS-Idle pattern, * max. allows for source frame synchronization); * 50 msec max. delay from valid video data from source * to video on dislpay or backlight enable. * * Disable the delay for now. * Enable it in the future if necessary.
*/ /* dc_service_sleep_in_milliseconds(50); */ /*edp 1.2*/ if (link->panel_cntl)
pwrseq_instance = link->panel_cntl->pwrseq_inst;
if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) { if (!link->dc->config.edp_no_power_sequencing) /* * Sometimes, DP receiver chip power-controlled externally by an * Embedded Controller could be treated and used as eDP, * if it drives mobile display. In this case, * we shouldn't be doing power-sequencing, hence we can skip * waiting for T7-ready.
*/
ctx->dc->link_srv->edp_receiver_ready_T7(link); else
DC_LOG_DC("edp_receiver_ready_T7 skipped\n");
}
/* Setting link_powered_externally will bypass delays in the backlight * as they are not required if the link is being powered by a different * source.
*/ if (ctx->dc->ctx->dmub_srv &&
ctx->dc->debug.dmub_command_table) { if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON)
ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
LVTMA_CONTROL_LCD_BLON,
pwrseq_instance, link->link_powered_externally); else
ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios,
LVTMA_CONTROL_LCD_BLOFF,
pwrseq_instance, link->link_powered_externally);
}
/*edp 1.2*/ if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_OFF) { if (!link->dc->config.edp_no_power_sequencing) /* * Sometimes, DP receiver chip power-controlled externally by an * Embedded Controller could be treated and used as eDP, * if it drives mobile display. In this case, * we shouldn't be doing power-sequencing, hence we can skip * waiting for T9-ready.
*/
ctx->dc->link_srv->edp_add_delay_for_T9(link); else
DC_LOG_DC("edp_receiver_ready_T9 skipped\n");
}
if (!enable) { /*follow oem panel config's requirement*/
pre_T11_delay += link->panel_config.pps.extra_pre_t11_ms; if (pre_T11_delay)
msleep(pre_T11_delay);
}
}
void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx)
{ /* notify audio driver for audio modes of monitor */ struct dc *dc; struct clk_mgr *clk_mgr; unsignedint i, num_audio = 1; conststruct link_hwss *link_hwss;
if (!pipe_ctx->stream) return;
dc = pipe_ctx->stream->ctx->dc;
clk_mgr = dc->clk_mgr;
link_hwss = get_link_hwss(pipe_ctx->stream->link, &pipe_ctx->link_res);
if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == true) return;
if (pipe_ctx->stream_res.audio) { for (i = 0; i < MAX_PIPES; i++) { /*current_state not updated yet*/ if (dc->current_state->res_ctx.pipe_ctx[i].stream_res.audio != NULL)
num_audio++;
}
if (num_audio >= 1 && clk_mgr->funcs->enable_pme_wa) /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/
clk_mgr->funcs->enable_pme_wa(clk_mgr);
link_hwss->enable_audio_packet(pipe_ctx);
if (pipe_ctx->stream_res.audio)
pipe_ctx->stream_res.audio->enabled = true;
}
}
if (hws && hws->wa_state.skip_blank_stream) return;
if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { if (!link->skip_implict_edp_power_control && hws)
hws->funcs.edp_backlight_control(link, false);
link->dc->hwss.set_abm_immediate_disable(pipe_ctx);
}
if (link->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { /* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_blank(
pipe_ctx->stream_res.hpo_dp_stream_enc);
} elseif (dc_is_dp_signal(pipe_ctx->stream->signal)) {
pipe_ctx->stream_res.stream_enc->funcs->dp_blank(link, pipe_ctx->stream_res.stream_enc);
if (!dc_is_embedded_signal(pipe_ctx->stream->signal)) { /* * After output is idle pattern some sinks need time to recognize the stream * has changed or they enter protection state and hang.
*/
msleep(60);
}
}
if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP &&
!link->dc->config.edp_no_power_sequencing) { /* * Sometimes, DP receiver chip power-controlled externally by an * Embedded Controller could be treated and used as eDP, * if it drives mobile display. In this case, * we shouldn't be doing power-sequencing, hence we can skip * waiting for T9-ready.
*/
link->dc->link_srv->edp_receiver_ready_T9(link);
}
/* For audio stream calculations, the video stream should not include FEC or SSC * in order to get the most pessimistic values.
*/ if (dp_link_info->encoding == DP_8b_10b_ENCODING &&
link->dc->link_srv->dp_is_fec_supported(link)) {
link_bw_kbps = dc_fixpt_mul(link_bw_kbps,
dc_fixpt_from_fraction(100, DATA_EFFICIENCY_8b_10b_FEC_EFFICIENCY_x100));
} elseif (dp_link_info->encoding == DP_128b_132b_ENCODING) {
link_bw_kbps = dc_fixpt_mul(link_bw_kbps,
dc_fixpt_from_fraction(10000, 9975)); /* 99.75% SSC overhead*/
}
if (crtc_timing->flags.DSC) {
bpp = crtc_timing->dsc_cfg.bits_per_pixel;
} else { /* When the timing is using DSC, dsc_cfg.bits_per_pixel is in 16th bits. * The bpp in this path is scaled to 16th bits so the final calculation * is correct for both cases.
*/
bpp = 16; switch (crtc_timing->display_color_depth) { case COLOR_DEPTH_666:
bpp *= 18; break; case COLOR_DEPTH_888:
bpp *= 24; break; case COLOR_DEPTH_101010:
bpp *= 30; break; case COLOR_DEPTH_121212:
bpp *= 36; break; default:
bpp = 0; break;
}
/* * Audio packets are sent during actual CRTC blank physical signal, we * need to specify actual active signal portion
*/
audio_output->crtc_info.h_active =
stream->timing.h_addressable
+ stream->timing.h_border_left
+ stream->timing.h_border_right;
/*for HDMI, audio ACR is with deep color ratio factor*/ if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) &&
audio_output->crtc_info.requested_pixel_clock_100Hz ==
(stream->timing.pix_clk_100hz)) { if (pipe_ctx->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420) {
audio_output->crtc_info.requested_pixel_clock_100Hz =
audio_output->crtc_info.requested_pixel_clock_100Hz/2;
audio_output->crtc_info.calculated_pixel_clock_100Hz =
pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz/2;
if (pipe_ctx->stream_res.tg->funcs->set_overscan_blank_color) { /* * The way 420 is packed, 2 channels carry Y component, 1 channel * alternate between Cb and Cr, so both channels need the pixel * value for Y
*/ if (pipe_ctx->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
color.color_r_cr = color.color_g_y;
/* program blank color */
color_space_to_black_color(dc,
stream->output_color_space, &black_color);
pipe_ctx->stream_res.tg->funcs->set_blank_color(
pipe_ctx->stream_res.tg,
&black_color);
/* * Must blank CRTC after disabling power gating and before any * programming, otherwise CRTC will be hung in bad state
*/
pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true);
if (dc->config.disable_hbr_audio_dp2) if (pipe_ctx->stream_res.audio->funcs->az_disable_hbr_audio &&
dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))
pipe_ctx->stream_res.audio->funcs->az_disable_hbr_audio(pipe_ctx->stream_res.audio);
}
/* make sure no pipes syncd to the pipe being enabled */ if (!pipe_ctx->stream->apply_seamless_boot_optimization && dc->config.use_pipe_ctx_sync_logic)
check_syncd_pipes_for_disabled_master_pipe(dc, context, pipe_ctx->pipe_idx);
/* DCN3.1 FPGA Workaround * Need to enable HPO DP Stream Encoder before setting OTG master enable. * To do so, move calling function enable_stream_timing to only be done AFTER calling * function core_link_enable_stream
*/ if (!(hws->wa.dp_hpo_and_otg_sequence && dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))) /* */ /* Do not touch stream timing on seamless boot optimization. */ if (!pipe_ctx->stream->apply_seamless_boot_optimization)
hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
if (hws->funcs.setup_vupdate_interrupt)
hws->funcs.setup_vupdate_interrupt(dc, pipe_ctx);
// DRR should set trigger event to monitor surface update event if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
event_triggers = 0x80; /* Event triggers and num frames initialized for DRR, but can be * later updated for PSR use. Note DRR trigger events are generated * regardless of whether num frames met.
*/ if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
pipe_ctx->stream_res.tg, event_triggers, 2);
if (!dc_is_virtual_signal(pipe_ctx->stream->signal))
pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg(
pipe_ctx->stream_res.stream_enc,
pipe_ctx->stream_res.tg->inst);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
/* Temporary workaround to perform DSC programming ahead of stream enablement * for smartmux/SPRS * TODO: Remove SmartMux/SPRS checks once movement of DSC programming is generalized
*/ if (pipe_ctx->stream->timing.flags.DSC) { if ((pipe_ctx->stream->signal == SIGNAL_TYPE_EDP &&
((link->dc->config.smart_mux_version && link->dc->is_switch_in_progress_dest)
|| link->is_dds || link->skip_implict_edp_power_control)) &&
(dc_is_dp_signal(pipe_ctx->stream->signal) ||
dc_is_virtual_signal(pipe_ctx->stream->signal)))
dc->link_srv->set_dsc_enable(pipe_ctx, true);
}
if (!stream->dpms_off)
dc->link_srv->set_dpms_on(context, pipe_ctx);
/* DCN3.1 FPGA Workaround * Need to enable HPO DP Stream Encoder before setting OTG master enable. * To do so, move calling function enable_stream_timing to only be done AFTER calling * function core_link_enable_stream
*/ if (hws->wa.dp_hpo_and_otg_sequence && dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { if (!pipe_ctx->stream->apply_seamless_boot_optimization)
hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
}
/* Phantom and main stream share the same link (because the stream * is constructed with the same sink). Make sure not to override * and link programming on the main.
*/ if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) {
pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false;
pipe_ctx->stream->link->replay_settings.replay_feature_enabled = false;
} return DC_OK;
}
staticvoid power_down_controllers(struct dc *dc)
{ int i;
for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
dc->res_pool->timing_generators[i]->funcs->disable_crtc(
dc->res_pool->timing_generators[i]);
}
}
staticvoid power_down_clock_sources(struct dc *dc)
{ int i;
if (dc->res_pool->dp_clock_source->funcs->cs_power_down(
dc->res_pool->dp_clock_source) == false)
dm_error("Failed to power down pll! (dp clk src)\n");
for (i = 0; i < dc->res_pool->clk_src_count; i++) { if (dc->res_pool->clock_sources[i]->funcs->cs_power_down(
dc->res_pool->clock_sources[i]) == false)
dm_error("Failed to power down pll! (clk src index=%d)\n", i);
}
}
staticvoid power_down_all_hw_blocks(struct dc *dc)
{
power_down_encoders(dc);
power_down_controllers(dc);
power_down_clock_sources(dc);
if (dc->fbc_compressor)
dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor);
}
staticvoid disable_vga_and_power_gate_all_controllers( struct dc *dc)
{ int i; struct timing_generator *tg; struct dc_context *ctx = dc->ctx;
for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
tg = dc->res_pool->timing_generators[i];
if (tg->funcs->disable_vga)
tg->funcs->disable_vga(tg);
} for (i = 0; i < dc->res_pool->pipe_count; i++) { /* Enable CLOCK gating for each pipe BEFORE controller
* powergating. */
enable_display_pipe_clock_gating(ctx, true);
staticvoid get_edp_streams(struct dc_state *context, struct dc_stream_state **edp_streams, int *edp_stream_num)
{ int i;
*edp_stream_num = 0; for (i = 0; i < context->stream_count; i++) { if (context->streams[i]->signal == SIGNAL_TYPE_EDP) {
edp_streams[*edp_stream_num] = context->streams[i]; if (++(*edp_stream_num) == MAX_NUM_EDP) return;
}
}
}
staticvoid get_edp_links_with_sink( struct dc *dc, struct dc_link **edp_links_with_sink, int *edp_with_sink_num)
{ int i;
/* check if there is an eDP panel not in use */
*edp_with_sink_num = 0; for (i = 0; i < dc->link_count; i++) { if (dc->links[i]->local_sink &&
dc->links[i]->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
edp_links_with_sink[*edp_with_sink_num] = dc->links[i]; if (++(*edp_with_sink_num) == MAX_NUM_EDP) return;
}
}
}
if (!dc->caps.is_apu ||
dc->ctx->dce_version < DCN_VERSION_3_15) return; /*VBIOS supports dsc starts from dcn315*/ for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) { struct dcn_dsc_state s = {0};
dsc = dc->res_pool->dscs[i];
dsc->funcs->dsc_read_state(dsc, &s); if (s.dsc_fw_en) { /* disable DSC in OPTC */ if (i < dc->res_pool->timing_generator_count) {
tg = dc->res_pool->timing_generators[i];
tg->funcs->set_dsc_config(tg, OPTC_DSC_DISABLED, 0, 0);
} /* disable DSC in stream encoder */ if (i < dc->res_pool->stream_enc_count) {
se = dc->res_pool->stream_enc[i];
se->funcs->dp_set_dsc_config(se, OPTC_DSC_DISABLED, 0, 0);
se->funcs->dp_set_dsc_pps_info_packet(se, false, NULL, true);
} /* disable DSC block */ if (dccg->funcs->set_ref_dscclk)
dccg->funcs->set_ref_dscclk(dccg, dsc->inst);
dsc->funcs->dsc_disable(dsc);
/* power down DSC */ if (pg_cntl != NULL)
pg_cntl->funcs->dsc_pg_control(pg_cntl, dsc->inst, false);
}
}
}
/* * When ASIC goes from VBIOS/VGA mode to driver/accelerated mode we need: * 1. Power down all DC HW blocks * 2. Disable VGA engine on all controllers * 3. Enable power gating for controller * 4. Set acc_mode_change bit (VBIOS will clear this bit when going to FSDOS)
*/ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
{ struct dc_link *edp_links_with_sink[MAX_NUM_EDP]; struct dc_link *edp_links[MAX_NUM_EDP]; struct dc_stream_state *edp_streams[MAX_NUM_EDP]; struct dc_link *edp_link_with_sink = NULL; struct dc_link *edp_link = NULL; struct pipe_ctx *pipe_ctx = NULL; struct dce_hwseq *hws = dc->hwseq; int edp_with_sink_num; int edp_num; int edp_stream_num; int i; bool can_apply_edp_fast_boot = false; bool can_apply_seamless_boot = false; bool keep_edp_vdd_on = false; struct dc_bios *dcb = dc->ctx->dc_bios;
DC_LOGGER_INIT();
/* Check fastboot support, disable on DCE 6-8 because of blank screens */ if (edp_num && edp_stream_num && dc->ctx->dce_version < DCE_VERSION_10_0) { for (i = 0; i < edp_num; i++) {
edp_link = edp_links[i]; if (edp_link != edp_streams[0]->link) continue; // enable fastboot if backend is enabled on eDP if (edp_link->link_enc->funcs->is_dig_enabled &&
edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
edp_link->link_status.link_active) { struct dc_stream_state *edp_stream = edp_streams[0];
// For Mux-platform, the default value is false. // Disable fast boot during mux switching. // The flag would be clean after switching done. if (dc->is_switch_in_progress_dest && edp_link->is_dds)
can_apply_edp_fast_boot = false;
edp_stream->apply_edp_fast_boot_optimization = can_apply_edp_fast_boot; if (can_apply_edp_fast_boot) {
DC_LOG_EVENT_LINK_TRAINING("eDP fast boot Enable\n");
// Vbios & Driver support different pixel rate div policy.
pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, edp_stream); if (pipe_ctx &&
hws->funcs.is_dp_dig_pixel_rate_div_policy &&
hws->funcs.is_dp_dig_pixel_rate_div_policy(pipe_ctx)) { // Get Vbios div factor from register
dc->res_pool->dccg->funcs->get_pixel_rate_div(
dc->res_pool->dccg,
pipe_ctx->stream_res.tg->inst,
&pipe_ctx->pixel_rate_divider.div_factor1,
&pipe_ctx->pixel_rate_divider.div_factor2);
// VBios doesn't support pixel rate div, so force it. // If VBios supports it, we check it from reigster or other flags.
pipe_ctx->stream_res.pix_clk_params.dio_se_pix_per_cycle = 1;
}
} break;
}
} // We are trying to enable eDP, don't power down VDD if (can_apply_edp_fast_boot)
keep_edp_vdd_on = true;
}
// Check seamless boot support for (i = 0; i < context->stream_count; i++) { if (context->streams[i]->apply_seamless_boot_optimization) {
can_apply_seamless_boot = true; break;
}
}
/* eDP should not have stream in resume from S4 and so even with VBios post * it should get turned off
*/ if (edp_with_sink_num)
edp_link_with_sink = edp_links_with_sink[0];
// During a mux switch, powering down the HW blocks and then enabling // the link via a DPCD SET_POWER write causes a brief flash
keep_edp_vdd_on |= dc->is_switch_in_progress_dest;
if (!can_apply_edp_fast_boot && !can_apply_seamless_boot) { if (edp_link_with_sink && !keep_edp_vdd_on) { /*turn off backlight before DP_blank and encoder powered down*/
hws->funcs.edp_backlight_control(edp_link_with_sink, false);
} /*resume from S3, no vbios posting, no need to power down again*/ if (dcb && dcb->funcs && !dcb->funcs->is_accelerated_mode(dcb))
clk_mgr_exit_optimized_pwr_state(dc, dc->clk_mgr);
power_down_all_hw_blocks(dc);
/* DSC could be enabled on eDP during VBIOS post. * To clean up dsc blocks if eDP is in link but not active.
*/ if (edp_link_with_sink && (edp_stream_num == 0))
clean_up_dsc_blocks(dc);
disable_vga_and_power_gate_all_controllers(dc); if (edp_link_with_sink && !keep_edp_vdd_on)
dc->hwss.edp_power_control(edp_link_with_sink, false); if (dcb && dcb->funcs && !dcb->funcs->is_accelerated_mode(dcb))
clk_mgr_optimize_pwr_state(dc, dc->clk_mgr);
}
bios_set_scratch_acc_mode_change(dc->ctx->dc_bios, 1);
}
if (i == underlay_idx)
res_ctx->pipe_ctx[i].plane_res.mi->funcs->mem_input_program_chroma_display_marks(
res_ctx->pipe_ctx[i].plane_res.mi,
nbp_marks,
max_marks,
max_marks,
MAX_WATERMARK);
}
}
/******************************************************************************* * Public functions
******************************************************************************/
staticvoid set_drr(struct pipe_ctx **pipe_ctx, int num_pipes, struct dc_crtc_timing_adjust adjust)
{ int i = 0; struct drr_params params = {0}; // DRR should set trigger event to monitor surface update event unsignedint event_triggers = 0x80; // Note DRR trigger events are generated regardless of whether num frames met. unsignedint num_frames = 2;
/* TODO: If multiple pipes are to be supported, you need * some GSL stuff. Static screen triggers may be programmed differently * as well.
*/ for (i = 0; i < num_pipes; i++) { /* dc_state_destruct() might null the stream resources, so fetch tg * here first to avoid a race condition. The lifetime of the pointee * itself (the timing_generator object) is not a problem here.
*/ struct timing_generator *tg = pipe_ctx[i]->stream_res.tg;
if ((tg != NULL) && tg->funcs) {
set_drr_and_clear_adjust_pending(pipe_ctx[i], pipe_ctx[i]->stream, ¶ms); if (adjust.v_total_max != 0 && adjust.v_total_min != 0) if (tg->funcs->set_static_screen_control)
tg->funcs->set_static_screen_control(
tg, event_triggers, num_frames);
}
}
}
staticvoid get_position(struct pipe_ctx **pipe_ctx, int num_pipes, struct crtc_position *position)
{ int i = 0;
/* TODO: handle pipes > 1
*/ for (i = 0; i < num_pipes; i++)
pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position);
}
if (params->triggers.overlay_update)
triggers |= 0x100; if (params->triggers.surface_update)
triggers |= 0x80; if (params->triggers.cursor_update)
triggers |= 0x2; if (params->triggers.force_trigger)
triggers |= 0x1;
if (num_pipes) { struct dc *dc = pipe_ctx[0]->stream->ctx->dc;
if (dc->fbc_compressor)
triggers |= 0x84;
}
for (i = 0; i < num_pipes; i++)
pipe_ctx[i]->stream_res.tg->funcs->
set_static_screen_control(pipe_ctx[i]->stream_res.tg,
triggers, params->num_frames);
}
/* * Check if FBC can be enabled
*/ staticbool should_enable_fbc(struct dc *dc, struct dc_state *context,
uint32_t *pipe_idx)
{
uint32_t i; struct pipe_ctx *pipe_ctx = NULL; struct resource_context *res_ctx = &context->res_ctx; unsignedint underlay_idx = dc->res_pool->underlay_pipe_index;
ASSERT(dc->fbc_compressor);
/* FBC memory should be allocated */ if (!dc->ctx->fbc_gpu_addr) returnfalse;
/* Only supports single display */ if (context->stream_count != 1) returnfalse;
for (i = 0; i < dc->res_pool->pipe_count; i++) { if (res_ctx->pipe_ctx[i].stream) {
pipe_ctx = &res_ctx->pipe_ctx[i];
/* fbc not applicable on underlay pipe */
--> --------------------
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.