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 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 {
99		is_in_uma = false;
100	}
101	return is_in_uma;
102}
103
104static 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();
126		break;
127	}
128}
129
130void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx)
131{
132	bool addr_patched = false;
133	PHYSICAL_ADDRESS_LOC 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)
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 */
161void 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;
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);
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
199static void read_mmhub_vm_setup(struct dce_hwseq *hws)
200{
201	uint32_t fb_base = REG_READ(MC_VM_FB_LOCATION_BASE);
202	uint32_t fb_top = REG_READ(MC_VM_FB_LOCATION_TOP);
203	uint32_t fb_offset = REG_READ(MC_VM_FB_OFFSET);
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
221void 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	hws->funcs.bios_golden_init(dc);
235
236	if (dc->ctx->dc_bios->fw_info_valid) {
237		res_pool->ref_clocks.xtalin_clock_inKhz =
238			dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
239
240		if (res_pool->dccg && res_pool->hubbub) {
241			(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
242					dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
243					&res_pool->ref_clocks.dccg_ref_clock_inKhz);
244
245			(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
246					res_pool->ref_clocks.dccg_ref_clock_inKhz,
247					&res_pool->ref_clocks.dchub_ref_clock_inKhz);
248		} else {
249			res_pool->ref_clocks.dccg_ref_clock_inKhz =
250					res_pool->ref_clocks.xtalin_clock_inKhz;
251			res_pool->ref_clocks.dchub_ref_clock_inKhz =
252					res_pool->ref_clocks.xtalin_clock_inKhz;
253		}
254	} else
255		ASSERT_CRITICAL(false);
256	for (i = 0; i < dc->link_count; i++) {
257		/* Power up AND update implementation according to the
258		 * required signal (which may be different from the
259		 * default signal on connector).
260		 */
261		struct dc_link *link = dc->links[i];
262
263		link->link_enc->funcs->hw_init(link->link_enc);
264	}
265	if (hws->fb_offset.quad_part == 0)
266		read_mmhub_vm_setup(hws);
267
268	/* Blank pixel data with OPP DPG */
269	for (i = 0; i < res_pool->timing_generator_count; i++) {
270		struct timing_generator *tg = res_pool->timing_generators[i];
271
272		if (tg->funcs->is_tg_enabled(tg)) {
273			dcn201_init_blank(dc, tg);
274		}
275	}
276
277	for (i = 0; i < res_pool->timing_generator_count; i++) {
278		struct timing_generator *tg = res_pool->timing_generators[i];
279
280		if (tg->funcs->is_tg_enabled(tg))
281			tg->funcs->lock(tg);
282	}
283
284	for (i = 0; i < res_pool->pipe_count; i++) {
285		struct dpp *dpp = res_pool->dpps[i];
286
287		dpp->funcs->dpp_reset(dpp);
288	}
289
290	/* Reset all MPCC muxes */
291	res_pool->mpc->funcs->mpc_init(res_pool->mpc);
292
293	/* initialize OPP mpc_tree parameter */
294	for (i = 0; i < res_pool->res_cap->num_opp; i++) {
295		res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst;
296		res_pool->opps[i]->mpc_tree_params.opp_list = NULL;
297		for (j = 0; j < MAX_PIPES; j++)
298			res_pool->opps[i]->mpcc_disconnect_pending[j] = false;
299	}
300
301	for (i = 0; i < res_pool->timing_generator_count; i++) {
302		struct timing_generator *tg = res_pool->timing_generators[i];
303		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
304		struct hubp *hubp = res_pool->hubps[i];
305		struct dpp *dpp = res_pool->dpps[i];
306
307		pipe_ctx->stream_res.tg = tg;
308		pipe_ctx->pipe_idx = i;
309
310		pipe_ctx->plane_res.hubp = hubp;
311		pipe_ctx->plane_res.dpp = dpp;
312		pipe_ctx->plane_res.mpcc_inst = dpp->inst;
313		hubp->mpcc_id = dpp->inst;
314		hubp->opp_id = OPP_ID_INVALID;
315		hubp->power_gated = false;
316		pipe_ctx->stream_res.opp = NULL;
317
318		hubp->funcs->hubp_init(hubp);
319
320		res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
321		pipe_ctx->stream_res.opp = res_pool->opps[i];
322		/*To do: number of MPCC != number of opp*/
323		hws->funcs.plane_atomic_disconnect(dc, pipe_ctx);
324	}
325
326	/* initialize DWB pointer to MCIF_WB */
327	for (i = 0; i < res_pool->res_cap->num_dwb; i++)
328		res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i];
329
330	for (i = 0; i < res_pool->timing_generator_count; i++) {
331		struct timing_generator *tg = res_pool->timing_generators[i];
332
333		if (tg->funcs->is_tg_enabled(tg))
334			tg->funcs->unlock(tg);
335	}
336
337	for (i = 0; i < res_pool->pipe_count; i++) {
338		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
339
340		dc->hwss.disable_plane(dc, pipe_ctx);
341
342		pipe_ctx->stream_res.tg = NULL;
343		pipe_ctx->plane_res.hubp = NULL;
344	}
345
346	for (i = 0; i < res_pool->timing_generator_count; i++) {
347		struct timing_generator *tg = res_pool->timing_generators[i];
348
349		tg->funcs->tg_init(tg);
350	}
351
352	for (i = 0; i < res_pool->audio_count; i++) {
353		struct audio *audio = res_pool->audios[i];
354
355		audio->funcs->hw_init(audio);
356	}
357
358	/* power AFMT HDMI memory TODO: may move to dis/en output save power*/
359	REG_WRITE(DIO_MEM_PWR_CTRL, 0);
360
361	if (!dc->debug.disable_clock_gate) {
362		/* enable all DCN clock gating */
363		REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
364
365		REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
366
367		REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
368	}
369}
370
371/* trigger HW to start disconnect plane from stream on the next vsync */
372void dcn201_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx)
373{
374	struct dce_hwseq *hws = dc->hwseq;
375	struct hubp *hubp = pipe_ctx->plane_res.hubp;
376	int dpp_id = pipe_ctx->plane_res.dpp->inst;
377	struct mpc *mpc = dc->res_pool->mpc;
378	struct mpc_tree *mpc_tree_params;
379	struct mpcc *mpcc_to_remove = NULL;
380	struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
381	bool mpcc_removed = false;
382
383	mpc_tree_params = &(opp->mpc_tree_params);
384
385	/* check if this plane is being used by an MPCC in the secondary blending chain */
386	if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
387		mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
388
389	/* remove MPCC from secondary if being used */
390	if (mpcc_to_remove != NULL && mpc->funcs->remove_mpcc_from_secondary) {
391		mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, mpcc_to_remove);
392		mpcc_removed = true;
393	}
394
395	/* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
396	mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
397	if (mpcc_to_remove != NULL) {
398		mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove);
399		mpcc_removed = true;
400	}
401
402	/*Already reset*/
403	if (mpcc_removed == false)
404		return;
405
406	if (opp != NULL)
407		opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true;
408
409	dc->optimized_required = true;
410
411	if (hubp->funcs->hubp_disconnect)
412		hubp->funcs->hubp_disconnect(hubp);
413
414	if (dc->debug.sanity_checks)
415		hws->funcs.verify_allow_pstate_change_high(dc);
416}
417
418void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
419{
420	struct hubp *hubp = pipe_ctx->plane_res.hubp;
421	struct mpcc_blnd_cfg blnd_cfg;
422	bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe;
423	int mpcc_id, dpp_id;
424	struct mpcc *new_mpcc;
425	struct mpcc *remove_mpcc = NULL;
426	struct mpc *mpc = dc->res_pool->mpc;
427	struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
428
429	if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) {
430		get_hdr_visual_confirm_color(
431				pipe_ctx, &blnd_cfg.black_color);
432	} else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) {
433		get_surface_visual_confirm_color(
434				pipe_ctx, &blnd_cfg.black_color);
435	} else {
436		color_space_to_black_color(
437				dc, pipe_ctx->stream->output_color_space,
438				&blnd_cfg.black_color);
439	}
440
441	if (per_pixel_alpha)
442		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
443	else
444		blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
445
446	blnd_cfg.overlap_only = false;
447
448	if (pipe_ctx->plane_state->global_alpha_value)
449		blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
450	else
451		blnd_cfg.global_alpha = 0xff;
452
453	blnd_cfg.global_gain = 0xff;
454	blnd_cfg.background_color_bpc = 4;
455	blnd_cfg.bottom_gain_mode = 0;
456	blnd_cfg.top_gain = 0x1f000;
457	blnd_cfg.bottom_inside_gain = 0x1f000;
458	blnd_cfg.bottom_outside_gain = 0x1f000;
459	/*the input to MPCC is RGB*/
460	blnd_cfg.black_color.color_b_cb = 0;
461	blnd_cfg.black_color.color_g_y = 0;
462	blnd_cfg.black_color.color_r_cr = 0;
463
464	/* DCN1.0 has output CM before MPC which seems to screw with
465	 * pre-multiplied alpha. This is a w/a hopefully unnecessary for DCN2.
466	 */
467	blnd_cfg.pre_multiplied_alpha = per_pixel_alpha;
468
469	/*
470	 * TODO: remove hack
471	 * Note: currently there is a bug in init_hw such that
472	 * on resume from hibernate, BIOS sets up MPCC0, and
473	 * we do mpcc_remove but the mpcc cannot go to idle
474	 * after remove. This cause us to pick mpcc1 here,
475	 * which causes a pstate hang for yet unknown reason.
476	 */
477	dpp_id = hubp->inst;
478	mpcc_id = dpp_id;
479
480	/* If there is no full update, don't need to touch MPC tree*/
481	if (!pipe_ctx->plane_state->update_flags.bits.full_update) {
482		dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
483		mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);
484		return;
485	}
486
487	/* check if this plane is being used by an MPCC in the secondary blending chain */
488	if (mpc->funcs->get_mpcc_for_dpp_from_secondary)
489		remove_mpcc = mpc->funcs->get_mpcc_for_dpp_from_secondary(mpc_tree_params, dpp_id);
490
491	/* remove MPCC from secondary if being used */
492	if (remove_mpcc != NULL && mpc->funcs->remove_mpcc_from_secondary)
493		mpc->funcs->remove_mpcc_from_secondary(mpc, mpc_tree_params, remove_mpcc);
494
495	/* check if this MPCC is already being used for this plane (dpp) in the primary blending chain */
496	remove_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, dpp_id);
497	/* remove MPCC if being used */
498
499	if (remove_mpcc != NULL)
500		mpc->funcs->remove_mpcc(mpc, mpc_tree_params, remove_mpcc);
501	else
502		if (dc->debug.sanity_checks)
503			mpc->funcs->assert_mpcc_idle_before_connect(
504					dc->res_pool->mpc, mpcc_id);
505
506	/* Call MPC to insert new plane */
507	dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
508	new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
509			mpc_tree_params,
510			&blnd_cfg,
511			NULL,
512			NULL,
513			dpp_id,
514			mpcc_id);
515
516	ASSERT(new_mpcc != NULL);
517	hubp->opp_id = pipe_ctx->stream_res.opp->inst;
518	hubp->mpcc_id = mpcc_id;
519}
520
521void dcn201_pipe_control_lock(
522	struct dc *dc,
523	struct pipe_ctx *pipe,
524	bool lock)
525{
526	struct dce_hwseq *hws = dc->hwseq;
527	/* use TG master update lock to lock everything on the TG
528	 * therefore only top pipe need to lock
529	 */
530	if (pipe->top_pipe)
531		return;
532
533	if (dc->debug.sanity_checks)
534		hws->funcs.verify_allow_pstate_change_high(dc);
535
536	if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) {
537		if (lock)
538			pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg);
539		else
540			pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg);
541	} else {
542		if (lock)
543			pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
544		else
545			pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
546	}
547
548	if (dc->debug.sanity_checks)
549		hws->funcs.verify_allow_pstate_change_high(dc);
550}
551
552void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
553{
554	struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
555
556	gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq, &attributes->address);
557
558	pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
559			pipe_ctx->plane_res.hubp, attributes);
560	pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes(
561		pipe_ctx->plane_res.dpp, attributes);
562}
563
564void dcn201_set_dmdata_attributes(struct pipe_ctx *pipe_ctx)
565{
566	struct dc_dmdata_attributes attr = { 0 };
567	struct hubp *hubp = pipe_ctx->plane_res.hubp;
568
569	gpu_addr_to_uma(pipe_ctx->stream->ctx->dc->hwseq,
570			&pipe_ctx->stream->dmdata_address);
571
572	attr.dmdata_mode = DMDATA_HW_MODE;
573	attr.dmdata_size =
574		dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36;
575	attr.address.quad_part =
576			pipe_ctx->stream->dmdata_address.quad_part;
577	attr.dmdata_dl_delta = 0;
578	attr.dmdata_qos_mode = 0;
579	attr.dmdata_qos_level = 0;
580	attr.dmdata_repeat = 1; /* always repeat */
581	attr.dmdata_updated = 1;
582	attr.dmdata_sw_data = NULL;
583
584	hubp->funcs->dmdata_set_attributes(hubp, &attr);
585}
586
587void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx,
588		struct dc_link_settings *link_settings)
589{
590	struct encoder_unblank_param params = { { 0 } };
591	struct dc_stream_state *stream = pipe_ctx->stream;
592	struct dc_link *link = stream->link;
593	struct dce_hwseq *hws = link->dc->hwseq;
594
595	/* only 3 items below are used by unblank */
596	params.timing = pipe_ctx->stream->timing;
597
598	params.link_settings.link_rate = link_settings->link_rate;
599
600	if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
601		/*check whether it is half the rate*/
602		if (optc201_is_two_pixels_per_containter(&stream->timing))
603			params.timing.pix_clk_100hz /= 2;
604
605		pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
606	}
607
608	if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
609		hws->funcs.edp_backlight_control(link, true);
610	}
611}
612