File Index
Files and directories
Sign in
FILE

dcn201_hwseq.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c C
  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/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 CTX \
 44	hws->ctx
 45
 46#define REG(reg)\
 47	hws->regs->reg
 48
 49#define DC_LOGGER \
 50	dc->ctx->logger
 51
 52#undef FN
 53#define FN(reg_name, field_name) \
 54	hws->shifts->field_name, hws->masks->field_name
 55
 56static bool patch_address_for_sbs_tb_stereo(
 57		struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr)
 58{
 59	struct dc_plane_state *plane_state = pipe_ctx->plane_state;
 60	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 true;
 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 false;
 83}
 84
 85static bool gpu_addr_to_uma(struct dce_hwseq *hwseq,
 86		PHYSICAL_ADDRESS_LOC *addr)
 87{
 88	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 = true;
 95	} else if (hwseq->fb_offset.quad_part <= addr->quad_part &&
 96			addr->quad_part <= hwseq->uma_top.quad_part) {
 97		is_in_uma = true;
 98	} else if (addr->quad_part == 0) {
 99		is_in_uma = false;
100	} else {
101		is_in_uma = false;
102		BREAK_TO_DEBUGGER();
103	}
104	return is_in_uma;
105}
106
107static void plane_address_in_gpu_space_to_uma(struct dce_hwseq *hwseq,
108		struct dc_plane_address *addr)
109{
110	switch (addr->type) {
111	case PLN_ADDR_TYPE_GRAPHICS:
112		gpu_addr_to_uma(hwseq, &addr->grph.addr);
113		gpu_addr_to_uma(hwseq, &addr->grph.meta_addr);
114		break;
115	case PLN_ADDR_TYPE_GRPH_STEREO:
116		gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_addr);
117		gpu_addr_to_uma(hwseq, &addr->grph_stereo.left_meta_addr);
118		gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_addr);
119		gpu_addr_to_uma(hwseq, &addr->grph_stereo.right_meta_addr);
120		break;
121	case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE:
122		gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_addr);
123		gpu_addr_to_uma(hwseq, &addr->video_progressive.luma_meta_addr);
124		gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_addr);
125		gpu_addr_to_uma(hwseq, &addr->video_progressive.chroma_meta_addr);
126		break;
127	default:
128		BREAK_TO_DEBUGGER();
129		break;
130	}
131}
132
133void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
134{
135	bool addr_patched = false;
136	PHYSICAL_ADDRESS_LOC addr;
137	struct dc_plane_state *plane_state = pipe_ctx->plane_state;
138	struct dce_hwseq *hws = dc->hwseq;
139	struct dc_plane_address uma;
140
141	if (plane_state == NULL)
142		return;
143
144	uma = plane_state->address;
145	addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr);
146
147	plane_address_in_gpu_space_to_uma(hws, &uma);
148
149	pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr(
150			pipe_ctx->plane_res.hubp,
151			&uma,
152			plane_state->flip_immediate);
153
154	plane_state->status.requested_address = plane_state->address;
155
156	if (plane_state->flip_immediate)
157		plane_state->status.current_address = plane_state->address;
158
159	if (addr_patched)
160		pipe_ctx->plane_state->address.grph_stereo.left_addr = addr;
161}
162
163/* Blank pixel data during initialization */
164void dcn201_init_blank(
165		struct dc *dc,
166		struct timing_generator *tg)
167{
168	struct dce_hwseq *hws = dc->hwseq;
169	enum dc_color_space color_space;
170	struct tg_color black_color = {0};
171	struct output_pixel_processor *opp = NULL;
172	uint32_t num_opps, opp_id_src0, opp_id_src1;
173	uint32_t otg_active_width = 0, otg_active_height = 0;
174
175	/* program opp dpg blank color */
176	color_space = COLOR_SPACE_SRGB;
177	color_space_to_black_color(dc, color_space, &black_color);
178
179	/* get the OTG active size */
180	tg->funcs->get_otg_active_size(tg,
181			&otg_active_width,
182			&otg_active_height);
183
184	/* get the OPTC source */
185	tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);
186	ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp);
187	opp = dc->res_pool->opps[opp_id_src0];
188
189	opp->funcs->opp_set_disp_pattern_generator(
190			opp,
191			CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR,
192			CONTROLLER_DP_COLOR_SPACE_UDEFINED,
193			COLOR_DEPTH_UNDEFINED,
194			&black_color,
195			otg_active_width,
196			otg_active_height,
197			0);
198
199	hws->funcs.wait_for_blank_complete(opp);
200}
201
202static void read_mmhub_vm_setup(struct dce_hwseq *hws)
203{
204	uint32_t fb_base = REG_READ(MC_VM_FB_LOCATION_BASE);
205	uint32_t fb_top = REG_READ(MC_VM_FB_LOCATION_TOP);
206	uint32_t fb_offset = REG_READ(MC_VM_FB_OFFSET);
207
208	/* MC_VM_FB_LOCATION_TOP is in pages, actual top should add 1 */
209	fb_top++;
210
211	/* bit 23:0 in register map to bit 47:24 in address */
212	hws->fb_base.low_part = fb_base;
213	hws->fb_base.quad_part <<= 24;
214
215	hws->fb_top.low_part  = fb_top;
216	hws->fb_top.quad_part <<= 24;
217	hws->fb_offset.low_part = fb_offset;
218	hws->fb_offset.quad_part <<= 24;
219
220	hws->uma_top.quad_part = hws->fb_top.quad_part
221			- hws->fb_base.quad_part + hws->fb_offset.quad_part;
222}
223
224void dcn201_init_hw(struct dc *dc)
225{
226	int i, j;
227	struct dce_hwseq *hws = dc->hwseq;
228	struct resource_pool *res_pool = dc->res_pool;
229	struct dc_state  *context = dc->current_state;
230
231	if (res_pool->dccg->funcs->dccg_init)
232		res_pool->dccg->funcs->dccg_init(res_pool->dccg);
233
234	if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
235		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
236
237	hws->funcs.bios_golden_init(dc);
238
239	if (dc->ctx->dc_bios->fw_info_valid) {
240		res_pool->ref_clocks.xtalin_clock_inKhz =
241			dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
242
243		if (res_pool->hubbub) {
244			(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
245					dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
246					&res_pool->ref_clocks.dccg_ref_clock_inKhz);
247
248			(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
249					res_pool->ref_clocks.dccg_ref_clock_inKhz,
250					&res_pool->ref_clocks.dchub_ref_clock_inKhz);
251		} else {
252			res_pool->ref_clocks.dccg_ref_clock_inKhz =
253					res_pool->ref_clocks.xtalin_clock_inKhz;
254			res_pool->ref_clocks.dchub_ref_clock_inKhz =
255					res_pool->ref_clocks.xtalin_clock_inKhz;
256		}
257	} else
258		ASSERT_CRITICAL(false);
259	for (i = 0; i < dc->link_count; i++) {
260		/* Power up AND update implementation according to the
261		 * required signal (which may be different from the
262		 * default signal on connector).
263		 */
264		struct dc_link *link = dc->links[i];
265
266		link->link_enc->funcs->hw_init(link->link_enc);
267	}
268	if (hws->fb_offset.quad_part == 0)
269		read_mmhub_vm_setup(hws);
270
271	/* Blank pixel data with OPP DPG */
272	for (i = 0; i < res_pool->timing_generator_count; i++) {
273		struct timing_generator *tg = res_pool->timing_generators[i];
274
275		if (tg->funcs->is_tg_enabled(tg)) {
276			dcn201_init_blank(dc, tg);
277		}
278	}
279
280	for (i = 0; i < res_pool->timing_generator_count; i++) {
281		struct timing_generator *tg = res_pool->timing_generators[i];
282
283		if (tg->funcs->is_tg_enabled(tg))
284			tg->funcs->lock(tg);
285	}
286
287	for (i = 0; i < res_pool->pipe_count; i++) {
288		struct dpp *dpp = res_pool->dpps[i];
289
290		dpp->funcs->dpp_reset(dpp);
291	}
292
293	/* Reset all MPCC muxes */
294	res_pool->mpc->funcs->mpc_init(res_pool->mpc);
295
296	/* initialize OPP mpc_tree parameter */
297	for (i = 0; i < res_pool->res_cap->num_opp; i++) {
298		res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;
299		res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
300		for (j = 0; j < MAX_PIPES; j++)
301			res_pool->opps[i]->mpcc_disconnect_pending[j] = false;
302	}
303
304	for (i = 0; i < res_pool->timing_generator_count; i++) {
305		struct timing_generator *tg = res_pool->timing_generators[i];
306		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
307		struct hubp *hubp = res_pool->hubps[i];
308		struct dpp *dpp = res_pool->dpps[i];
309
310		pipe_ctx->stream_res.tg = tg;
311		pipe_ctx->pipe_idx = i;
312
313		pipe_ctx->plane_res.hubp = hubp;
314		pipe_ctx->plane_res.dpp = dpp;
315		pipe_ctx->plane_res.mpcc_inst = dpp->inst;
316		hubp->mpcc_id = dpp->inst;
317		hubp->opp_id = OPP_ID_INVALID;
318		hubp->power_gated = false;
319		pipe_ctx->stream_res.opp = NULL;
320
321		hubp->funcs->hubp_init(hubp);
322
323		res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
324		pipe_ctx->stream_res.opp = res_pool->opps[i];
325		/*To do: number of MPCC != number of opp*/
326		hws->funcs.plane_atomic_disconnect(dc, context, pipe_ctx);
327	}
328
329	/* initialize DWB pointer to MCIF_WB */
330	for (i = 0; i < res_pool->res_cap->num_dwb; i++)
331		res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i];
332
333	for (i = 0; i < res_pool->timing_generator_count; i++) {
334		struct timing_generator *tg = res_pool->timing_generators[i];
335
336		if (tg->funcs->is_tg_enabled(tg))
337			tg->funcs->unlock(tg);
338	}
339
340	for (i = 0; i < res_pool->pipe_count; i++) {
341		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
342
343		dc->hwss.disable_plane(dc, context, pipe_ctx);
344
345		pipe_ctx->stream_res.tg = NULL;
346		pipe_ctx->plane_res.hubp = NULL;
347	}
348
349	for (i = 0; i < res_pool->timing_generator_count; i++) {
350		struct timing_generator *tg = res_pool->timing_generators[i];
351
352		tg->funcs->tg_init(tg);
353	}
354
355	for (i = 0; i < res_pool->audio_count; i++) {
356		struct audio *audio = res_pool->audios[i];
357
358		audio->funcs->hw_init(audio);
359	}
360
361	/* power AFMT HDMI memory TODO: may move to dis/en output save power*/
362	REG_WRITE(DIO_MEM_PWR_CTRL, 0);
363
364	if (!dc->debug.disable_clock_gate) {
365		/* enable all DCN clock gating */
366		REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
367
368		REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
369
370		REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
371	}
372}
373
374/* trigger HW to start disconnect plane from stream on the next vsync */
375void dcn201_plane_atomic_disconnect(struct dc *dc,
376		struct dc_state *state,
377		struct pipe_ctx *pipe_ctx)
378{
379	struct dce_hwseq *hws = dc->hwseq;
380	struct hubp *hubp = pipe_ctx->plane_res.hubp;
381	int dpp_id = pipe_ctx->plane_res.dpp->inst;
382	struct mpc *mpc = dc->res_pool->mpc;
383	struct mpc_tree *mpc_tree_params;
384	struct mpcc *mpcc_to_remove = NULL;
385	struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
386	bool mpcc_removed = false;
387
388	mpc_tree_params = &(opp->mpc_tree_params);
389
390	/* check if this plane is being used by an MPCC in the secondary blending chain */
391	if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
392		mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
393
394	/* remove MPCC from secondary if being used */
395	if (mpcc_to_remove != NULL && mpc->funcs->remove_mpcc_from_secondary) {
396		mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, mpcc_to_remove);
397		mpcc_removed = true;
398	}
399
400	/* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
401	mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
402	if (mpcc_to_remove != NULL) {
403		mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove);
404		mpcc_removed = true;
405	}
406
407	/*Already reset*/
408	if (mpcc_removed == false)
409		return;
410
411	opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
412
413	dc->optimized_required = true;
414
415	if (hubp->funcs->hubp_disconnect)
416		hubp->funcs->hubp_disconnect(hubp);
417
418	if (dc->debug.sanity_checks)
419		hws->funcs.verify_allow_pstate_change_high(dc);
420}
421
422void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
423{
424	struct hubp *hubp = pipe_ctx->plane_res.hubp;
425	struct mpcc_blnd_cfg blnd_cfg;
426	bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
427	int mpcc_id, dpp_id;
428	struct mpcc *new_mpcc;
429	struct mpcc *remove_mpcc = NULL;
430	struct mpc *mpc = dc->res_pool->mpc;
431	struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
432
433	if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) {
434		get_hdr_visual_confirm_color(
435				pipe_ctx, &blnd_cfg.black_color);
436	} else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) {
437		get_surface_visual_confirm_color(
438				pipe_ctx, &blnd_cfg.black_color);
439	} else {
440		color_space_to_black_color(
441				dc, pipe_ctx->stream->output_color_space,
442				&blnd_cfg.black_color);
443	}
444
445	if (per_pixel_alpha)
446		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
447	else
448		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
449
450	blnd_cfg.overlap_only = false;
451
452	if (pipe_ctx->plane_state->global_alpha_value)
453		blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
454	else
455		blnd_cfg.global_alpha = 0xff;
456
457	blnd_cfg.global_gain = 0xff;
458	blnd_cfg.background_color_bpc = 4;
459	blnd_cfg.bottom_gain_mode = 0;
460	blnd_cfg.top_gain = 0x1f000;
461	blnd_cfg.bottom_inside_gain = 0x1f000;
462	blnd_cfg.bottom_outside_gain = 0x1f000;
463	/*the input to MPCC is RGB*/
464	blnd_cfg.black_color.color_b_cb = 0;
465	blnd_cfg.black_color.color_g_y = 0;
466	blnd_cfg.black_color.color_r_cr = 0;
467
468	/* DCN1.0 has output CM before MPC which seems to screw with
469	 * pre-multiplied alpha. This is a w/a hopefully unnecessary for DCN2.
470	 */
471	blnd_cfg.pre_multiplied_alpha = per_pixel_alpha;
472
473	/*
474	 * TODO: remove hack
475	 * Note: currently there is a bug in init_hw such that
476	 * on resume from hibernate, BIOS sets up MPCC0, and
477	 * we do mpcc_remove but the mpcc cannot go to idle
478	 * after remove. This cause us to pick mpcc1 here,
479	 * which causes a pstate hang for yet unknown reason.
480	 */
481	dpp_id = hubp->inst;
482	mpcc_id = dpp_id;
483
484	/* If there is no full update, don't need to touch MPC tree*/
485	if (!pipe_ctx->plane_state->update_flags.bits.full_update) {
486		dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
487		mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);
488		return;
489	}
490
491	/* check if this plane is being used by an MPCC in the secondary blending chain */
492	if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
493		remove_mpcc = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
494
495	/* remove MPCC from secondary if being used */
496	if (remove_mpcc != NULL && mpc->funcs->remove_mpcc_from_secondary)
497		mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, remove_mpcc);
498
499	/* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
500	remove_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
501	/* remove MPCC if being used */
502
503	if (remove_mpcc != NULL)
504		mpc->funcs->remove_mpcc(mpc, mpc_tree_params, remove_mpcc);
505	else
506		if (dc->debug.sanity_checks)
507			mpc->funcs->assert_mpcc_idle_before_connect(
508					dc->res_pool->mpc, mpcc_id);
509
510	/* Call MPC to insert new plane */
511	dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
512	new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
513			mpc_tree_params,
514			&blnd_cfg,
515			NULL,
516			NULL,
517			dpp_id,
518			mpcc_id);
519
520	ASSERT(new_mpcc != NULL);
521	hubp->opp_id = pipe_ctx->stream_res.opp->inst;
522	hubp->mpcc_id = mpcc_id;
523}
524
525void dcn201_pipe_control_lock(
526	struct dc *dc,
527	struct pipe_ctx *pipe,
528	bool lock)
529{
530	struct dce_hwseq *hws = dc->hwseq;
531	/* use TG master update lock to lock everything on the TG
532	 * therefore only top pipe need to lock
533	 */
534	if (pipe->top_pipe)
535		return;
536
537	if (dc->debug.sanity_checks)
538		hws->funcs.verify_allow_pstate_change_high(dc);
539
540	if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) {
541		if (lock)
542			pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg);
543		else
544			pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);
545	} else {
546		if (lock)
547			pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
548		else
549			pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
550	}
551
552	if (dc->debug.sanity_checks)
553		hws->funcs.verify_allow_pstate_change_high(dc);
554}
555
556void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
557{
558	struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
559
560	gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq, &attributes->address);
561
562	pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
563			pipe_ctx->plane_res.hubp, attributes);
564	pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes(
565		pipe_ctx->plane_res.dpp, attributes);
566}
567
568void dcn201_set_dmdata_attributes(struct pipe_ctx *pipe_ctx)
569{
570	struct dc_dmdata_attributes attr = { 0 };
571	struct hubp *hubp = pipe_ctx->plane_res.hubp;
572
573	gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq,
574			&pipe_ctx->stream->dmdata_address);
575
576	attr.dmdata_mode = DMDATA_HW_MODE;
577	attr.dmdata_size =
578		dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36;
579	attr.address.quad_part =
580			pipe_ctx->stream->dmdata_address.quad_part;
581	attr.dmdata_dl_delta = 0;
582	attr.dmdata_qos_mode = 0;
583	attr.dmdata_qos_level = 0;
584	attr.dmdata_repeat = 1; /* always repeat */
585	attr.dmdata_updated = 1;
586	attr.dmdata_sw_data = NULL;
587
588	hubp->funcs->dmdata_set_attributes(hubp, &attr);
589}
590
591void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx,
592		struct dc_link_settings *link_settings)
593{
594	struct encoder_unblank_param params = { { 0 } };
595	struct dc_stream_state *stream = pipe_ctx->stream;
596	struct dc_link *link = stream->link;
597	struct dce_hwseq *hws = link->dc->hwseq;
598
599	/* only 3 items below are used by unblank */
600	params.timing = pipe_ctx->stream->timing;
601
602	params.link_settings.link_rate = link_settings->link_rate;
603
604	if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
605		/*check whether it is half the rate*/
606		if (pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing))
607			params.timing.pix_clk_100hz /= 2;
608
609		pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
610	}
611
612	if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
613		hws->funcs.edp_backlight_control(link, true);
614	}
615}
~/ Read-only file preview.