| File: | dev/pci/drm/amd/display/dc/dcn201/dcn201_hwseq.c |
| Warning: | line 545, column 2 Value stored to 'hubp' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* |
| 2 | * Copyright 2016 Advanced Micro Devices, Inc. |
| 3 | * |
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a |
| 5 | * copy of this software and associated documentation files (the "Software"), |
| 6 | * to deal in the Software without restriction, including without limitation |
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 8 | * and/or sell copies of the Software, and to permit persons to whom the |
| 9 | * Software is furnished to do so, subject to the following conditions: |
| 10 | * |
| 11 | * The above copyright notice and this permission notice shall be included in |
| 12 | * all copies or substantial portions of the Software. |
| 13 | * |
| 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| 18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| 19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| 20 | * OTHER DEALINGS IN THE SOFTWARE. |
| 21 | * |
| 22 | * Authors: AMD |
| 23 | * |
| 24 | */ |
| 25 | |
| 26 | #include "dm_services.h" |
| 27 | #include "basics/dc_common.h" |
| 28 | #include "core_types.h" |
| 29 | #include "resource.h" |
| 30 | #include "dcn201_hwseq.h" |
| 31 | #include "dcn201_optc.h" |
| 32 | #include "dce/dce_hwseq.h" |
| 33 | #include "hubp.h" |
| 34 | #include "dchubbub.h" |
| 35 | #include "timing_generator.h" |
| 36 | #include "opp.h" |
| 37 | #include "ipp.h" |
| 38 | #include "mpc.h" |
| 39 | #include "dccg.h" |
| 40 | #include "clk_mgr.h" |
| 41 | #include "reg_helper.h" |
| 42 | |
| 43 | #define CTXhws->ctx \ |
| 44 | hws->ctx |
| 45 | |
| 46 | #define REG(reg)hws->regs->reg\ |
| 47 | hws->regs->reg |
| 48 | |
| 49 | #define DC_LOGGERdc->ctx->logger \ |
| 50 | dc->ctx->logger |
| 51 | |
| 52 | #undef FN |
| 53 | #define FN(reg_name, field_name)hws->shifts->field_name, hws->masks->field_name \ |
| 54 | hws->shifts->field_name, hws->masks->field_name |
| 55 | |
| 56 | static bool_Bool patch_address_for_sbs_tb_stereo( |
| 57 | struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOCunion large_integer *addr) |
| 58 | { |
| 59 | struct dc_plane_state *plane_state = pipe_ctx->plane_state; |
| 60 | bool_Bool sec_split = pipe_ctx->top_pipe && |
| 61 | pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; |
| 62 | |
| 63 | if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO && |
| 64 | (pipe_ctx->stream->timing.timing_3d_format == |
| 65 | TIMING_3D_FORMAT_SIDE_BY_SIDE || |
| 66 | pipe_ctx->stream->timing.timing_3d_format == |
| 67 | TIMING_3D_FORMAT_TOP_AND_BOTTOM)) { |
| 68 | *addr = plane_state->address.grph_stereo.left_addr; |
| 69 | plane_state->address.grph_stereo.left_addr = |
| 70 | plane_state->address.grph_stereo.right_addr; |
| 71 | return true1; |
| 72 | } else { |
| 73 | if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE && |
| 74 | plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) { |
| 75 | plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO; |
| 76 | plane_state->address.grph_stereo.right_addr = |
| 77 | plane_state->address.grph_stereo.left_addr; |
| 78 | plane_state->address.grph_stereo.right_meta_addr = |
| 79 | plane_state->address.grph_stereo.left_meta_addr; |
| 80 | } |
| 81 | } |
| 82 | return false0; |
| 83 | } |
| 84 | |
| 85 | static bool_Bool gpu_addr_to_uma(struct dce_hwseq *hwseq, |
| 86 | PHYSICAL_ADDRESS_LOCunion large_integer *addr) |
| 87 | { |
| 88 | bool_Bool is_in_uma; |
| 89 | |
| 90 | if (hwseq->fb_base.quad_part <= addr->quad_part && |
| 91 | addr->quad_part < hwseq->fb_top.quad_part) { |
| 92 | addr->quad_part -= hwseq->fb_base.quad_part; |
| 93 | addr->quad_part += hwseq->fb_offset.quad_part; |
| 94 | is_in_uma = true1; |
| 95 | } else if (hwseq->fb_offset.quad_part <= addr->quad_part && |
| 96 | addr->quad_part <= hwseq->uma_top.quad_part) { |
| 97 | is_in_uma = true1; |
| 98 | } else { |
| 99 | is_in_uma = false0; |
| 100 | } |
| 101 | return is_in_uma; |
| 102 | } |
| 103 | |
| 104 | static void plane_address_in_gpu_space_to_uma(struct dce_hwseq *hwseq, |
| 105 | struct dc_plane_address *addr) |
| 106 | { |
| 107 | switch (addr->type) { |
| 108 | case PLN_ADDR_TYPE_GRAPHICS: |
| 109 | gpu_addr_to_uma(hwseq, &addr->grph.addr); |
| 110 | gpu_addr_to_uma(hwseq, &addr->grph.meta_addr); |
| 111 | break; |
| 112 | case PLN_ADDR_TYPE_GRPH_STEREO: |
| 113 | gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_addr); |
| 114 | gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_meta_addr); |
| 115 | gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_addr); |
| 116 | gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_meta_addr); |
| 117 | break; |
| 118 | case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE: |
| 119 | gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_addr); |
| 120 | gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_meta_addr); |
| 121 | gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_addr); |
| 122 | gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_meta_addr); |
| 123 | break; |
| 124 | default: |
| 125 | BREAK_TO_DEBUGGER()do { ___drm_dbg(((void *)0), DRM_UT_DRIVER, "%s():%d\n", __func__ , 125); do {} while (0); } while (0); |
| 126 | break; |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) |
| 131 | { |
| 132 | bool_Bool addr_patched = false0; |
| 133 | PHYSICAL_ADDRESS_LOCunion large_integer addr; |
| 134 | struct dc_plane_state *plane_state = pipe_ctx->plane_state; |
| 135 | struct dce_hwseq *hws = dc->hwseq; |
| 136 | struct dc_plane_address uma; |
| 137 | |
| 138 | if (plane_state == NULL((void *)0)) |
| 139 | return; |
| 140 | |
| 141 | uma = plane_state->address; |
| 142 | addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); |
| 143 | |
| 144 | plane_address_in_gpu_space_to_uma(hws, &uma); |
| 145 | |
| 146 | pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr( |
| 147 | pipe_ctx->plane_res.hubp, |
| 148 | &uma, |
| 149 | plane_state->flip_immediate); |
| 150 | |
| 151 | plane_state->status.requested_address = plane_state->address; |
| 152 | |
| 153 | if (plane_state->flip_immediate) |
| 154 | plane_state->status.current_address = plane_state->address; |
| 155 | |
| 156 | if (addr_patched) |
| 157 | pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; |
| 158 | } |
| 159 | |
| 160 | /* Blank pixel data during initialization */ |
| 161 | void dcn201_init_blank( |
| 162 | struct dc *dc, |
| 163 | struct timing_generator *tg) |
| 164 | { |
| 165 | struct dce_hwseq *hws = dc->hwseq; |
| 166 | enum dc_color_space color_space; |
| 167 | struct tg_color black_color = {0}; |
| 168 | struct output_pixel_processor *opp = NULL((void *)0); |
| 169 | uint32_t num_opps, opp_id_src0, opp_id_src1; |
| 170 | uint32_t otg_active_width, otg_active_height; |
| 171 | |
| 172 | /* program opp dpg blank color */ |
| 173 | color_space = COLOR_SPACE_SRGB; |
| 174 | color_space_to_black_color(dc, color_space, &black_color); |
| 175 | |
| 176 | /* get the OTG active size */ |
| 177 | tg->funcs->get_otg_active_size(tg, |
| 178 | &otg_active_width, |
| 179 | &otg_active_height); |
| 180 | |
| 181 | /* get the OPTC source */ |
| 182 | tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); |
| 183 | ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp)do { if (({ static int __warned; int __ret = !!(!(opp_id_src0 < dc->res_pool->res_cap->num_opp)); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n", "!(opp_id_src0 < dc->res_pool->res_cap->num_opp)" , "/usr/src/sys/dev/pci/drm/amd/display/dc/dcn201/dcn201_hwseq.c" , 183); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
| 184 | opp = dc->res_pool->opps[opp_id_src0]; |
| 185 | |
| 186 | opp->funcs->opp_set_disp_pattern_generator( |
| 187 | opp, |
| 188 | CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, |
| 189 | CONTROLLER_DP_COLOR_SPACE_UDEFINED, |
| 190 | COLOR_DEPTH_UNDEFINED, |
| 191 | &black_color, |
| 192 | otg_active_width, |
| 193 | otg_active_height, |
| 194 | 0); |
| 195 | |
| 196 | hws->funcs.wait_for_blank_complete(opp); |
| 197 | } |
| 198 | |
| 199 | static void read_mmhub_vm_setup(struct dce_hwseq *hws) |
| 200 | { |
| 201 | uint32_t fb_base = REG_READ(MC_VM_FB_LOCATION_BASE)dm_read_reg_func(hws->ctx, hws->regs->MC_VM_FB_LOCATION_BASE , __func__); |
| 202 | uint32_t fb_top = REG_READ(MC_VM_FB_LOCATION_TOP)dm_read_reg_func(hws->ctx, hws->regs->MC_VM_FB_LOCATION_TOP , __func__); |
| 203 | uint32_t fb_offset = REG_READ(MC_VM_FB_OFFSET)dm_read_reg_func(hws->ctx, hws->regs->MC_VM_FB_OFFSET , __func__); |
| 204 | |
| 205 | /* MC_VM_FB_LOCATION_TOP is in pages, actual top should add 1 */ |
| 206 | fb_top++; |
| 207 | |
| 208 | /* bit 23:0 in register map to bit 47:24 in address */ |
| 209 | hws->fb_base.low_part = fb_base; |
| 210 | hws->fb_base.quad_part <<= 24; |
| 211 | |
| 212 | hws->fb_top.low_part = fb_top; |
| 213 | hws->fb_top.quad_part <<= 24; |
| 214 | hws->fb_offset.low_part = fb_offset; |
| 215 | hws->fb_offset.quad_part <<= 24; |
| 216 | |
| 217 | hws->uma_top.quad_part = hws->fb_top.quad_part |
| 218 | - hws->fb_base.quad_part + hws->fb_offset.quad_part; |
| 219 | } |
| 220 | |
| 221 | void dcn201_init_hw(struct dc *dc) |
| 222 | { |
| 223 | int i, j; |
| 224 | struct dce_hwseq *hws = dc->hwseq; |
| 225 | struct resource_pool *res_pool = dc->res_pool; |
| 226 | struct dc_state *context = dc->current_state; |
| 227 | |
| 228 | if (res_pool->dccg->funcs->dccg_init) |
| 229 | res_pool->dccg->funcs->dccg_init(res_pool->dccg); |
| 230 | |
| 231 | if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) |
| 232 | dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); |
| 233 | |
| 234 | if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)(dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS)) { |
| 235 | REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF)dm_write_reg_func(hws->ctx, hws->regs->RBBMIF_TIMEOUT_DIS , 0xFFFFFFFF, __func__); |
| 236 | REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF)dm_write_reg_func(hws->ctx, hws->regs->RBBMIF_TIMEOUT_DIS_2 , 0xFFFFFFFF, __func__); |
| 237 | |
| 238 | hws->funcs.dccg_init(hws); |
| 239 | |
| 240 | REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2)generic_reg_update_ex(hws->ctx, hws->regs->DCHUBBUB_GLOBAL_TIMER_CNTL , 1, hws->shifts->DCHUBBUB_GLOBAL_TIMER_REFDIV, hws-> masks->DCHUBBUB_GLOBAL_TIMER_REFDIV, 2); |
| 241 | REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1)generic_reg_update_ex(hws->ctx, hws->regs->DCHUBBUB_GLOBAL_TIMER_CNTL , 1, hws->shifts->DCHUBBUB_GLOBAL_TIMER_ENABLE, hws-> masks->DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); |
| 242 | REG_WRITE(REFCLK_CNTL, 0)dm_write_reg_func(hws->ctx, hws->regs->REFCLK_CNTL, 0 , __func__); |
| 243 | } else { |
| 244 | hws->funcs.bios_golden_init(dc); |
| 245 | |
| 246 | if (dc->ctx->dc_bios->fw_info_valid) { |
| 247 | res_pool->ref_clocks.xtalin_clock_inKhz = |
| 248 | dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; |
| 249 | |
| 250 | if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)(dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS)) { |
| 251 | if (res_pool->dccg && res_pool->hubbub) { |
| 252 | (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, |
| 253 | dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency, |
| 254 | &res_pool->ref_clocks.dccg_ref_clock_inKhz); |
| 255 | |
| 256 | (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, |
| 257 | res_pool->ref_clocks.dccg_ref_clock_inKhz, |
| 258 | &res_pool->ref_clocks.dchub_ref_clock_inKhz); |
| 259 | } else { |
| 260 | res_pool->ref_clocks.dccg_ref_clock_inKhz = |
| 261 | res_pool->ref_clocks.xtalin_clock_inKhz; |
| 262 | res_pool->ref_clocks.dchub_ref_clock_inKhz = |
| 263 | res_pool->ref_clocks.xtalin_clock_inKhz; |
| 264 | } |
| 265 | } |
| 266 | } else |
| 267 | ASSERT_CRITICAL(false)do { if (({ int __ret = !!(!(0)); if (__ret) printf("WARNING %s failed at %s:%d\n" , "!(0)", "/usr/src/sys/dev/pci/drm/amd/display/dc/dcn201/dcn201_hwseq.c" , 267); __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
| 268 | for (i = 0; i < dc->link_count; i++) { |
| 269 | /* Power up AND update implementation according to the |
| 270 | * required signal (which may be different from the |
| 271 | * default signal on connector). |
| 272 | */ |
| 273 | struct dc_link *link = dc->links[i]; |
| 274 | |
| 275 | link->link_enc->funcs->hw_init(link->link_enc); |
| 276 | } |
| 277 | if (hws->fb_offset.quad_part == 0) |
| 278 | read_mmhub_vm_setup(hws); |
| 279 | } |
| 280 | |
| 281 | /* Blank pixel data with OPP DPG */ |
| 282 | for (i = 0; i < res_pool->timing_generator_count; i++) { |
| 283 | struct timing_generator *tg = res_pool->timing_generators[i]; |
| 284 | |
| 285 | if (tg->funcs->is_tg_enabled(tg)) { |
| 286 | dcn201_init_blank(dc, tg); |
| 287 | } |
| 288 | } |
| 289 | |
| 290 | for (i = 0; i < res_pool->timing_generator_count; i++) { |
| 291 | struct timing_generator *tg = res_pool->timing_generators[i]; |
| 292 | |
| 293 | if (tg->funcs->is_tg_enabled(tg)) |
| 294 | tg->funcs->lock(tg); |
| 295 | } |
| 296 | |
| 297 | for (i = 0; i < res_pool->pipe_count; i++) { |
| 298 | struct dpp *dpp = res_pool->dpps[i]; |
| 299 | |
| 300 | dpp->funcs->dpp_reset(dpp); |
| 301 | } |
| 302 | |
| 303 | /* Reset all MPCC muxes */ |
| 304 | res_pool->mpc->funcs->mpc_init(res_pool->mpc); |
| 305 | |
| 306 | /* initialize OPP mpc_tree parameter */ |
| 307 | for (i = 0; i < res_pool->res_cap->num_opp; i++) { |
| 308 | res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst; |
| 309 | res_pool->opps[i]->mpc_tree_params.opp_list = NULL((void *)0); |
| 310 | for (j = 0; j < MAX_PIPES6; j++) |
| 311 | res_pool->opps[i]->mpcc_disconnect_pending[j] = false0; |
| 312 | } |
| 313 | |
| 314 | for (i = 0; i < res_pool->timing_generator_count; i++) { |
| 315 | struct timing_generator *tg = res_pool->timing_generators[i]; |
| 316 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
| 317 | struct hubp *hubp = res_pool->hubps[i]; |
| 318 | struct dpp *dpp = res_pool->dpps[i]; |
| 319 | |
| 320 | pipe_ctx->stream_res.tg = tg; |
| 321 | pipe_ctx->pipe_idx = i; |
| 322 | |
| 323 | pipe_ctx->plane_res.hubp = hubp; |
| 324 | pipe_ctx->plane_res.dpp = dpp; |
| 325 | pipe_ctx->plane_res.mpcc_inst = dpp->inst; |
| 326 | hubp->mpcc_id = dpp->inst; |
| 327 | hubp->opp_id = OPP_ID_INVALID0xf; |
| 328 | hubp->power_gated = false0; |
| 329 | pipe_ctx->stream_res.opp = NULL((void *)0); |
| 330 | |
| 331 | hubp->funcs->hubp_init(hubp); |
| 332 | |
| 333 | res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true1; |
| 334 | pipe_ctx->stream_res.opp = res_pool->opps[i]; |
| 335 | /*To do: number of MPCC != number of opp*/ |
| 336 | hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); |
| 337 | } |
| 338 | |
| 339 | /* initialize DWB pointer to MCIF_WB */ |
| 340 | for (i = 0; i < res_pool->res_cap->num_dwb; i++) |
| 341 | res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i]; |
| 342 | |
| 343 | for (i = 0; i < res_pool->timing_generator_count; i++) { |
| 344 | struct timing_generator *tg = res_pool->timing_generators[i]; |
| 345 | |
| 346 | if (tg->funcs->is_tg_enabled(tg)) |
| 347 | tg->funcs->unlock(tg); |
| 348 | } |
| 349 | |
| 350 | for (i = 0; i < res_pool->pipe_count; i++) { |
| 351 | struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; |
| 352 | |
| 353 | dc->hwss.disable_plane(dc, pipe_ctx); |
| 354 | |
| 355 | pipe_ctx->stream_res.tg = NULL((void *)0); |
| 356 | pipe_ctx->plane_res.hubp = NULL((void *)0); |
| 357 | } |
| 358 | |
| 359 | for (i = 0; i < res_pool->timing_generator_count; i++) { |
| 360 | struct timing_generator *tg = res_pool->timing_generators[i]; |
| 361 | |
| 362 | tg->funcs->tg_init(tg); |
| 363 | } |
| 364 | |
| 365 | /* end of FPGA. Below if real ASIC */ |
| 366 | if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)(dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS)) |
| 367 | return; |
| 368 | |
| 369 | for (i = 0; i < res_pool->audio_count; i++) { |
| 370 | struct audio *audio = res_pool->audios[i]; |
| 371 | |
| 372 | audio->funcs->hw_init(audio); |
| 373 | } |
| 374 | |
| 375 | /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ |
| 376 | REG_WRITE(DIO_MEM_PWR_CTRL, 0)dm_write_reg_func(hws->ctx, hws->regs->DIO_MEM_PWR_CTRL , 0, __func__); |
| 377 | |
| 378 | if (!dc->debug.disable_clock_gate) { |
| 379 | /* enable all DCN clock gating */ |
| 380 | REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0)dm_write_reg_func(hws->ctx, hws->regs->DCCG_GATE_DISABLE_CNTL , 0, __func__); |
| 381 | |
| 382 | REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0)dm_write_reg_func(hws->ctx, hws->regs->DCCG_GATE_DISABLE_CNTL2 , 0, __func__); |
| 383 | |
| 384 | REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0)generic_reg_update_ex(hws->ctx, hws->regs->DCFCLK_CNTL , 1, hws->shifts->DCFCLK_GATE_DIS, hws->masks->DCFCLK_GATE_DIS , 0); |
| 385 | } |
| 386 | } |
| 387 | |
| 388 | /* trigger HW to start disconnect plane from stream on the next vsync */ |
| 389 | void dcn201_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) |
| 390 | { |
| 391 | struct dce_hwseq *hws = dc->hwseq; |
| 392 | struct hubp *hubp = pipe_ctx->plane_res.hubp; |
| 393 | int dpp_id = pipe_ctx->plane_res.dpp->inst; |
| 394 | struct mpc *mpc = dc->res_pool->mpc; |
| 395 | struct mpc_tree *mpc_tree_params; |
| 396 | struct mpcc *mpcc_to_remove = NULL((void *)0); |
| 397 | struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; |
| 398 | bool_Bool mpcc_removed = false0; |
| 399 | |
| 400 | mpc_tree_params = &(opp->mpc_tree_params); |
| 401 | |
| 402 | /* check if this plane is being used by an MPCC in the secondary blending chain */ |
| 403 | if (mpc->funcs->get_mpcc_for_dpp_from_secondary) |
| 404 | mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id); |
| 405 | |
| 406 | /* remove MPCC from secondary if being used */ |
| 407 | if (mpcc_to_remove != NULL((void *)0) && mpc->funcs->remove_mpcc_from_secondary) { |
| 408 | mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, mpcc_to_remove); |
| 409 | mpcc_removed = true1; |
| 410 | } |
| 411 | |
| 412 | /* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */ |
| 413 | mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); |
| 414 | if (mpcc_to_remove != NULL((void *)0)) { |
| 415 | mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); |
| 416 | mpcc_removed = true1; |
| 417 | } |
| 418 | |
| 419 | /*Already reset*/ |
| 420 | if (mpcc_removed == false0) |
| 421 | return; |
| 422 | |
| 423 | if (opp != NULL((void *)0)) |
| 424 | opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true1; |
| 425 | |
| 426 | dc->optimized_required = true1; |
| 427 | |
| 428 | if (hubp->funcs->hubp_disconnect) |
| 429 | hubp->funcs->hubp_disconnect(hubp); |
| 430 | |
| 431 | if (dc->debug.sanity_checks) |
| 432 | hws->funcs.verify_allow_pstate_change_high(dc); |
| 433 | } |
| 434 | |
| 435 | void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) |
| 436 | { |
| 437 | struct hubp *hubp = pipe_ctx->plane_res.hubp; |
| 438 | struct mpcc_blnd_cfg blnd_cfg; |
| 439 | bool_Bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; |
| 440 | int mpcc_id, dpp_id; |
| 441 | struct mpcc *new_mpcc; |
| 442 | struct mpcc *remove_mpcc = NULL((void *)0); |
| 443 | struct mpc *mpc = dc->res_pool->mpc; |
| 444 | struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); |
| 445 | |
| 446 | if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) { |
| 447 | get_hdr_visual_confirm_color( |
| 448 | pipe_ctx, &blnd_cfg.black_color); |
| 449 | } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) { |
| 450 | get_surface_visual_confirm_color( |
| 451 | pipe_ctx, &blnd_cfg.black_color); |
| 452 | } else { |
| 453 | color_space_to_black_color( |
| 454 | dc, pipe_ctx->stream->output_color_space, |
| 455 | &blnd_cfg.black_color); |
| 456 | } |
| 457 | |
| 458 | if (per_pixel_alpha) |
| 459 | blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; |
| 460 | else |
| 461 | blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; |
| 462 | |
| 463 | blnd_cfg.overlap_only = false0; |
| 464 | |
| 465 | if (pipe_ctx->plane_state->global_alpha_value) |
| 466 | blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value; |
| 467 | else |
| 468 | blnd_cfg.global_alpha = 0xff; |
| 469 | |
| 470 | blnd_cfg.global_gain = 0xff; |
| 471 | blnd_cfg.background_color_bpc = 4; |
| 472 | blnd_cfg.bottom_gain_mode = 0; |
| 473 | blnd_cfg.top_gain = 0x1f000; |
| 474 | blnd_cfg.bottom_inside_gain = 0x1f000; |
| 475 | blnd_cfg.bottom_outside_gain = 0x1f000; |
| 476 | /*the input to MPCC is RGB*/ |
| 477 | blnd_cfg.black_color.color_b_cb = 0; |
| 478 | blnd_cfg.black_color.color_g_y = 0; |
| 479 | blnd_cfg.black_color.color_r_cr = 0; |
| 480 | |
| 481 | /* DCN1.0 has output CM before MPC which seems to screw with |
| 482 | * pre-multiplied alpha. This is a w/a hopefully unnecessary for DCN2. |
| 483 | */ |
| 484 | blnd_cfg.pre_multiplied_alpha = per_pixel_alpha; |
| 485 | |
| 486 | /* |
| 487 | * TODO: remove hack |
| 488 | * Note: currently there is a bug in init_hw such that |
| 489 | * on resume from hibernate, BIOS sets up MPCC0, and |
| 490 | * we do mpcc_remove but the mpcc cannot go to idle |
| 491 | * after remove. This cause us to pick mpcc1 here, |
| 492 | * which causes a pstate hang for yet unknown reason. |
| 493 | */ |
| 494 | dpp_id = hubp->inst; |
| 495 | mpcc_id = dpp_id; |
| 496 | |
| 497 | /* If there is no full update, don't need to touch MPC tree*/ |
| 498 | if (!pipe_ctx->plane_state->update_flags.bits.full_update) { |
| 499 | dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id); |
| 500 | mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); |
| 501 | return; |
| 502 | } |
| 503 | |
| 504 | /* check if this plane is being used by an MPCC in the secondary blending chain */ |
| 505 | if (mpc->funcs->get_mpcc_for_dpp_from_secondary) |
| 506 | remove_mpcc = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id); |
| 507 | |
| 508 | /* remove MPCC from secondary if being used */ |
| 509 | if (remove_mpcc != NULL((void *)0) && mpc->funcs->remove_mpcc_from_secondary) |
| 510 | mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, remove_mpcc); |
| 511 | |
| 512 | /* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */ |
| 513 | remove_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id); |
| 514 | /* remove MPCC if being used */ |
| 515 | |
| 516 | if (remove_mpcc != NULL((void *)0)) |
| 517 | mpc->funcs->remove_mpcc(mpc, mpc_tree_params, remove_mpcc); |
| 518 | else |
| 519 | if (dc->debug.sanity_checks) |
| 520 | mpc->funcs->assert_mpcc_idle_before_connect( |
| 521 | dc->res_pool->mpc, mpcc_id); |
| 522 | |
| 523 | /* Call MPC to insert new plane */ |
| 524 | dc->hwss.update_visual_confirm_color(dc, pipe_ctx, &blnd_cfg.black_color, mpcc_id); |
| 525 | new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc, |
| 526 | mpc_tree_params, |
| 527 | &blnd_cfg, |
| 528 | NULL((void *)0), |
| 529 | NULL((void *)0), |
| 530 | dpp_id, |
| 531 | mpcc_id); |
| 532 | |
| 533 | ASSERT(new_mpcc != NULL)do { if (({ static int __warned; int __ret = !!(!(new_mpcc != ((void *)0))); if (__ret && !__warned) { printf("WARNING %s failed at %s:%d\n" , "!(new_mpcc != ((void *)0))", "/usr/src/sys/dev/pci/drm/amd/display/dc/dcn201/dcn201_hwseq.c" , 533); __warned = 1; } __builtin_expect(!!(__ret), 0); })) do {} while (0); } while (0); |
| 534 | hubp->opp_id = pipe_ctx->stream_res.opp->inst; |
| 535 | hubp->mpcc_id = mpcc_id; |
| 536 | } |
| 537 | |
| 538 | void dcn201_pipe_control_lock( |
| 539 | struct dc *dc, |
| 540 | struct pipe_ctx *pipe, |
| 541 | bool_Bool lock) |
| 542 | { |
| 543 | struct dce_hwseq *hws = dc->hwseq; |
| 544 | struct hubp *hubp = NULL((void *)0); |
| 545 | hubp = dc->res_pool->hubps[pipe->pipe_idx]; |
Value stored to 'hubp' is never read | |
| 546 | /* use TG master update lock to lock everything on the TG |
| 547 | * therefore only top pipe need to lock |
| 548 | */ |
| 549 | if (pipe->top_pipe) |
| 550 | return; |
| 551 | |
| 552 | if (dc->debug.sanity_checks) |
| 553 | hws->funcs.verify_allow_pstate_change_high(dc); |
| 554 | |
| 555 | if (pipe->plane_state != NULL((void *)0) && pipe->plane_state->triplebuffer_flips) { |
| 556 | if (lock) |
| 557 | pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg); |
| 558 | else |
| 559 | pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg); |
| 560 | } else { |
| 561 | if (lock) |
| 562 | pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); |
| 563 | else |
| 564 | pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); |
| 565 | } |
| 566 | |
| 567 | if (dc->debug.sanity_checks) |
| 568 | hws->funcs.verify_allow_pstate_change_high(dc); |
| 569 | } |
| 570 | |
| 571 | void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx) |
| 572 | { |
| 573 | struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes; |
| 574 | |
| 575 | gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq, &attributes->address); |
| 576 | |
| 577 | pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( |
| 578 | pipe_ctx->plane_res.hubp, attributes); |
| 579 | pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( |
| 580 | pipe_ctx->plane_res.dpp, attributes); |
| 581 | } |
| 582 | |
| 583 | void dcn201_set_dmdata_attributes(struct pipe_ctx *pipe_ctx) |
| 584 | { |
| 585 | struct dc_dmdata_attributes attr = { 0 }; |
| 586 | struct hubp *hubp = pipe_ctx->plane_res.hubp; |
| 587 | |
| 588 | gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq, |
| 589 | &pipe_ctx->stream->dmdata_address); |
| 590 | |
| 591 | attr.dmdata_mode = DMDATA_HW_MODE; |
| 592 | attr.dmdata_size = |
| 593 | dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36; |
| 594 | attr.address.quad_part = |
| 595 | pipe_ctx->stream->dmdata_address.quad_part; |
| 596 | attr.dmdata_dl_delta = 0; |
| 597 | attr.dmdata_qos_mode = 0; |
| 598 | attr.dmdata_qos_level = 0; |
| 599 | attr.dmdata_repeat = 1; /* always repeat */ |
| 600 | attr.dmdata_updated = 1; |
| 601 | attr.dmdata_sw_data = NULL((void *)0); |
| 602 | |
| 603 | hubp->funcs->dmdata_set_attributes(hubp, &attr); |
| 604 | } |
| 605 | |
| 606 | void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx, |
| 607 | struct dc_link_settings *link_settings) |
| 608 | { |
| 609 | struct encoder_unblank_param params = { { 0 } }; |
| 610 | struct dc_stream_state *stream = pipe_ctx->stream; |
| 611 | struct dc_link *link = stream->link; |
| 612 | struct dce_hwseq *hws = link->dc->hwseq; |
| 613 | |
| 614 | /* only 3 items below are used by unblank */ |
| 615 | params.timing = pipe_ctx->stream->timing; |
| 616 | |
| 617 | params.link_settings.link_rate = link_settings->link_rate; |
| 618 | |
| 619 | if (dc_is_dp_signal(pipe_ctx->stream->signal)) { |
| 620 | /*check whether it is half the rate*/ |
| 621 | if (optc201_is_two_pixels_per_containter(&stream->timing)) |
| 622 | params.timing.pix_clk_100hz /= 2; |
| 623 | |
| 624 | pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms); |
| 625 | } |
| 626 | |
| 627 | if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { |
| 628 | hws->funcs.edp_backlight_control(link, true1); |
| 629 | } |
| 630 | } |