13f68c01bSZhan Liu /*
23f68c01bSZhan Liu * Copyright 2016 Advanced Micro Devices, Inc.
33f68c01bSZhan Liu *
43f68c01bSZhan Liu * Permission is hereby granted, free of charge, to any person obtaining a
53f68c01bSZhan Liu * copy of this software and associated documentation files (the "Software"),
63f68c01bSZhan Liu * to deal in the Software without restriction, including without limitation
73f68c01bSZhan Liu * the rights to use, copy, modify, merge, publish, distribute, sublicense,
83f68c01bSZhan Liu * and/or sell copies of the Software, and to permit persons to whom the
93f68c01bSZhan Liu * Software is furnished to do so, subject to the following conditions:
103f68c01bSZhan Liu *
113f68c01bSZhan Liu * The above copyright notice and this permission notice shall be included in
123f68c01bSZhan Liu * all copies or substantial portions of the Software.
133f68c01bSZhan Liu *
143f68c01bSZhan Liu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
153f68c01bSZhan Liu * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
163f68c01bSZhan Liu * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
173f68c01bSZhan Liu * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
183f68c01bSZhan Liu * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
193f68c01bSZhan Liu * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
203f68c01bSZhan Liu * OTHER DEALINGS IN THE SOFTWARE.
213f68c01bSZhan Liu *
223f68c01bSZhan Liu * Authors: AMD
233f68c01bSZhan Liu *
243f68c01bSZhan Liu */
253f68c01bSZhan Liu
263f68c01bSZhan Liu #include "dm_services.h"
273f68c01bSZhan Liu #include "basics/dc_common.h"
283f68c01bSZhan Liu #include "core_types.h"
293f68c01bSZhan Liu #include "resource.h"
303f68c01bSZhan Liu #include "dcn201_hwseq.h"
31e53524cdSMounika Adhuri #include "dcn201/dcn201_optc.h"
323f68c01bSZhan Liu #include "dce/dce_hwseq.h"
333f68c01bSZhan Liu #include "hubp.h"
343f68c01bSZhan Liu #include "dchubbub.h"
353f68c01bSZhan Liu #include "timing_generator.h"
363f68c01bSZhan Liu #include "opp.h"
373f68c01bSZhan Liu #include "ipp.h"
383f68c01bSZhan Liu #include "mpc.h"
393f68c01bSZhan Liu #include "dccg.h"
403f68c01bSZhan Liu #include "clk_mgr.h"
413f68c01bSZhan Liu #include "reg_helper.h"
423f68c01bSZhan Liu
433f68c01bSZhan Liu #define CTX \
443f68c01bSZhan Liu hws->ctx
453f68c01bSZhan Liu
463f68c01bSZhan Liu #define REG(reg)\
473f68c01bSZhan Liu hws->regs->reg
483f68c01bSZhan Liu
493f68c01bSZhan Liu #define DC_LOGGER \
503f68c01bSZhan Liu dc->ctx->logger
513f68c01bSZhan Liu
523f68c01bSZhan Liu #undef FN
533f68c01bSZhan Liu #define FN(reg_name, field_name) \
543f68c01bSZhan Liu hws->shifts->field_name, hws->masks->field_name
553f68c01bSZhan Liu
patch_address_for_sbs_tb_stereo(struct pipe_ctx * pipe_ctx,PHYSICAL_ADDRESS_LOC * addr)563f68c01bSZhan Liu static bool patch_address_for_sbs_tb_stereo(
573f68c01bSZhan Liu struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
583f68c01bSZhan Liu {
593f68c01bSZhan Liu struct dc_plane_state *plane_state = pipe_ctx->plane_state;
603f68c01bSZhan Liu bool sec_split = pipe_ctx->top_pipe &&
613f68c01bSZhan Liu pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state;
623f68c01bSZhan Liu
633f68c01bSZhan Liu if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
643f68c01bSZhan Liu (pipe_ctx->stream->timing.timing_3d_format ==
653f68c01bSZhan Liu TIMING_3D_FORMAT_SIDE_BY_SIDE ||
663f68c01bSZhan Liu pipe_ctx->stream->timing.timing_3d_format ==
673f68c01bSZhan Liu TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
683f68c01bSZhan Liu *addr = plane_state->address.grph_stereo.left_addr;
693f68c01bSZhan Liu plane_state->address.grph_stereo.left_addr =
703f68c01bSZhan Liu plane_state->address.grph_stereo.right_addr;
713f68c01bSZhan Liu return true;
723f68c01bSZhan Liu } else {
733f68c01bSZhan Liu if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE &&
743f68c01bSZhan Liu plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) {
753f68c01bSZhan Liu plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO;
763f68c01bSZhan Liu plane_state->address.grph_stereo.right_addr =
773f68c01bSZhan Liu plane_state->address.grph_stereo.left_addr;
783f68c01bSZhan Liu plane_state->address.grph_stereo.right_meta_addr =
793f68c01bSZhan Liu plane_state->address.grph_stereo.left_meta_addr;
803f68c01bSZhan Liu }
813f68c01bSZhan Liu }
823f68c01bSZhan Liu return false;
833f68c01bSZhan Liu }
843f68c01bSZhan Liu
gpu_addr_to_uma(struct dce_hwseq * hwseq,PHYSICAL_ADDRESS_LOC * addr)858434f818SCharlene Liu static bool gpu_addr_to_uma(struct dce_hwseq *hwseq,
863f68c01bSZhan Liu PHYSICAL_ADDRESS_LOC *addr)
873f68c01bSZhan Liu {
883f68c01bSZhan Liu bool is_in_uma;
893f68c01bSZhan Liu
903f68c01bSZhan Liu if (hwseq->fb_base.quad_part <= addr->quad_part &&
913f68c01bSZhan Liu addr->quad_part < hwseq->fb_top.quad_part) {
923f68c01bSZhan Liu addr->quad_part -= hwseq->fb_base.quad_part;
933f68c01bSZhan Liu addr->quad_part += hwseq->fb_offset.quad_part;
943f68c01bSZhan Liu is_in_uma = true;
953f68c01bSZhan Liu } else if (hwseq->fb_offset.quad_part <= addr->quad_part &&
963f68c01bSZhan Liu addr->quad_part <= hwseq->uma_top.quad_part) {
973f68c01bSZhan Liu is_in_uma = true;
9802fb803dSRodrigo Siqueira } else if (addr->quad_part == 0) {
9902fb803dSRodrigo Siqueira is_in_uma = false;
1003f68c01bSZhan Liu } else {
1013f68c01bSZhan Liu is_in_uma = false;
10202fb803dSRodrigo Siqueira BREAK_TO_DEBUGGER();
1033f68c01bSZhan Liu }
1048434f818SCharlene Liu return is_in_uma;
1053f68c01bSZhan Liu }
1063f68c01bSZhan Liu
plane_address_in_gpu_space_to_uma(struct dce_hwseq * hwseq,struct dc_plane_address * addr)1073f68c01bSZhan Liu static void plane_address_in_gpu_space_to_uma(struct dce_hwseq *hwseq,
1083f68c01bSZhan Liu struct dc_plane_address *addr)
1093f68c01bSZhan Liu {
1103f68c01bSZhan Liu switch (addr->type) {
1113f68c01bSZhan Liu case PLN_ADDR_TYPE_GRAPHICS:
1123f68c01bSZhan Liu gpu_addr_to_uma(hwseq, &addr->grph.addr);
1133f68c01bSZhan Liu gpu_addr_to_uma(hwseq, &addr->grph.meta_addr);
1143f68c01bSZhan Liu break;
1153f68c01bSZhan Liu case PLN_ADDR_TYPE_GRPH_STEREO:
1163f68c01bSZhan Liu gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_addr);
1173f68c01bSZhan Liu gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_meta_addr);
1183f68c01bSZhan Liu gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_addr);
1193f68c01bSZhan Liu gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_meta_addr);
1203f68c01bSZhan Liu break;
1213f68c01bSZhan Liu case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE:
1223f68c01bSZhan Liu gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_addr);
1233f68c01bSZhan Liu gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_meta_addr);
1243f68c01bSZhan Liu gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_addr);
1253f68c01bSZhan Liu gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_meta_addr);
1263f68c01bSZhan Liu break;
1273f68c01bSZhan Liu default:
1283f68c01bSZhan Liu BREAK_TO_DEBUGGER();
1293f68c01bSZhan Liu break;
1303f68c01bSZhan Liu }
1313f68c01bSZhan Liu }
1323f68c01bSZhan Liu
dcn201_update_plane_addr(const struct dc * dc,struct pipe_ctx * pipe_ctx)1333f68c01bSZhan Liu void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
1343f68c01bSZhan Liu {
1353f68c01bSZhan Liu bool addr_patched = false;
1363f68c01bSZhan Liu PHYSICAL_ADDRESS_LOC addr;
1373f68c01bSZhan Liu struct dc_plane_state *plane_state = pipe_ctx->plane_state;
1383f68c01bSZhan Liu struct dce_hwseq *hws = dc->hwseq;
139f28cad86SJosé Expósito struct dc_plane_address uma;
1403f68c01bSZhan Liu
1413f68c01bSZhan Liu if (plane_state == NULL)
1423f68c01bSZhan Liu return;
1433f68c01bSZhan Liu
144f28cad86SJosé Expósito uma = plane_state->address;
1453f68c01bSZhan Liu addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
1463f68c01bSZhan Liu
1473f68c01bSZhan Liu plane_address_in_gpu_space_to_uma(hws, &uma);
1483f68c01bSZhan Liu
1493f68c01bSZhan Liu pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
1503f68c01bSZhan Liu pipe_ctx->plane_res.hubp,
1513f68c01bSZhan Liu &uma,
1523f68c01bSZhan Liu plane_state->flip_immediate);
1533f68c01bSZhan Liu
1543f68c01bSZhan Liu plane_state->status.requested_address = plane_state->address;
1553f68c01bSZhan Liu
1563f68c01bSZhan Liu if (plane_state->flip_immediate)
1573f68c01bSZhan Liu plane_state->status.current_address = plane_state->address;
1583f68c01bSZhan Liu
1593f68c01bSZhan Liu if (addr_patched)
1603f68c01bSZhan Liu pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
1613f68c01bSZhan Liu }
1623f68c01bSZhan Liu
1633f68c01bSZhan Liu /* Blank pixel data during initialization */
dcn201_init_blank(struct dc * dc,struct timing_generator * tg)1643f68c01bSZhan Liu void dcn201_init_blank(
1653f68c01bSZhan Liu struct dc *dc,
1663f68c01bSZhan Liu struct timing_generator *tg)
1673f68c01bSZhan Liu {
1683f68c01bSZhan Liu struct dce_hwseq *hws = dc->hwseq;
1693f68c01bSZhan Liu enum dc_color_space color_space;
1703f68c01bSZhan Liu struct tg_color black_color = {0};
1713f68c01bSZhan Liu struct output_pixel_processor *opp = NULL;
1723f68c01bSZhan Liu uint32_t num_opps, opp_id_src0, opp_id_src1;
173ba3193faSAlex Hung uint32_t otg_active_width = 0, otg_active_height = 0;
1743f68c01bSZhan Liu
1753f68c01bSZhan Liu /* program opp dpg blank color */
1763f68c01bSZhan Liu color_space = COLOR_SPACE_SRGB;
1773f68c01bSZhan Liu color_space_to_black_color(dc, color_space, &black_color);
1783f68c01bSZhan Liu
1793f68c01bSZhan Liu /* get the OTG active size */
1803f68c01bSZhan Liu tg->funcs->get_otg_active_size(tg,
1813f68c01bSZhan Liu &otg_active_width,
1823f68c01bSZhan Liu &otg_active_height);
1833f68c01bSZhan Liu
1843f68c01bSZhan Liu /* get the OPTC source */
1853f68c01bSZhan Liu tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);
1863f68c01bSZhan Liu ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp);
1873f68c01bSZhan Liu opp = dc->res_pool->opps[opp_id_src0];
1883f68c01bSZhan Liu
1893f68c01bSZhan Liu opp->funcs->opp_set_disp_pattern_generator(
1903f68c01bSZhan Liu opp,
1913f68c01bSZhan Liu CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
1923f68c01bSZhan Liu CONTROLLER_DP_COLOR_SPACE_UDEFINED,
1933f68c01bSZhan Liu COLOR_DEPTH_UNDEFINED,
1943f68c01bSZhan Liu &black_color,
1953f68c01bSZhan Liu otg_active_width,
1963f68c01bSZhan Liu otg_active_height,
1973f68c01bSZhan Liu 0);
1983f68c01bSZhan Liu
1993f68c01bSZhan Liu hws->funcs.wait_for_blank_complete(opp);
2003f68c01bSZhan Liu }
2013f68c01bSZhan Liu
read_mmhub_vm_setup(struct dce_hwseq * hws)2023f68c01bSZhan Liu static void read_mmhub_vm_setup(struct dce_hwseq *hws)
2033f68c01bSZhan Liu {
2043f68c01bSZhan Liu uint32_t fb_base = REG_READ(MC_VM_FB_LOCATION_BASE);
2053f68c01bSZhan Liu uint32_t fb_top = REG_READ(MC_VM_FB_LOCATION_TOP);
2063f68c01bSZhan Liu uint32_t fb_offset = REG_READ(MC_VM_FB_OFFSET);
2073f68c01bSZhan Liu
2083f68c01bSZhan Liu /* MC_VM_FB_LOCATION_TOP is in pages, actual top should add 1 */
2093f68c01bSZhan Liu fb_top++;
2103f68c01bSZhan Liu
2113f68c01bSZhan Liu /* bit 23:0 in register map to bit 47:24 in address */
2123f68c01bSZhan Liu hws->fb_base.low_part = fb_base;
2133f68c01bSZhan Liu hws->fb_base.quad_part <<= 24;
2143f68c01bSZhan Liu
2153f68c01bSZhan Liu hws->fb_top.low_part = fb_top;
2163f68c01bSZhan Liu hws->fb_top.quad_part <<= 24;
2173f68c01bSZhan Liu hws->fb_offset.low_part = fb_offset;
2183f68c01bSZhan Liu hws->fb_offset.quad_part <<= 24;
2193f68c01bSZhan Liu
2203f68c01bSZhan Liu hws->uma_top.quad_part = hws->fb_top.quad_part
2213f68c01bSZhan Liu - hws->fb_base.quad_part + hws->fb_offset.quad_part;
2223f68c01bSZhan Liu }
2233f68c01bSZhan Liu
dcn201_init_hw(struct dc * dc)2243f68c01bSZhan Liu void dcn201_init_hw(struct dc *dc)
2253f68c01bSZhan Liu {
2263f68c01bSZhan Liu int i, j;
2273f68c01bSZhan Liu struct dce_hwseq *hws = dc->hwseq;
2283f68c01bSZhan Liu struct resource_pool *res_pool = dc->res_pool;
2293f68c01bSZhan Liu struct dc_state *context = dc->current_state;
2303f68c01bSZhan Liu
2313f68c01bSZhan Liu if (res_pool->dccg->funcs->dccg_init)
2323f68c01bSZhan Liu res_pool->dccg->funcs->dccg_init(res_pool->dccg);
2333f68c01bSZhan Liu
2343f68c01bSZhan Liu if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
2353f68c01bSZhan Liu dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
2363f68c01bSZhan Liu
2373f68c01bSZhan Liu hws->funcs.bios_golden_init(dc);
2383f68c01bSZhan Liu
2393f68c01bSZhan Liu if (dc->ctx->dc_bios->fw_info_valid) {
2403f68c01bSZhan Liu res_pool->ref_clocks.xtalin_clock_inKhz =
2413f68c01bSZhan Liu dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
2423f68c01bSZhan Liu
2431a664dc0SAlex Hung if (res_pool->hubbub) {
2443f68c01bSZhan Liu (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
2453f68c01bSZhan Liu dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
2463f68c01bSZhan Liu &res_pool->ref_clocks.dccg_ref_clock_inKhz);
2473f68c01bSZhan Liu
2483f68c01bSZhan Liu (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
2493f68c01bSZhan Liu res_pool->ref_clocks.dccg_ref_clock_inKhz,
2503f68c01bSZhan Liu &res_pool->ref_clocks.dchub_ref_clock_inKhz);
2513f68c01bSZhan Liu } else {
2523f68c01bSZhan Liu res_pool->ref_clocks.dccg_ref_clock_inKhz =
2533f68c01bSZhan Liu res_pool->ref_clocks.xtalin_clock_inKhz;
2543f68c01bSZhan Liu res_pool->ref_clocks.dchub_ref_clock_inKhz =
2553f68c01bSZhan Liu res_pool->ref_clocks.xtalin_clock_inKhz;
2563f68c01bSZhan Liu }
2573f68c01bSZhan Liu } else
2583f68c01bSZhan Liu ASSERT_CRITICAL(false);
2593f68c01bSZhan Liu for (i = 0; i < dc->link_count; i++) {
2603f68c01bSZhan Liu /* Power up AND update implementation according to the
2613f68c01bSZhan Liu * required signal (which may be different from the
2623f68c01bSZhan Liu * default signal on connector).
2633f68c01bSZhan Liu */
2643f68c01bSZhan Liu struct dc_link *link = dc->links[i];
2653f68c01bSZhan Liu
2663f68c01bSZhan Liu link->link_enc->funcs->hw_init(link->link_enc);
2673f68c01bSZhan Liu }
2683f68c01bSZhan Liu if (hws->fb_offset.quad_part == 0)
2693f68c01bSZhan Liu read_mmhub_vm_setup(hws);
2703f68c01bSZhan Liu
2713f68c01bSZhan Liu /* Blank pixel data with OPP DPG */
2723f68c01bSZhan Liu for (i = 0; i < res_pool->timing_generator_count; i++) {
2733f68c01bSZhan Liu struct timing_generator *tg = res_pool->timing_generators[i];
2743f68c01bSZhan Liu
2753f68c01bSZhan Liu if (tg->funcs->is_tg_enabled(tg)) {
2763f68c01bSZhan Liu dcn201_init_blank(dc, tg);
2773f68c01bSZhan Liu }
2783f68c01bSZhan Liu }
2793f68c01bSZhan Liu
2803f68c01bSZhan Liu for (i = 0; i < res_pool->timing_generator_count; i++) {
2813f68c01bSZhan Liu struct timing_generator *tg = res_pool->timing_generators[i];
2823f68c01bSZhan Liu
2833f68c01bSZhan Liu if (tg->funcs->is_tg_enabled(tg))
2843f68c01bSZhan Liu tg->funcs->lock(tg);
2853f68c01bSZhan Liu }
2863f68c01bSZhan Liu
2873f68c01bSZhan Liu for (i = 0; i < res_pool->pipe_count; i++) {
2883f68c01bSZhan Liu struct dpp *dpp = res_pool->dpps[i];
2893f68c01bSZhan Liu
2903f68c01bSZhan Liu dpp->funcs->dpp_reset(dpp);
2913f68c01bSZhan Liu }
2923f68c01bSZhan Liu
2933f68c01bSZhan Liu /* Reset all MPCC muxes */
2943f68c01bSZhan Liu res_pool->mpc->funcs->mpc_init(res_pool->mpc);
2953f68c01bSZhan Liu
2963f68c01bSZhan Liu /* initialize OPP mpc_tree parameter */
2973f68c01bSZhan Liu for (i = 0; i < res_pool->res_cap->num_opp; i++) {
2983f68c01bSZhan Liu res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;
2993f68c01bSZhan Liu res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
3003f68c01bSZhan Liu for (j = 0; j < MAX_PIPES; j++)
3013f68c01bSZhan Liu res_pool->opps[i]->mpcc_disconnect_pending[j] = false;
3023f68c01bSZhan Liu }
3033f68c01bSZhan Liu
3043f68c01bSZhan Liu for (i = 0; i < res_pool->timing_generator_count; i++) {
3053f68c01bSZhan Liu struct timing_generator *tg = res_pool->timing_generators[i];
3063f68c01bSZhan Liu struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
3073f68c01bSZhan Liu struct hubp *hubp = res_pool->hubps[i];
3083f68c01bSZhan Liu struct dpp *dpp = res_pool->dpps[i];
3093f68c01bSZhan Liu
3103f68c01bSZhan Liu pipe_ctx->stream_res.tg = tg;
3113f68c01bSZhan Liu pipe_ctx->pipe_idx = i;
3123f68c01bSZhan Liu
3133f68c01bSZhan Liu pipe_ctx->plane_res.hubp = hubp;
3143f68c01bSZhan Liu pipe_ctx->plane_res.dpp = dpp;
3153f68c01bSZhan Liu pipe_ctx->plane_res.mpcc_inst = dpp->inst;
3163f68c01bSZhan Liu hubp->mpcc_id = dpp->inst;
3173f68c01bSZhan Liu hubp->opp_id = OPP_ID_INVALID;
3183f68c01bSZhan Liu hubp->power_gated = false;
3193f68c01bSZhan Liu pipe_ctx->stream_res.opp = NULL;
3203f68c01bSZhan Liu
3213f68c01bSZhan Liu hubp->funcs->hubp_init(hubp);
3223f68c01bSZhan Liu
3233f68c01bSZhan Liu res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
3243f68c01bSZhan Liu pipe_ctx->stream_res.opp = res_pool->opps[i];
3253f68c01bSZhan Liu /*To do: number of MPCC != number of opp*/
326012a04b1SDillon Varone hws->funcs.plane_atomic_disconnect(dc, context, pipe_ctx);
3273f68c01bSZhan Liu }
3283f68c01bSZhan Liu
3293f68c01bSZhan Liu /* initialize DWB pointer to MCIF_WB */
3303f68c01bSZhan Liu for (i = 0; i < res_pool->res_cap->num_dwb; i++)
3313f68c01bSZhan Liu res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i];
3323f68c01bSZhan Liu
3333f68c01bSZhan Liu for (i = 0; i < res_pool->timing_generator_count; i++) {
3343f68c01bSZhan Liu struct timing_generator *tg = res_pool->timing_generators[i];
3353f68c01bSZhan Liu
3363f68c01bSZhan Liu if (tg->funcs->is_tg_enabled(tg))
3373f68c01bSZhan Liu tg->funcs->unlock(tg);
3383f68c01bSZhan Liu }
3393f68c01bSZhan Liu
3403f68c01bSZhan Liu for (i = 0; i < res_pool->pipe_count; i++) {
3413f68c01bSZhan Liu struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
3423f68c01bSZhan Liu
343012a04b1SDillon Varone dc->hwss.disable_plane(dc, context, pipe_ctx);
3443f68c01bSZhan Liu
3453f68c01bSZhan Liu pipe_ctx->stream_res.tg = NULL;
3463f68c01bSZhan Liu pipe_ctx->plane_res.hubp = NULL;
3473f68c01bSZhan Liu }
3483f68c01bSZhan Liu
3493f68c01bSZhan Liu for (i = 0; i < res_pool->timing_generator_count; i++) {
3503f68c01bSZhan Liu struct timing_generator *tg = res_pool->timing_generators[i];
3513f68c01bSZhan Liu
3523f68c01bSZhan Liu tg->funcs->tg_init(tg);
3533f68c01bSZhan Liu }
3543f68c01bSZhan Liu
3553f68c01bSZhan Liu for (i = 0; i < res_pool->audio_count; i++) {
3563f68c01bSZhan Liu struct audio *audio = res_pool->audios[i];
3573f68c01bSZhan Liu
3583f68c01bSZhan Liu audio->funcs->hw_init(audio);
3593f68c01bSZhan Liu }
3603f68c01bSZhan Liu
3613f68c01bSZhan Liu /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
3623f68c01bSZhan Liu REG_WRITE(DIO_MEM_PWR_CTRL, 0);
3633f68c01bSZhan Liu
3643f68c01bSZhan Liu if (!dc->debug.disable_clock_gate) {
3653f68c01bSZhan Liu /* enable all DCN clock gating */
3663f68c01bSZhan Liu REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
3673f68c01bSZhan Liu
3683f68c01bSZhan Liu REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
3693f68c01bSZhan Liu
3703f68c01bSZhan Liu REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
3713f68c01bSZhan Liu }
3723f68c01bSZhan Liu }
3733f68c01bSZhan Liu
3743f68c01bSZhan Liu /* trigger HW to start disconnect plane from stream on the next vsync */
dcn201_plane_atomic_disconnect(struct dc * dc,struct dc_state * state,struct pipe_ctx * pipe_ctx)375012a04b1SDillon Varone void dcn201_plane_atomic_disconnect(struct dc *dc,
376012a04b1SDillon Varone struct dc_state *state,
377012a04b1SDillon Varone struct pipe_ctx *pipe_ctx)
3783f68c01bSZhan Liu {
3793f68c01bSZhan Liu struct dce_hwseq *hws = dc->hwseq;
3803f68c01bSZhan Liu struct hubp *hubp = pipe_ctx->plane_res.hubp;
3813f68c01bSZhan Liu int dpp_id = pipe_ctx->plane_res.dpp->inst;
3823f68c01bSZhan Liu struct mpc *mpc = dc->res_pool->mpc;
3833f68c01bSZhan Liu struct mpc_tree *mpc_tree_params;
3843f68c01bSZhan Liu struct mpcc *mpcc_to_remove = NULL;
3853f68c01bSZhan Liu struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
3863f68c01bSZhan Liu bool mpcc_removed = false;
3873f68c01bSZhan Liu
3883f68c01bSZhan Liu mpc_tree_params = &(opp->mpc_tree_params);
3893f68c01bSZhan Liu
3903f68c01bSZhan Liu /* check if this plane is being used by an MPCC in the secondary blending chain */
3913f68c01bSZhan Liu if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
3923f68c01bSZhan Liu mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
3933f68c01bSZhan Liu
3943f68c01bSZhan Liu /* remove MPCC from secondary if being used */
3953f68c01bSZhan Liu if (mpcc_to_remove != NULL && mpc->funcs->remove_mpcc_from_secondary) {
3963f68c01bSZhan Liu mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, mpcc_to_remove);
3973f68c01bSZhan Liu mpcc_removed = true;
3983f68c01bSZhan Liu }
3993f68c01bSZhan Liu
4003f68c01bSZhan Liu /* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
4013f68c01bSZhan Liu mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
4023f68c01bSZhan Liu if (mpcc_to_remove != NULL) {
4033f68c01bSZhan Liu mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove);
4043f68c01bSZhan Liu mpcc_removed = true;
4053f68c01bSZhan Liu }
4063f68c01bSZhan Liu
4073f68c01bSZhan Liu /*Already reset*/
4083f68c01bSZhan Liu if (mpcc_removed == false)
4093f68c01bSZhan Liu return;
4103f68c01bSZhan Liu
4113f68c01bSZhan Liu opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
4123f68c01bSZhan Liu
4133f68c01bSZhan Liu dc->optimized_required = true;
4143f68c01bSZhan Liu
4153f68c01bSZhan Liu if (hubp->funcs->hubp_disconnect)
4163f68c01bSZhan Liu hubp->funcs->hubp_disconnect(hubp);
4173f68c01bSZhan Liu
4183f68c01bSZhan Liu if (dc->debug.sanity_checks)
4193f68c01bSZhan Liu hws->funcs.verify_allow_pstate_change_high(dc);
4203f68c01bSZhan Liu }
4213f68c01bSZhan Liu
dcn201_update_mpcc(struct dc * dc,struct pipe_ctx * pipe_ctx)4223f68c01bSZhan Liu void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
4233f68c01bSZhan Liu {
4243f68c01bSZhan Liu struct hubp *hubp = pipe_ctx->plane_res.hubp;
4253f68c01bSZhan Liu struct mpcc_blnd_cfg blnd_cfg;
4263f68c01bSZhan Liu bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
4273f68c01bSZhan Liu int mpcc_id, dpp_id;
4283f68c01bSZhan Liu struct mpcc *new_mpcc;
4293f68c01bSZhan Liu struct mpcc *remove_mpcc = NULL;
4303f68c01bSZhan Liu struct mpc *mpc = dc->res_pool->mpc;
4313f68c01bSZhan Liu struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
4323f68c01bSZhan Liu
4333f68c01bSZhan Liu if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) {
4343f68c01bSZhan Liu get_hdr_visual_confirm_color(
4353f68c01bSZhan Liu pipe_ctx, &blnd_cfg.black_color);
4363f68c01bSZhan Liu } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) {
4373f68c01bSZhan Liu get_surface_visual_confirm_color(
4383f68c01bSZhan Liu pipe_ctx, &blnd_cfg.black_color);
4393f68c01bSZhan Liu } else {
4403f68c01bSZhan Liu color_space_to_black_color(
4413f68c01bSZhan Liu dc, pipe_ctx->stream->output_color_space,
4423f68c01bSZhan Liu &blnd_cfg.black_color);
4433f68c01bSZhan Liu }
4443f68c01bSZhan Liu
4453f68c01bSZhan Liu if (per_pixel_alpha)
4463f68c01bSZhan Liu blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
4473f68c01bSZhan Liu else
4483f68c01bSZhan Liu blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
4493f68c01bSZhan Liu
4503f68c01bSZhan Liu blnd_cfg.overlap_only = false;
4513f68c01bSZhan Liu
4523f68c01bSZhan Liu if (pipe_ctx->plane_state->global_alpha_value)
4533f68c01bSZhan Liu blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
4543f68c01bSZhan Liu else
4553f68c01bSZhan Liu blnd_cfg.global_alpha = 0xff;
4563f68c01bSZhan Liu
4573f68c01bSZhan Liu blnd_cfg.global_gain = 0xff;
4583f68c01bSZhan Liu blnd_cfg.background_color_bpc = 4;
4593f68c01bSZhan Liu blnd_cfg.bottom_gain_mode = 0;
4603f68c01bSZhan Liu blnd_cfg.top_gain = 0x1f000;
4613f68c01bSZhan Liu blnd_cfg.bottom_inside_gain = 0x1f000;
4623f68c01bSZhan Liu blnd_cfg.bottom_outside_gain = 0x1f000;
4633f68c01bSZhan Liu /*the input to MPCC is RGB*/
4643f68c01bSZhan Liu blnd_cfg.black_color.color_b_cb = 0;
4653f68c01bSZhan Liu blnd_cfg.black_color.color_g_y = 0;
4663f68c01bSZhan Liu blnd_cfg.black_color.color_r_cr = 0;
4673f68c01bSZhan Liu
4683f68c01bSZhan Liu /* DCN1.0 has output CM before MPC which seems to screw with
4693f68c01bSZhan Liu * pre-multiplied alpha. This is a w/a hopefully unnecessary for DCN2.
4703f68c01bSZhan Liu */
4713f68c01bSZhan Liu blnd_cfg.pre_multiplied_alpha = per_pixel_alpha;
4723f68c01bSZhan Liu
4733f68c01bSZhan Liu /*
4743f68c01bSZhan Liu * TODO: remove hack
4753f68c01bSZhan Liu * Note: currently there is a bug in init_hw such that
4763f68c01bSZhan Liu * on resume from hibernate, BIOS sets up MPCC0, and
4773f68c01bSZhan Liu * we do mpcc_remove but the mpcc cannot go to idle
4783f68c01bSZhan Liu * after remove. This cause us to pick mpcc1 here,
4793f68c01bSZhan Liu * which causes a pstate hang for yet unknown reason.
4803f68c01bSZhan Liu */
4813f68c01bSZhan Liu dpp_id = hubp->inst;
4823f68c01bSZhan Liu mpcc_id = dpp_id;
4833f68c01bSZhan Liu
4843f68c01bSZhan Liu /* If there is no full update, don't need to touch MPC tree*/
4853f68c01bSZhan Liu if (!pipe_ctx->plane_state->update_flags.bits.full_update) {
486d205a800SLeo (Hanghong) Ma dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
4873f68c01bSZhan Liu mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);
4883f68c01bSZhan Liu return;
4893f68c01bSZhan Liu }
4903f68c01bSZhan Liu
4913f68c01bSZhan Liu /* check if this plane is being used by an MPCC in the secondary blending chain */
4923f68c01bSZhan Liu if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
4933f68c01bSZhan Liu remove_mpcc = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
4943f68c01bSZhan Liu
4953f68c01bSZhan Liu /* remove MPCC from secondary if being used */
4963f68c01bSZhan Liu if (remove_mpcc != NULL && mpc->funcs->remove_mpcc_from_secondary)
4973f68c01bSZhan Liu mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, remove_mpcc);
4983f68c01bSZhan Liu
4993f68c01bSZhan Liu /* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
5003f68c01bSZhan Liu remove_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
5013f68c01bSZhan Liu /* remove MPCC if being used */
5023f68c01bSZhan Liu
5033f68c01bSZhan Liu if (remove_mpcc != NULL)
5043f68c01bSZhan Liu mpc->funcs->remove_mpcc(mpc, mpc_tree_params, remove_mpcc);
5053f68c01bSZhan Liu else
5063f68c01bSZhan Liu if (dc->debug.sanity_checks)
5073f68c01bSZhan Liu mpc->funcs->assert_mpcc_idle_before_connect(
5083f68c01bSZhan Liu dc->res_pool->mpc, mpcc_id);
5093f68c01bSZhan Liu
5103f68c01bSZhan Liu /* Call MPC to insert new plane */
511d205a800SLeo (Hanghong) Ma dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
5123f68c01bSZhan Liu new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
5133f68c01bSZhan Liu mpc_tree_params,
5143f68c01bSZhan Liu &blnd_cfg,
5153f68c01bSZhan Liu NULL,
5163f68c01bSZhan Liu NULL,
5173f68c01bSZhan Liu dpp_id,
5183f68c01bSZhan Liu mpcc_id);
5193f68c01bSZhan Liu
5203f68c01bSZhan Liu ASSERT(new_mpcc != NULL);
5213f68c01bSZhan Liu hubp->opp_id = pipe_ctx->stream_res.opp->inst;
5223f68c01bSZhan Liu hubp->mpcc_id = mpcc_id;
5233f68c01bSZhan Liu }
5243f68c01bSZhan Liu
dcn201_pipe_control_lock(struct dc * dc,struct pipe_ctx * pipe,bool lock)5253f68c01bSZhan Liu void dcn201_pipe_control_lock(
5263f68c01bSZhan Liu struct dc *dc,
5273f68c01bSZhan Liu struct pipe_ctx *pipe,
5283f68c01bSZhan Liu bool lock)
5293f68c01bSZhan Liu {
5303f68c01bSZhan Liu struct dce_hwseq *hws = dc->hwseq;
5313f68c01bSZhan Liu /* use TG master update lock to lock everything on the TG
5323f68c01bSZhan Liu * therefore only top pipe need to lock
5333f68c01bSZhan Liu */
5343f68c01bSZhan Liu if (pipe->top_pipe)
5353f68c01bSZhan Liu return;
5363f68c01bSZhan Liu
5373f68c01bSZhan Liu if (dc->debug.sanity_checks)
5383f68c01bSZhan Liu hws->funcs.verify_allow_pstate_change_high(dc);
5393f68c01bSZhan Liu
5403f68c01bSZhan Liu if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) {
5413f68c01bSZhan Liu if (lock)
5423f68c01bSZhan Liu pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg);
5433f68c01bSZhan Liu else
5443f68c01bSZhan Liu pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);
5453f68c01bSZhan Liu } else {
5463f68c01bSZhan Liu if (lock)
5473f68c01bSZhan Liu pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
5483f68c01bSZhan Liu else
5493f68c01bSZhan Liu pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
5503f68c01bSZhan Liu }
5513f68c01bSZhan Liu
5523f68c01bSZhan Liu if (dc->debug.sanity_checks)
5533f68c01bSZhan Liu hws->funcs.verify_allow_pstate_change_high(dc);
5543f68c01bSZhan Liu }
5553f68c01bSZhan Liu
dcn201_set_cursor_attribute(struct pipe_ctx * pipe_ctx)5563f68c01bSZhan Liu void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
5573f68c01bSZhan Liu {
5583f68c01bSZhan Liu struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
5593f68c01bSZhan Liu
5603f68c01bSZhan Liu gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq, &attributes->address);
5613f68c01bSZhan Liu
5623f68c01bSZhan Liu pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
5633f68c01bSZhan Liu pipe_ctx->plane_res.hubp, attributes);
5643f68c01bSZhan Liu pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes(
5653f68c01bSZhan Liu pipe_ctx->plane_res.dpp, attributes);
5663f68c01bSZhan Liu }
5673f68c01bSZhan Liu
dcn201_set_dmdata_attributes(struct pipe_ctx * pipe_ctx)5683f68c01bSZhan Liu void dcn201_set_dmdata_attributes(struct pipe_ctx *pipe_ctx)
5693f68c01bSZhan Liu {
5703f68c01bSZhan Liu struct dc_dmdata_attributes attr = { 0 };
5713f68c01bSZhan Liu struct hubp *hubp = pipe_ctx->plane_res.hubp;
5723f68c01bSZhan Liu
5733f68c01bSZhan Liu gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq,
5743f68c01bSZhan Liu &pipe_ctx->stream->dmdata_address);
5753f68c01bSZhan Liu
5763f68c01bSZhan Liu attr.dmdata_mode = DMDATA_HW_MODE;
5773f68c01bSZhan Liu attr.dmdata_size =
5783f68c01bSZhan Liu dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36;
5793f68c01bSZhan Liu attr.address.quad_part =
5803f68c01bSZhan Liu pipe_ctx->stream->dmdata_address.quad_part;
5813f68c01bSZhan Liu attr.dmdata_dl_delta = 0;
5823f68c01bSZhan Liu attr.dmdata_qos_mode = 0;
5833f68c01bSZhan Liu attr.dmdata_qos_level = 0;
5843f68c01bSZhan Liu attr.dmdata_repeat = 1; /* always repeat */
5853f68c01bSZhan Liu attr.dmdata_updated = 1;
5863f68c01bSZhan Liu attr.dmdata_sw_data = NULL;
5873f68c01bSZhan Liu
5883f68c01bSZhan Liu hubp->funcs->dmdata_set_attributes(hubp, &attr);
5893f68c01bSZhan Liu }
5903f68c01bSZhan Liu
dcn201_unblank_stream(struct pipe_ctx * pipe_ctx,struct dc_link_settings * link_settings)5913f68c01bSZhan Liu void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx,
5923f68c01bSZhan Liu struct dc_link_settings *link_settings)
5933f68c01bSZhan Liu {
5943f68c01bSZhan Liu struct encoder_unblank_param params = { { 0 } };
5953f68c01bSZhan Liu struct dc_stream_state *stream = pipe_ctx->stream;
5963f68c01bSZhan Liu struct dc_link *link = stream->link;
5973f68c01bSZhan Liu struct dce_hwseq *hws = link->dc->hwseq;
5983f68c01bSZhan Liu
5993f68c01bSZhan Liu /* only 3 items below are used by unblank */
6003f68c01bSZhan Liu params.timing = pipe_ctx->stream->timing;
6013f68c01bSZhan Liu
6023f68c01bSZhan Liu params.link_settings.link_rate = link_settings->link_rate;
6033f68c01bSZhan Liu
6043f68c01bSZhan Liu if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
6053f68c01bSZhan Liu /*check whether it is half the rate*/
606e6a901a0SWenjing Liu if (pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing))
6073f68c01bSZhan Liu params.timing.pix_clk_100hz /= 2;
6083f68c01bSZhan Liu
6093f68c01bSZhan Liu pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms);
6103f68c01bSZhan Liu }
6113f68c01bSZhan Liu
6123f68c01bSZhan Liu if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
6133f68c01bSZhan Liu hws->funcs.edp_backlight_control(link, true);
6143f68c01bSZhan Liu }
6153f68c01bSZhan Liu }
616