/* * Copyright 2016 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 *
*/
void dcn201_init_hw(struct dc *dc)
{ int i, j; struct dce_hwseq *hws = dc->hwseq; struct resource_pool *res_pool = dc->res_pool; struct dc_state *context = dc->current_state;
if (res_pool->dccg->funcs->dccg_init)
res_pool->dccg->funcs->dccg_init(res_pool->dccg);
if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
hws->funcs.bios_golden_init(dc);
if (dc->ctx->dc_bios->fw_info_valid) {
res_pool->ref_clocks.xtalin_clock_inKhz =
dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
if (res_pool->hubbub) {
(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
&res_pool->ref_clocks.dccg_ref_clock_inKhz);
(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
res_pool->ref_clocks.dccg_ref_clock_inKhz,
&res_pool->ref_clocks.dchub_ref_clock_inKhz);
} else {
res_pool->ref_clocks.dccg_ref_clock_inKhz =
res_pool->ref_clocks.xtalin_clock_inKhz;
res_pool->ref_clocks.dchub_ref_clock_inKhz =
res_pool->ref_clocks.xtalin_clock_inKhz;
}
} else
ASSERT_CRITICAL(false); for (i = 0; i < dc->link_count; i++) { /* Power up AND update implementation according to the * required signal (which may be different from the * default signal on connector).
*/ struct dc_link *link = dc->links[i];
link->link_enc->funcs->hw_init(link->link_enc);
} if (hws->fb_offset.quad_part == 0)
read_mmhub_vm_setup(hws);
/* Blank pixel data with OPP DPG */ for (i = 0; i < res_pool->timing_generator_count; i++) { struct timing_generator *tg = res_pool->timing_generators[i];
if (tg->funcs->is_tg_enabled(tg)) {
dcn201_init_blank(dc, tg);
}
}
for (i = 0; i < res_pool->timing_generator_count; i++) { struct timing_generator *tg = res_pool->timing_generators[i];
if (tg->funcs->is_tg_enabled(tg))
tg->funcs->lock(tg);
}
for (i = 0; i < res_pool->pipe_count; i++) { struct dpp *dpp = res_pool->dpps[i];
dpp->funcs->dpp_reset(dpp);
}
/* Reset all MPCC muxes */
res_pool->mpc->funcs->mpc_init(res_pool->mpc);
/* initialize OPP mpc_tree parameter */ for (i = 0; i < res_pool->res_cap->num_opp; i++) {
res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;
res_pool->opps[i]->mpc_tree_params.opp_list = NULL; for (j = 0; j < MAX_PIPES; j++)
res_pool->opps[i]->mpcc_disconnect_pending[j] = false;
}
for (i = 0; i < res_pool->timing_generator_count; i++) { struct timing_generator *tg = res_pool->timing_generators[i]; struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; struct hubp *hubp = res_pool->hubps[i]; struct dpp *dpp = res_pool->dpps[i];
res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
pipe_ctx->stream_res.opp = res_pool->opps[i]; /*To do: number of MPCC != number of opp*/
hws->funcs.plane_atomic_disconnect(dc, context, pipe_ctx);
}
/* initialize DWB pointer to MCIF_WB */ for (i = 0; i < res_pool->res_cap->num_dwb; i++)
res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i];
for (i = 0; i < res_pool->timing_generator_count; i++) { struct timing_generator *tg = res_pool->timing_generators[i];
if (tg->funcs->is_tg_enabled(tg))
tg->funcs->unlock(tg);
}
for (i = 0; i < res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
for (i = 0; i < res_pool->timing_generator_count; i++) { struct timing_generator *tg = res_pool->timing_generators[i];
tg->funcs->tg_init(tg);
}
for (i = 0; i < res_pool->audio_count; i++) { struct audio *audio = res_pool->audios[i];
audio->funcs->hw_init(audio);
}
/* power AFMT HDMI memory TODO: may move to dis/en output save power*/
REG_WRITE(DIO_MEM_PWR_CTRL, 0);
if (!dc->debug.disable_clock_gate) { /* enable all DCN clock gating */
REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
}
}
/* trigger HW to start disconnect plane from stream on the next vsync */ void dcn201_plane_atomic_disconnect(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx)
{ struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; int dpp_id = pipe_ctx->plane_res.dpp->inst; struct mpc *mpc = dc->res_pool->mpc; struct mpc_tree *mpc_tree_params; struct mpcc *mpcc_to_remove = NULL; struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; bool mpcc_removed = false;
mpc_tree_params = &(opp->mpc_tree_params);
/* check if this plane is being used by an MPCC in the secondary blending chain */ if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
/* remove MPCC from secondary if being used */ if (mpcc_to_remove != NULL && mpc->funcs->remove_mpcc_from_secondary) {
mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, mpcc_to_remove);
mpcc_removed = true;
}
/* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); if (mpcc_to_remove != NULL) {
mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove);
mpcc_removed = true;
}
/*Already reset*/ if (mpcc_removed == false) return;
/* DCN1.0 has output CM before MPC which seems to screw with * pre-multiplied alpha. This is a w/a hopefully unnecessary for DCN2.
*/
blnd_cfg.pre_multiplied_alpha = per_pixel_alpha;
/* * TODO: remove hack * Note: currently there is a bug in init_hw such that * on resume from hibernate, BIOS sets up MPCC0, and * we do mpcc_remove but the mpcc cannot go to idle * after remove. This cause us to pick mpcc1 here, * which causes a pstate hang for yet unknown reason.
*/
dpp_id = hubp->inst;
mpcc_id = dpp_id;
/* If there is no full update, don't need to touch MPC tree*/ if (!pipe_ctx->plane_state->update_flags.bits.full_update) {
dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); return;
}
/* check if this plane is being used by an MPCC in the secondary blending chain */ if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
remove_mpcc = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
/* remove MPCC from secondary if being used */ if (remove_mpcc != NULL && mpc->funcs->remove_mpcc_from_secondary)
mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, remove_mpcc);
/* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
remove_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); /* remove MPCC if being used */
if (remove_mpcc != NULL)
mpc->funcs->remove_mpcc(mpc, mpc_tree_params, remove_mpcc); else if (dc->debug.sanity_checks)
mpc->funcs->assert_mpcc_idle_before_connect(
dc->res_pool->mpc, mpcc_id);
/* Call MPC to insert new plane */
dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
mpc_tree_params,
&blnd_cfg,
NULL,
NULL,
dpp_id,
mpcc_id);
void dcn201_pipe_control_lock( struct dc *dc, struct pipe_ctx *pipe, bool lock)
{ struct dce_hwseq *hws = dc->hwseq; /* use TG master update lock to lock everything on the TG * therefore only top pipe need to lock
*/ if (pipe->top_pipe) return;
if (dc->debug.sanity_checks)
hws->funcs.verify_allow_pstate_change_high(dc);
if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) { if (lock)
pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg); else
pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);
} else { if (lock)
pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); else
pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
}
if (dc->debug.sanity_checks)
hws->funcs.verify_allow_pstate_change_high(dc);
}
if (dc_is_dp_signal(pipe_ctx->stream->signal)) { /*check whether it is half the rate*/ if (pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing))
params.timing.pix_clk_100hz /= 2;
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.