File Index
Files and directories
Sign in
FILE

dcn31_hwseq.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_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
 27#include "dm_services.h"
 28#include "dm_helpers.h"
 29#include "core_types.h"
 30#include "resource.h"
 31#include "dccg.h"
 32#include "dce/dce_hwseq.h"
 33#include "clk_mgr.h"
 34#include "reg_helper.h"
 35#include "abm.h"
 36#include "hubp.h"
 37#include "dchubbub.h"
 38#include "timing_generator.h"
 39#include "opp.h"
 40#include "ipp.h"
 41#include "mpc.h"
 42#include "mcif_wb.h"
 43#include "dc_dmub_srv.h"
 44#include "dcn31_hwseq.h"
 45#include "link_hwss.h"
 46#include "dpcd_defs.h"
 47#include "dce/dmub_outbox.h"
 48#include "link_service.h"
 49#include "dcn10/dcn10_hwseq.h"
 50#include "dcn21/dcn21_hwseq.h"
 51#include "inc/link_enc_cfg.h"
 52#include "dcn30/dcn30_vpg.h"
 53#include "dce/dce_i2c_hw.h"
 54#include "dce/dmub_abm_lcd.h"
 55
 56#define DC_LOGGER_INIT(logger)
 57
 58#define CTX \
 59	hws->ctx
 60#define REG(reg)\
 61	hws->regs->reg
 62#define DC_LOGGER \
 63		dc->ctx->logger
 64
 65
 66#undef FN
 67#define FN(reg_name, field_name) \
 68	hws->shifts->field_name, hws->masks->field_name
 69
 70static void enable_memory_low_power(struct dc *dc)
 71{
 72	struct dce_hwseq *hws = dc->hwseq;
 73	int i;
 74
 75	if (dc->debug.enable_mem_low_power.bits.dmcu) {
 76		// Force ERAM to shutdown if DMCU is not enabled
 77		if (dc->debug.disable_dmcu || dc->config.disable_dmcu) {
 78			REG_UPDATE(DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, 3);
 79		}
 80	}
 81
 82	// Set default OPTC memory power states
 83	if (dc->debug.enable_mem_low_power.bits.optc) {
 84		// Shutdown when unassigned and light sleep in VBLANK
 85		REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
 86	}
 87
 88	if (dc->debug.enable_mem_low_power.bits.vga) {
 89		// Power down VGA memory
 90		REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
 91	}
 92
 93	if (dc->debug.enable_mem_low_power.bits.mpc &&
 94		dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode)
 95		dc->res_pool->mpc->funcs->set_mpc_mem_lp_mode(dc->res_pool->mpc);
 96
 97
 98	if (dc->debug.enable_mem_low_power.bits.vpg && dc->res_pool->stream_enc[0]->vpg->funcs->vpg_powerdown) {
 99		// Power down VPGs
100		for (i = 0; i < dc->res_pool->stream_enc_count; i++)
101			if (dc->res_pool->stream_enc[i]->vpg)
102				dc->res_pool->stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->stream_enc[i]->vpg);
103		for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++)
104			dc->res_pool->hpo_dp_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_dp_stream_enc[i]->vpg);
105	}
106
107}
108
109void dcn31_init_hw(struct dc *dc)
110{
111	struct abm **abms = dc->res_pool->multiple_abms;
112	struct dce_hwseq *hws = dc->hwseq;
113	struct dc_bios *dcb = dc->ctx->dc_bios;
114	struct resource_pool *res_pool = dc->res_pool;
115	uint32_t backlight = MAX_BACKLIGHT_LEVEL;
116	uint32_t user_level = MAX_BACKLIGHT_LEVEL;
117	int i;
118
119	if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
120		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
121
122	if (!dcb->funcs->is_accelerated_mode(dcb)) {
123		hws->funcs.bios_golden_init(dc);
124		if (hws->funcs.disable_vga)
125			hws->funcs.disable_vga(dc->hwseq);
126	}
127	// Initialize the dccg
128	if (res_pool->dccg->funcs->dccg_init)
129		res_pool->dccg->funcs->dccg_init(res_pool->dccg);
130
131	enable_memory_low_power(dc);
132
133	if (dc->ctx->dc_bios->fw_info_valid) {
134		res_pool->ref_clocks.xtalin_clock_inKhz =
135				dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
136
137		if (res_pool->hubbub) {
138
139			(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
140					dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
141					&res_pool->ref_clocks.dccg_ref_clock_inKhz);
142
143			(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
144					res_pool->ref_clocks.dccg_ref_clock_inKhz,
145					&res_pool->ref_clocks.dchub_ref_clock_inKhz);
146		} else {
147			// Not all ASICs have DCCG sw component
148			res_pool->ref_clocks.dccg_ref_clock_inKhz =
149					res_pool->ref_clocks.xtalin_clock_inKhz;
150			res_pool->ref_clocks.dchub_ref_clock_inKhz =
151					res_pool->ref_clocks.xtalin_clock_inKhz;
152		}
153	} else
154		ASSERT_CRITICAL(false);
155
156	for (i = 0; i < dc->link_count; i++) {
157		/* Power up AND update implementation according to the
158		 * required signal (which may be different from the
159		 * default signal on connector).
160		 */
161		struct dc_link *link = dc->links[i];
162
163		if (link->ep_type != DISPLAY_ENDPOINT_PHY)
164			continue;
165
166		link->link_enc->funcs->hw_init(link->link_enc);
167
168		/* Check for enabled DIG to identify enabled display */
169		if (link->link_enc->funcs->is_dig_enabled &&
170			link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
171			link->link_status.link_active = true;
172			if (link->link_enc->funcs->fec_is_active &&
173					link->link_enc->funcs->fec_is_active(link->link_enc))
174				link->fec_state = dc_link_fec_enabled;
175		}
176	}
177
178	/* we want to turn off all dp displays before doing detection */
179	dc->link_srv->blank_all_dp_displays(dc);
180
181	if (hws->funcs.enable_power_gating_plane)
182		hws->funcs.enable_power_gating_plane(dc->hwseq, true);
183
184	/* If taking control over from VBIOS, we may want to optimize our first
185	 * mode set, so we need to skip powering down pipes until we know which
186	 * pipes we want to use.
187	 * Otherwise, if taking control is not possible, we need to power
188	 * everything down.
189	 */
190	if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
191
192		// we want to turn off edp displays if odm is enabled and no seamless boot
193		if (!dc->caps.seamless_odm) {
194			for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
195				struct timing_generator *tg = dc->res_pool->timing_generators[i];
196				uint32_t num_opps, opp_id_src0, opp_id_src1;
197
198				num_opps = 1;
199				if (tg) {
200					if (tg->funcs->is_tg_enabled(tg) && tg->funcs->get_optc_source) {
201						tg->funcs->get_optc_source(tg, &num_opps,
202								&opp_id_src0, &opp_id_src1);
203					}
204				}
205
206				if (num_opps > 1) {
207					dc->link_srv->blank_all_edp_displays(dc);
208					break;
209				}
210			}
211		}
212
213		hws->funcs.init_pipes(dc, dc->current_state);
214		if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
215			dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
216					!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
217	}
218
219	for (i = 0; i < res_pool->audio_count; i++) {
220		struct audio *audio = res_pool->audios[i];
221
222		audio->funcs->hw_init(audio);
223	}
224
225	for (i = 0; i < dc->link_count; i++) {
226		struct dc_link *link = dc->links[i];
227
228		if (link->panel_cntl) {
229			backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
230			user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL;
231		}
232	}
233
234	for (i = 0; i < dc->res_pool->pipe_count; i++) {
235		if (abms[i] != NULL)
236			abms[i]->funcs->abm_init(abms[i], backlight, user_level);
237	}
238
239	/* power AFMT HDMI memory TODO: may move to dis/en output save power*/
240	REG_WRITE(DIO_MEM_PWR_CTRL, 0);
241
242	// Set i2c to light sleep until engine is setup
243	if (dc->debug.enable_mem_low_power.bits.i2c)
244		REG_UPDATE(DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, 1);
245
246	if (hws->funcs.setup_hpo_hw_control)
247		hws->funcs.setup_hpo_hw_control(hws, false);
248
249	if (!dc->debug.disable_clock_gate) {
250		/* enable all DCN clock gating */
251		REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
252
253		REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0);
254
255		REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
256	}
257
258	if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
259		dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
260
261	if (dc->clk_mgr && dc->clk_mgr->funcs->notify_wm_ranges)
262		dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
263
264	if (dc->clk_mgr && dc->clk_mgr->funcs->set_hard_max_memclk && !dc->clk_mgr->dc_mode_softmax_enabled)
265		dc->clk_mgr->funcs->set_hard_max_memclk(dc->clk_mgr);
266
267	if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
268		dc->res_pool->hubbub->funcs->force_pstate_change_control(
269				dc->res_pool->hubbub, false, false);
270#if defined(CONFIG_DRM_AMD_DC_FP)
271	if (dc->res_pool->hubbub->funcs->init_crb)
272		dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
273#endif
274
275	// Get DMCUB capabilities
276	dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv);
277	dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
278	dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;
279}
280
281void dcn31_dsc_pg_control(
282		struct dce_hwseq *hws,
283		unsigned int dsc_inst,
284		bool power_on)
285{
286	uint32_t power_gate = power_on ? 0 : 1;
287	uint32_t pwr_status = power_on ? 0 : 2;
288	uint32_t org_ip_request_cntl = 0;
289
290	if (hws->ctx->dc->debug.disable_dsc_power_gate)
291		return;
292
293	if (hws->ctx->dc->debug.root_clock_optimization.bits.dsc &&
294		hws->ctx->dc->res_pool->dccg->funcs->enable_dsc &&
295		power_on)
296		hws->ctx->dc->res_pool->dccg->funcs->enable_dsc(
297			hws->ctx->dc->res_pool->dccg, dsc_inst);
298
299	REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
300	if (org_ip_request_cntl == 0)
301		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
302
303	switch (dsc_inst) {
304	case 0: /* DSC0 */
305		REG_UPDATE(DOMAIN16_PG_CONFIG,
306				DOMAIN_POWER_GATE, power_gate);
307
308		REG_WAIT(DOMAIN16_PG_STATUS,
309				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
310				1, 1000);
311		break;
312	case 1: /* DSC1 */
313		REG_UPDATE(DOMAIN17_PG_CONFIG,
314				DOMAIN_POWER_GATE, power_gate);
315
316		REG_WAIT(DOMAIN17_PG_STATUS,
317				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
318				1, 1000);
319		break;
320	case 2: /* DSC2 */
321		REG_UPDATE(DOMAIN18_PG_CONFIG,
322				DOMAIN_POWER_GATE, power_gate);
323
324		REG_WAIT(DOMAIN18_PG_STATUS,
325				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
326				1, 1000);
327		break;
328	default:
329		BREAK_TO_DEBUGGER();
330		break;
331	}
332
333	if (org_ip_request_cntl == 0)
334		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
335
336	if (hws->ctx->dc->debug.root_clock_optimization.bits.dsc) {
337		if (hws->ctx->dc->res_pool->dccg->funcs->disable_dsc && !power_on)
338			hws->ctx->dc->res_pool->dccg->funcs->disable_dsc(
339				hws->ctx->dc->res_pool->dccg, dsc_inst);
340	}
341
342}
343
344
345void dcn31_enable_power_gating_plane(
346	struct dce_hwseq *hws,
347	bool enable)
348{
349	bool force_on = true; /* disable power gating */
350	uint32_t org_ip_request_cntl = 0;
351
352	if (enable && !hws->ctx->dc->debug.disable_hubp_power_gate)
353		force_on = false;
354
355	REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
356	if (org_ip_request_cntl == 0)
357		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
358	/* DCHUBP0/1/2/3/4/5 */
359	REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
360	REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
361	/* DPP0/1/2/3/4/5 */
362	REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
363	REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
364
365	force_on = true; /* disable power gating */
366	if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate)
367		force_on = false;
368
369	/* DCS0/1/2/3/4/5 */
370	REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
371	REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
372	REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
373
374	if (org_ip_request_cntl == 0)
375		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
376}
377
378void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx)
379{
380	bool is_hdmi_tmds;
381	bool is_dp;
382
383	ASSERT(pipe_ctx->stream);
384
385	if (pipe_ctx->stream_res.stream_enc == NULL)
386		return;  /* this is not root pipe */
387
388	is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal);
389	is_dp = dc_is_dp_signal(pipe_ctx->stream->signal);
390
391	if (!is_hdmi_tmds && !is_dp)
392		return;
393
394	if (is_hdmi_tmds)
395		pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
396			pipe_ctx->stream_res.stream_enc,
397			&pipe_ctx->stream_res.encoder_info_frame);
398	else if (pipe_ctx->stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
399		if (pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->update_dp_info_packets_sdp_line_num)
400			pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->update_dp_info_packets_sdp_line_num(
401				pipe_ctx->stream_res.hpo_dp_stream_enc,
402				&pipe_ctx->stream_res.encoder_info_frame);
403
404		pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->update_dp_info_packets(
405				pipe_ctx->stream_res.hpo_dp_stream_enc,
406				&pipe_ctx->stream_res.encoder_info_frame);
407		return;
408	} else {
409		if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num)
410			pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num(
411				pipe_ctx->stream_res.stream_enc,
412				&pipe_ctx->stream_res.encoder_info_frame);
413
414		pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets(
415			pipe_ctx->stream_res.stream_enc,
416			&pipe_ctx->stream_res.encoder_info_frame);
417	}
418}
419void dcn31_z10_save_init(struct dc *dc)
420{
421	union dmub_rb_cmd cmd;
422
423	memset(&cmd, 0, sizeof(cmd));
424	cmd.dcn_restore.header.type = DMUB_CMD__IDLE_OPT;
425	cmd.dcn_restore.header.sub_type = DMUB_CMD__IDLE_OPT_DCN_SAVE_INIT;
426
427	dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
428}
429
430void dcn31_z10_restore(const struct dc *dc)
431{
432	union dmub_rb_cmd cmd;
433
434	/*
435	 * DMUB notifies whether restore is required.
436	 * Optimization to avoid sending commands when not required.
437	 */
438	if (!dc_dmub_srv_is_restore_required(dc->ctx->dmub_srv))
439		return;
440
441	memset(&cmd, 0, sizeof(cmd));
442	cmd.dcn_restore.header.type = DMUB_CMD__IDLE_OPT;
443	cmd.dcn_restore.header.sub_type = DMUB_CMD__IDLE_OPT_DCN_RESTORE;
444
445	dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
446}
447
448void dcn31_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on)
449{
450	uint32_t power_gate = power_on ? 0 : 1;
451	uint32_t pwr_status = power_on ? 0 : 2;
452	uint32_t org_ip_request_cntl;
453	if (hws->ctx->dc->debug.disable_hubp_power_gate)
454		return;
455
456	if (REG(DOMAIN0_PG_CONFIG) == 0)
457		return;
458	REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
459	if (org_ip_request_cntl == 0)
460		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
461
462	switch (hubp_inst) {
463	case 0:
464		REG_SET(DOMAIN0_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate);
465		REG_WAIT(DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
466		break;
467	case 1:
468		REG_SET(DOMAIN1_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate);
469		REG_WAIT(DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
470		break;
471	case 2:
472		REG_SET(DOMAIN2_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate);
473		REG_WAIT(DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
474		break;
475	case 3:
476		REG_SET(DOMAIN3_PG_CONFIG, 0, DOMAIN_POWER_GATE, power_gate);
477		REG_WAIT(DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000);
478		break;
479	default:
480		BREAK_TO_DEBUGGER();
481		break;
482	}
483	if (org_ip_request_cntl == 0)
484		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
485}
486
487int dcn31_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config)
488{
489	struct dcn_hubbub_phys_addr_config config = {0};
490
491	config.system_aperture.fb_top = pa_config->system_aperture.fb_top;
492	config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset;
493	config.system_aperture.fb_base = pa_config->system_aperture.fb_base;
494	config.system_aperture.agp_top = pa_config->system_aperture.agp_top;
495	config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot;
496	config.system_aperture.agp_base = pa_config->system_aperture.agp_base;
497	config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr;
498	config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr;
499
500	if (pa_config->gart_config.base_addr_is_mc_addr) {
501		/* Convert from MC address to offset into FB */
502		config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr -
503				pa_config->system_aperture.fb_base +
504				pa_config->system_aperture.fb_offset;
505	} else
506		config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr;
507
508	return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config);
509}
510
511static void dcn31_reset_back_end_for_pipe(
512		struct dc *dc,
513		struct pipe_ctx *pipe_ctx,
514		struct dc_state *context)
515{
516	struct dc_link *link;
517
518	DC_LOGGER_INIT(dc->ctx->logger);
519	if (pipe_ctx->stream_res.stream_enc == NULL) {
520		pipe_ctx->stream = NULL;
521		return;
522	}
523	ASSERT(!pipe_ctx->top_pipe);
524
525	dc->hwss.set_abm_immediate_disable(pipe_ctx);
526
527	link = pipe_ctx->stream->link;
528
529	if (dc->hwseq)
530		dc->hwseq->wa_state.skip_blank_stream = false;
531
532	if ((!pipe_ctx->stream->dpms_off || link->link_status.link_active) &&
533		(link->connector_signal == SIGNAL_TYPE_EDP)) {
534		dc->hwss.blank_stream(pipe_ctx);
535		if (dc->hwseq)
536			dc->hwseq->wa_state.skip_blank_stream = true;
537	}
538
539	pipe_ctx->stream_res.tg->funcs->set_dsc_config(
540			pipe_ctx->stream_res.tg,
541			OPTC_DSC_DISABLED, 0, 0);
542
543	pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
544
545	pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
546	if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)
547		pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
548				pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
549	/*
550	 * TODO - convert symclk_ref_cnts for otg to a bit map to solve
551	 * the case where the same symclk is shared across multiple otg
552	 * instances
553	 */
554	if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal))
555		link->phy_state.symclk_ref_cnts.otg = 0;
556
557	if (pipe_ctx->top_pipe == NULL) {
558		if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) {
559			const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
560
561			link_hwss->disable_link_output(link, &pipe_ctx->link_res, pipe_ctx->stream->signal);
562			link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
563		}
564	}
565
566	set_drr_and_clear_adjust_pending(pipe_ctx, pipe_ctx->stream, NULL);
567
568	/* DPMS may already disable or */
569	/* dpms_off status is incorrect due to fastboot
570	 * feature. When system resume from S4 with second
571	 * screen only, the dpms_off would be true but
572	 * VBIOS lit up eDP, so check link status too.
573	 */
574	if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
575		dc->link_srv->set_dpms_off(pipe_ctx);
576	else if (pipe_ctx->stream_res.audio)
577		dc->hwss.disable_audio_stream(pipe_ctx);
578
579	/* Temporary workaround to perform DSC programming ahead of pipe reset
580	 * for smartmux/SPRS
581	 * TODO: Remove SmartMux/SPRS checks once movement of DSC programming is generalized
582	 */
583	if (pipe_ctx->stream->timing.flags.DSC) {
584		if ((pipe_ctx->stream->signal == SIGNAL_TYPE_EDP &&
585			((link->dc->config.smart_mux_version && link->dc->is_switch_in_progress_dest)
586			|| link->is_dds || link->skip_implict_edp_power_control)) &&
587			(dc_is_dp_signal(pipe_ctx->stream->signal) ||
588			dc_is_virtual_signal(pipe_ctx->stream->signal)))
589			dc->link_srv->set_dsc_enable(pipe_ctx, false);
590	}
591
592	/* free acquired resources */
593	if (pipe_ctx->stream_res.audio) {
594		/*disable az_endpoint*/
595		pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
596
597		/*free audio*/
598		if (dc->caps.dynamic_audio == true) {
599			/*we have to dynamic arbitrate the audio endpoints*/
600			/*we free the resource, need reset is_audio_acquired*/
601			update_audio_usage(&dc->current_state->res_ctx, dc->res_pool,
602					pipe_ctx->stream_res.audio, false);
603			pipe_ctx->stream_res.audio = NULL;
604		}
605	}
606	if (dc->hwseq)
607		dc->hwseq->wa_state.skip_blank_stream = false;
608	pipe_ctx->stream = NULL;
609	DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
610					pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
611}
612
613void dcn31_reset_hw_ctx_wrap(
614		struct dc *dc,
615		struct dc_state *context)
616{
617	int i;
618	struct dce_hwseq *hws = dc->hwseq;
619
620	/* Reset Back End*/
621	for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
622		struct pipe_ctx *pipe_ctx_old =
623			&dc->current_state->res_ctx.pipe_ctx[i];
624		struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
625
626		if (!pipe_ctx_old->stream)
627			continue;
628
629		if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
630			continue;
631
632		if (!pipe_ctx->stream ||
633				pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
634			struct clock_source *old_clk = pipe_ctx_old->clock_source;
635
636			/* Reset pipe which is seamless boot stream. */
637			if (!pipe_ctx_old->plane_state &&
638				dc->res_pool->hubbub->funcs->program_det_size &&
639				dc->res_pool->hubbub->funcs->wait_for_det_apply) {
640				dc->res_pool->hubbub->funcs->program_det_size(
641					dc->res_pool->hubbub, pipe_ctx_old->plane_res.hubp->inst, 0);
642				/* Wait det size changed. */
643				dc->res_pool->hubbub->funcs->wait_for_det_apply(
644					dc->res_pool->hubbub, pipe_ctx_old->plane_res.hubp->inst);
645			}
646
647			dcn31_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);
648			if (hws->funcs.enable_stream_gating)
649				hws->funcs.enable_stream_gating(dc, pipe_ctx_old);
650			if (old_clk)
651				old_clk->funcs->cs_power_down(old_clk);
652		}
653	}
654
655	/* New dc_state in the process of being applied to hardware. */
656	if (!dc->config.unify_link_enc_assignment)
657		link_enc_cfg_set_transient_mode(dc, dc->current_state, context);
658}
659
660void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable)
661{
662	if (hws->ctx->dc->debug.hpo_optimization)
663		REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, !!enable);
664}
665
666void dcn31_set_static_screen_control(struct pipe_ctx **pipe_ctx,
667		int num_pipes, const struct dc_static_screen_params *params)
668{
669	unsigned int i;
670	unsigned int triggers = 0;
671
672	if (params->triggers.surface_update)
673		triggers |= 0x100;
674	if (params->triggers.cursor_update)
675		triggers |= 0x8;
676	if (params->triggers.force_trigger)
677		triggers |= 0x1;
678
679	for (i = 0; i < num_pipes; i++)
680		pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(pipe_ctx[i]->stream_res.tg,
681					triggers, params->num_frames);
682}
683
684static void dmub_abm_set_backlight(struct dc_context *dc,
685	struct set_backlight_level_params *backlight_level_params, uint32_t panel_inst)
686{
687	union dmub_rb_cmd cmd;
688
689	memset(&cmd, 0, sizeof(cmd));
690	cmd.abm_set_backlight.header.type = DMUB_CMD__ABM;
691	cmd.abm_set_backlight.header.sub_type = DMUB_CMD__ABM_SET_BACKLIGHT;
692	cmd.abm_set_backlight.abm_set_backlight_data.frame_ramp = backlight_level_params->frame_ramp;
693	cmd.abm_set_backlight.abm_set_backlight_data.backlight_user_level = backlight_level_params->backlight_pwm_u16_16;
694	cmd.abm_set_backlight.abm_set_backlight_data.backlight_control_type =
695		(enum dmub_backlight_control_type) backlight_level_params->control_type;
696	cmd.abm_set_backlight.abm_set_backlight_data.min_luminance = backlight_level_params->min_luminance;
697	cmd.abm_set_backlight.abm_set_backlight_data.max_luminance = backlight_level_params->max_luminance;
698	cmd.abm_set_backlight.abm_set_backlight_data.min_backlight_pwm = backlight_level_params->min_backlight_pwm;
699	cmd.abm_set_backlight.abm_set_backlight_data.max_backlight_pwm = backlight_level_params->max_backlight_pwm;
700	cmd.abm_set_backlight.abm_set_backlight_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1;
701	cmd.abm_set_backlight.abm_set_backlight_data.panel_mask = (0x01 << panel_inst);
702	cmd.abm_set_backlight.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_backlight_data);
703
704	dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
705}
706
707bool dcn31_set_backlight_level(struct pipe_ctx *pipe_ctx,
708	struct set_backlight_level_params *backlight_level_params)
709{
710	struct dc_context *dc = pipe_ctx->stream->ctx;
711	struct abm *abm = pipe_ctx->stream_res.abm;
712	struct timing_generator *tg = pipe_ctx->stream_res.tg;
713	struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl;
714	uint32_t otg_inst;
715
716	if (!abm || !tg || !panel_cntl)
717		return false;
718
719	otg_inst = tg->inst;
720
721		dcn21_dmub_abm_set_pipe(abm,
722			otg_inst,
723			SET_ABM_PIPE_NORMAL,
724			panel_cntl->inst,
725			panel_cntl->pwrseq_inst);
726
727	if (backlight_level_params->control_type != BACKLIGHT_CONTROL_AMD_AUX)
728		dmub_abm_set_backlight(dc, backlight_level_params, panel_cntl->inst);
729
730	return true;
731}
~/ Read-only file preview.