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 "core_types.h"
28#include "resource.h"
29#include "custom_float.h"
30#include "dcn10/dcn10_hwseq.h"
31#include "dce110/dce110_hwseq.h"
32#include "dce/dce_hwseq.h"
33#include "abm.h"
34#include "dmcu.h"
35#include "dcn10/dcn10_optc.h"
36#include "dcn10/dcn10_dpp.h"
37#include "dcn10/dcn10_mpc.h"
38#include "timing_generator.h"
39#include "opp.h"
40#include "ipp.h"
41#include "mpc.h"
42#include "reg_helper.h"
43#include "dcn10_hubp.h"
44#include "dcn10_hubbub.h"
45#include "dcn10_cm_common.h"
46#include "clk_mgr.h"
47
48__printf(3, 4)
49unsigned int snprintf_count(char *pbuf, unsigned int bufsize, char *fmt, ...)
50{
51	int ret_vsnprintf;
52	unsigned int chars_printed;
53
54	va_list args;
55	va_start(args, fmt);
56
57	ret_vsnprintf = vsnprintf(pbuf, bufsize, fmt, args);
58
59	va_end(args);
60
61	if (ret_vsnprintf > 0) {
62		if (ret_vsnprintf < bufsize)
63			chars_printed = ret_vsnprintf;
64		else
65			chars_printed = bufsize - 1;
66	} else
67		chars_printed = 0;
68
69	return chars_printed;
70}
71
72static unsigned int dcn10_get_hubbub_state(struct dc *dc, char *pBuf, unsigned int bufSize)
73{
74	struct dc_context *dc_ctx = dc->ctx;
75	struct dcn_hubbub_wm wm;
76	int i;
77
78	unsigned int chars_printed = 0;
79	unsigned int remaining_buffer = bufSize;
80
81	const uint32_t ref_clk_mhz = dc_ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
82	static const unsigned int frac = 1000;
83
84	memset(&wm, 0, sizeof(struct dcn_hubbub_wm));
85	dc->res_pool->hubbub->funcs->wm_read_state(dc->res_pool->hubbub, &wm);
86
87	chars_printed = snprintf_count(pBuf, remaining_buffer, "wm_set_index,data_urgent,pte_meta_urgent,sr_enter,sr_exit,dram_clk_change\n");
88	remaining_buffer -= chars_printed;
89	pBuf += chars_printed;
90
91	for (i = 0; i < 4; i++) {
92		struct dcn_hubbub_wm_set *s;
93
94		s = &wm.sets[i];
95
96		chars_printed = snprintf_count(pBuf, remaining_buffer, "%x,%d.%03d,%d.%03d,%d.%03d,%d.%03d,%d.%03d\n",
97			s->wm_set,
98			(s->data_urgent * frac) / ref_clk_mhz / frac, (s->data_urgent * frac) / ref_clk_mhz % frac,
99			(s->pte_meta_urgent * frac) / ref_clk_mhz / frac, (s->pte_meta_urgent * frac) / ref_clk_mhz % frac,
100			(s->sr_enter * frac) / ref_clk_mhz / frac, (s->sr_enter * frac) / ref_clk_mhz % frac,
101			(s->sr_exit * frac) / ref_clk_mhz / frac, (s->sr_exit * frac) / ref_clk_mhz % frac,
102			(s->dram_clk_change * frac) / ref_clk_mhz / frac, (s->dram_clk_change * frac) / ref_clk_mhz % frac);
103		remaining_buffer -= chars_printed;
104		pBuf += chars_printed;
105	}
106
107	return bufSize - remaining_buffer;
108}
109
110static unsigned int dcn10_get_hubp_states(struct dc *dc, char *pBuf, unsigned int bufSize, bool invarOnly)
111{
112	struct dc_context *dc_ctx = dc->ctx;
113	struct resource_pool *pool = dc->res_pool;
114	int i;
115
116	unsigned int chars_printed = 0;
117	unsigned int remaining_buffer = bufSize;
118
119	const uint32_t ref_clk_mhz = dc_ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
120	static const unsigned int frac = 1000;
121
122	if (invarOnly)
123		chars_printed = snprintf_count(pBuf, remaining_buffer, "instance,format,addr_hi,width,height,rotation,mirror,sw_mode,dcc_en,blank_en,ttu_dis,underflow,"
124			"min_ttu_vblank,qos_low_wm,qos_high_wm"
125			"\n");
126	else
127		chars_printed = snprintf_count(pBuf, remaining_buffer, "instance,format,addr_hi,addr_lo,width,height,rotation,mirror,sw_mode,dcc_en,blank_en,ttu_dis,underflow,"
128					"min_ttu_vblank,qos_low_wm,qos_high_wm"
129					"\n");
130
131	remaining_buffer -= chars_printed;
132	pBuf += chars_printed;
133
134	for (i = 0; i < pool->pipe_count; i++) {
135		struct hubp *hubp = pool->hubps[i];
136		struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state);
137
138		hubp->funcs->hubp_read_state(hubp);
139
140		if (!s->blank_en) {
141			if (invarOnly)
142				chars_printed = snprintf_count(pBuf, remaining_buffer, "%x,%x,%x,%d,%d,%x,%x,%x,%x,%x,%x,%x,"
143					"%d.%03d,%d.%03d,%d.%03d"
144					"\n",
145					hubp->inst,
146					s->pixel_format,
147					s->inuse_addr_hi,
148					s->viewport_width,
149					s->viewport_height,
150					s->rotation_angle,
151					s->h_mirror_en,
152					s->sw_mode,
153					s->dcc_en,
154					s->blank_en,
155					s->ttu_disable,
156					s->underflow_status,
157					(s->min_ttu_vblank * frac) / ref_clk_mhz / frac, (s->min_ttu_vblank * frac) / ref_clk_mhz % frac,
158					(s->qos_level_low_wm * frac) / ref_clk_mhz / frac, (s->qos_level_low_wm * frac) / ref_clk_mhz % frac,
159					(s->qos_level_high_wm * frac) / ref_clk_mhz / frac, (s->qos_level_high_wm * frac) / ref_clk_mhz % frac);
160			else
161				chars_printed = snprintf_count(pBuf, remaining_buffer, "%x,%x,%x,%x,%d,%d,%x,%x,%x,%x,%x,%x,%x,"
162					"%d.%03d,%d.%03d,%d.%03d"
163					"\n",
164					hubp->inst,
165					s->pixel_format,
166					s->inuse_addr_hi,
167					s->inuse_addr_lo,
168					s->viewport_width,
169					s->viewport_height,
170					s->rotation_angle,
171					s->h_mirror_en,
172					s->sw_mode,
173					s->dcc_en,
174					s->blank_en,
175					s->ttu_disable,
176					s->underflow_status,
177					(s->min_ttu_vblank * frac) / ref_clk_mhz / frac, (s->min_ttu_vblank * frac) / ref_clk_mhz % frac,
178					(s->qos_level_low_wm * frac) / ref_clk_mhz / frac, (s->qos_level_low_wm * frac) / ref_clk_mhz % frac,
179					(s->qos_level_high_wm * frac) / ref_clk_mhz / frac, (s->qos_level_high_wm * frac) / ref_clk_mhz % frac);
180
181			remaining_buffer -= chars_printed;
182			pBuf += chars_printed;
183		}
184	}
185
186	return bufSize - remaining_buffer;
187}
188
189static unsigned int dcn10_get_rq_states(struct dc *dc, char *pBuf, unsigned int bufSize)
190{
191	struct resource_pool *pool = dc->res_pool;
192	int i;
193
194	unsigned int chars_printed = 0;
195	unsigned int remaining_buffer = bufSize;
196
197	chars_printed = snprintf_count(pBuf, remaining_buffer, "instance,drq_exp_m,prq_exp_m,mrq_exp_m,crq_exp_m,plane1_ba,"
198		"luma_chunk_s,luma_min_chu_s,luma_meta_ch_s,luma_min_m_c_s,luma_dpte_gr_s,luma_mpte_gr_s,luma_swath_hei,luma_pte_row_h,"
199		"chroma_chunk_s,chroma_min_chu_s,chroma_meta_ch_s,chroma_min_m_c_s,chroma_dpte_gr_s,chroma_mpte_gr_s,chroma_swath_hei,chroma_pte_row_h"
200		"\n");
201	remaining_buffer -= chars_printed;
202	pBuf += chars_printed;
203
204	for (i = 0; i < pool->pipe_count; i++) {
205		struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state);
206		struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs;
207
208		if (!s->blank_en) {
209			chars_printed = snprintf_count(pBuf, remaining_buffer, "%x,%x,%x,%x,%x,%x,"
210				"%x,%x,%x,%x,%x,%x,%x,%x,"
211				"%x,%x,%x,%x,%x,%x,%x,%x"
212				"\n",
213				pool->hubps[i]->inst, rq_regs->drq_expansion_mode, rq_regs->prq_expansion_mode, rq_regs->mrq_expansion_mode,
214				rq_regs->crq_expansion_mode, rq_regs->plane1_base_address, rq_regs->rq_regs_l.chunk_size,
215				rq_regs->rq_regs_l.min_chunk_size, rq_regs->rq_regs_l.meta_chunk_size,
216				rq_regs->rq_regs_l.min_meta_chunk_size, rq_regs->rq_regs_l.dpte_group_size,
217				rq_regs->rq_regs_l.mpte_group_size, rq_regs->rq_regs_l.swath_height,
218				rq_regs->rq_regs_l.pte_row_height_linear, rq_regs->rq_regs_c.chunk_size, rq_regs->rq_regs_c.min_chunk_size,
219				rq_regs->rq_regs_c.meta_chunk_size, rq_regs->rq_regs_c.min_meta_chunk_size,
220				rq_regs->rq_regs_c.dpte_group_size, rq_regs->rq_regs_c.mpte_group_size,
221				rq_regs->rq_regs_c.swath_height, rq_regs->rq_regs_c.pte_row_height_linear);
222
223			remaining_buffer -= chars_printed;
224			pBuf += chars_printed;
225		}
226	}
227
228	return bufSize - remaining_buffer;
229}
230
231static unsigned int dcn10_get_dlg_states(struct dc *dc, char *pBuf, unsigned int bufSize)
232{
233	struct resource_pool *pool = dc->res_pool;
234	int i;
235
236	unsigned int chars_printed = 0;
237	unsigned int remaining_buffer = bufSize;
238
239	chars_printed = snprintf_count(pBuf, remaining_buffer, "instance,rc_hbe,dlg_vbe,min_d_y_n,rc_per_ht,rc_x_a_s,"
240		"dst_y_a_s,dst_y_pf,dst_y_vvb,dst_y_rvb,dst_y_vfl,dst_y_rfl,rf_pix_fq,"
241		"vratio_pf,vrat_pf_c,rc_pg_vbl,rc_pg_vbc,rc_mc_vbl,rc_mc_vbc,rc_pg_fll,"
242		"rc_pg_flc,rc_mc_fll,rc_mc_flc,pr_nom_l,pr_nom_c,rc_pg_nl,rc_pg_nc,"
243		"mr_nom_l,mr_nom_c,rc_mc_nl,rc_mc_nc,rc_ld_pl,rc_ld_pc,rc_ld_l,"
244		"rc_ld_c,cha_cur0,ofst_cur1,cha_cur1,vr_af_vc0,ddrq_limt,x_rt_dlay,x_rp_dlay,x_rr_sfl"
245		"\n");
246	remaining_buffer -= chars_printed;
247	pBuf += chars_printed;
248
249	for (i = 0; i < pool->pipe_count; i++) {
250		struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state);
251		struct _vcs_dpi_display_dlg_regs_st *dlg_regs = &s->dlg_attr;
252
253		if (!s->blank_en) {
254			chars_printed = snprintf_count(pBuf, remaining_buffer, "%x,%x,%x,%x,%x,"
255				"%x,%x,%x,%x,%x,%x,%x,"
256				"%x,%x,%x,%x,%x,%x,%x,"
257				"%x,%x,%x,%x,%x,%x,%x,"
258				"%x,%x,%x,%x,%x,%x,%x,"
259				"%x,%x,%x,%x,%x,%x,%x,%x,%x,%x"
260				"\n",
261				pool->hubps[i]->inst, dlg_regs->refcyc_h_blank_end, dlg_regs->dlg_vblank_end, dlg_regs->min_dst_y_next_start,
262				dlg_regs->refcyc_per_htotal, dlg_regs->refcyc_x_after_scaler, dlg_regs->dst_y_after_scaler,
263				dlg_regs->dst_y_prefetch, dlg_regs->dst_y_per_vm_vblank, dlg_regs->dst_y_per_row_vblank,
264				dlg_regs->dst_y_per_vm_flip, dlg_regs->dst_y_per_row_flip, dlg_regs->ref_freq_to_pix_freq,
265				dlg_regs->vratio_prefetch, dlg_regs->vratio_prefetch_c, dlg_regs->refcyc_per_pte_group_vblank_l,
266				dlg_regs->refcyc_per_pte_group_vblank_c, dlg_regs->refcyc_per_meta_chunk_vblank_l,
267				dlg_regs->refcyc_per_meta_chunk_vblank_c, dlg_regs->refcyc_per_pte_group_flip_l,
268				dlg_regs->refcyc_per_pte_group_flip_c, dlg_regs->refcyc_per_meta_chunk_flip_l,
269				dlg_regs->refcyc_per_meta_chunk_flip_c, dlg_regs->dst_y_per_pte_row_nom_l,
270				dlg_regs->dst_y_per_pte_row_nom_c, dlg_regs->refcyc_per_pte_group_nom_l,
271				dlg_regs->refcyc_per_pte_group_nom_c, dlg_regs->dst_y_per_meta_row_nom_l,
272				dlg_regs->dst_y_per_meta_row_nom_c, dlg_regs->refcyc_per_meta_chunk_nom_l,
273				dlg_regs->refcyc_per_meta_chunk_nom_c, dlg_regs->refcyc_per_line_delivery_pre_l,
274				dlg_regs->refcyc_per_line_delivery_pre_c, dlg_regs->refcyc_per_line_delivery_l,
275				dlg_regs->refcyc_per_line_delivery_c, dlg_regs->chunk_hdl_adjust_cur0, dlg_regs->dst_y_offset_cur1,
276				dlg_regs->chunk_hdl_adjust_cur1, dlg_regs->vready_after_vcount0, dlg_regs->dst_y_delta_drq_limit,
277				dlg_regs->xfc_reg_transfer_delay, dlg_regs->xfc_reg_precharge_delay,
278				dlg_regs->xfc_reg_remote_surface_flip_latency);
279
280			remaining_buffer -= chars_printed;
281			pBuf += chars_printed;
282		}
283	}
284
285	return bufSize - remaining_buffer;
286}
287
288static unsigned int dcn10_get_ttu_states(struct dc *dc, char *pBuf, unsigned int bufSize)
289{
290	struct resource_pool *pool = dc->res_pool;
291	int i;
292
293	unsigned int chars_printed = 0;
294	unsigned int remaining_buffer = bufSize;
295
296	chars_printed = snprintf_count(pBuf, remaining_buffer, "instance,qos_ll_wm,qos_lh_wm,mn_ttu_vb,qos_l_flp,rc_rd_p_l,rc_rd_l,rc_rd_p_c,"
297		"rc_rd_c,rc_rd_c0,rc_rd_pc0,rc_rd_c1,rc_rd_pc1,qos_lf_l,qos_rds_l,"
298		"qos_lf_c,qos_rds_c,qos_lf_c0,qos_rds_c0,qos_lf_c1,qos_rds_c1"
299		"\n");
300	remaining_buffer -= chars_printed;
301	pBuf += chars_printed;
302
303	for (i = 0; i < pool->pipe_count; i++) {
304		struct dcn_hubp_state *s = &(TO_DCN10_HUBP(pool->hubps[i])->state);
305		struct _vcs_dpi_display_ttu_regs_st *ttu_regs = &s->ttu_attr;
306
307		if (!s->blank_en) {
308			chars_printed = snprintf_count(pBuf, remaining_buffer, "%x,%x,%x,%x,%x,%x,%x,%x,"
309				"%x,%x,%x,%x,%x,%x,%x,"
310				"%x,%x,%x,%x,%x,%x"
311				"\n",
312				pool->hubps[i]->inst, ttu_regs->qos_level_low_wm, ttu_regs->qos_level_high_wm, ttu_regs->min_ttu_vblank,
313				ttu_regs->qos_level_flip, ttu_regs->refcyc_per_req_delivery_pre_l, ttu_regs->refcyc_per_req_delivery_l,
314				ttu_regs->refcyc_per_req_delivery_pre_c, ttu_regs->refcyc_per_req_delivery_c, ttu_regs->refcyc_per_req_delivery_cur0,
315				ttu_regs->refcyc_per_req_delivery_pre_cur0, ttu_regs->refcyc_per_req_delivery_cur1,
316				ttu_regs->refcyc_per_req_delivery_pre_cur1, ttu_regs->qos_level_fixed_l, ttu_regs->qos_ramp_disable_l,
317				ttu_regs->qos_level_fixed_c, ttu_regs->qos_ramp_disable_c, ttu_regs->qos_level_fixed_cur0,
318				ttu_regs->qos_ramp_disable_cur0, ttu_regs->qos_level_fixed_cur1, ttu_regs->qos_ramp_disable_cur1);
319
320			remaining_buffer -= chars_printed;
321			pBuf += chars_printed;
322		}
323	}
324
325	return bufSize - remaining_buffer;
326}
327
328static unsigned int dcn10_get_cm_states(struct dc *dc, char *pBuf, unsigned int bufSize)
329{
330	struct resource_pool *pool = dc->res_pool;
331	int i;
332
333	unsigned int chars_printed = 0;
334	unsigned int remaining_buffer = bufSize;
335
336	chars_printed = snprintf_count(pBuf, remaining_buffer, "instance,igam_format,igam_mode,dgam_mode,rgam_mode,gamut_mode,"
337		"c11_c12,c13_c14,c21_c22,c23_c24,c31_c32,c33_c34"
338		"\n");
339	remaining_buffer -= chars_printed;
340	pBuf += chars_printed;
341
342	for (i = 0; i < pool->pipe_count; i++) {
343		struct dpp *dpp = pool->dpps[i];
344		struct dcn_dpp_state s = {0};
345
346		dpp->funcs->dpp_read_state(dpp, &s);
347
348		if (s.is_enabled) {
349			chars_printed = snprintf_count(pBuf, remaining_buffer, "%x,%x,"
350					"%s,%s,%s,"
351					"%x,%08x,%08x,%08x,%08x,%08x,%08x"
352				"\n",
353				dpp->inst, s.igam_input_format,
354				(s.igam_lut_mode == 0) ? "BypassFixed" :
355					((s.igam_lut_mode == 1) ? "BypassFloat" :
356					((s.igam_lut_mode == 2) ? "RAM" :
357					((s.igam_lut_mode == 3) ? "RAM" :
358								 "Unknown"))),
359				(s.dgam_lut_mode == 0) ? "Bypass" :
360					((s.dgam_lut_mode == 1) ? "sRGB" :
361					((s.dgam_lut_mode == 2) ? "Ycc" :
362					((s.dgam_lut_mode == 3) ? "RAM" :
363					((s.dgam_lut_mode == 4) ? "RAM" :
364								 "Unknown")))),
365				(s.rgam_lut_mode == 0) ? "Bypass" :
366					((s.rgam_lut_mode == 1) ? "sRGB" :
367					((s.rgam_lut_mode == 2) ? "Ycc" :
368					((s.rgam_lut_mode == 3) ? "RAM" :
369					((s.rgam_lut_mode == 4) ? "RAM" :
370								 "Unknown")))),
371				s.gamut_remap_mode, s.gamut_remap_c11_c12,
372				s.gamut_remap_c13_c14, s.gamut_remap_c21_c22, s.gamut_remap_c23_c24,
373				s.gamut_remap_c31_c32, s.gamut_remap_c33_c34);
374
375			remaining_buffer -= chars_printed;
376			pBuf += chars_printed;
377		}
378	}
379
380	return bufSize - remaining_buffer;
381}
382
383static unsigned int dcn10_get_mpcc_states(struct dc *dc, char *pBuf, unsigned int bufSize)
384{
385	struct resource_pool *pool = dc->res_pool;
386	int i;
387
388	unsigned int chars_printed = 0;
389	unsigned int remaining_buffer = bufSize;
390
391	chars_printed = snprintf_count(pBuf, remaining_buffer, "instance,opp,dpp,mpccbot,mode,alpha_mode,premult,overlap_only,idle\n");
392	remaining_buffer -= chars_printed;
393	pBuf += chars_printed;
394
395	for (i = 0; i < pool->pipe_count; i++) {
396		struct mpcc_state s = {0};
397
398		pool->mpc->funcs->read_mpcc_state(pool->mpc, i, &s);
399
400		if (s.opp_id != 0xf) {
401			chars_printed = snprintf_count(pBuf, remaining_buffer, "%x,%x,%x,%x,%x,%x,%x,%x,%x\n",
402				i, s.opp_id, s.dpp_id, s.bot_mpcc_id,
403				s.mode, s.alpha_mode, s.pre_multiplied_alpha, s.overlap_only,
404				s.idle);
405
406			remaining_buffer -= chars_printed;
407			pBuf += chars_printed;
408		}
409	}
410
411	return bufSize - remaining_buffer;
412}
413
414static unsigned int dcn10_get_otg_states(struct dc *dc, char *pBuf, unsigned int bufSize)
415{
416	struct resource_pool *pool = dc->res_pool;
417	int i;
418
419	unsigned int chars_printed = 0;
420	unsigned int remaining_buffer = bufSize;
421
422	chars_printed = snprintf_count(pBuf, remaining_buffer, "instance,v_bs,v_be,v_ss,v_se,vpol,vmax,vmin,vmax_sel,vmin_sel,"
423			"h_bs,h_be,h_ss,h_se,hpol,htot,vtot,underflow,pixelclk[khz]\n");
424	remaining_buffer -= chars_printed;
425	pBuf += chars_printed;
426
427	for (i = 0; i < pool->timing_generator_count; i++) {
428		struct timing_generator *tg = pool->timing_generators[i];
429		struct dcn_otg_state s = {0};
430		int pix_clk = 0;
431
432		optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
433		pix_clk = dc->current_state->res_ctx.pipe_ctx[i].stream_res.pix_clk_params.requested_pix_clk_100hz / 10;
434
435		//only print if OTG master is enabled
436		if (s.otg_enabled & 1) {
437			chars_printed = snprintf_count(pBuf, remaining_buffer, "%x,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
438				"%d,%d,%d,%d,%d,%d,%d,%d,%d"
439				"\n",
440				tg->inst,
441				s.v_blank_start,
442				s.v_blank_end,
443				s.v_sync_a_start,
444				s.v_sync_a_end,
445				s.v_sync_a_pol,
446				s.v_total_max,
447				s.v_total_min,
448				s.v_total_max_sel,
449				s.v_total_min_sel,
450				s.h_blank_start,
451				s.h_blank_end,
452				s.h_sync_a_start,
453				s.h_sync_a_end,
454				s.h_sync_a_pol,
455				s.h_total,
456				s.v_total,
457				s.underflow_occurred_status,
458				pix_clk);
459
460			remaining_buffer -= chars_printed;
461			pBuf += chars_printed;
462		}
463	}
464
465	return bufSize - remaining_buffer;
466}
467
468static unsigned int dcn10_get_clock_states(struct dc *dc, char *pBuf, unsigned int bufSize)
469{
470	unsigned int chars_printed = 0;
471	unsigned int remaining_buffer = bufSize;
472
473	chars_printed = snprintf_count(pBuf, bufSize, "dcfclk,dcfclk_deep_sleep,dispclk,"
474		"dppclk,fclk,socclk\n"
475		"%d,%d,%d,%d,%d,%d\n",
476		dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_khz,
477		dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz,
478		dc->current_state->bw_ctx.bw.dcn.clk.dispclk_khz,
479		dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz,
480		dc->current_state->bw_ctx.bw.dcn.clk.fclk_khz,
481		dc->current_state->bw_ctx.bw.dcn.clk.socclk_khz);
482
483	remaining_buffer -= chars_printed;
484	pBuf += chars_printed;
485
486	return bufSize - remaining_buffer;
487}
488
489static void dcn10_clear_otpc_underflow(struct dc *dc)
490{
491	struct resource_pool *pool = dc->res_pool;
492	int i;
493
494	for (i = 0; i < pool->timing_generator_count; i++) {
495		struct timing_generator *tg = pool->timing_generators[i];
496		struct dcn_otg_state s = {0};
497
498		optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s);
499
500		if (s.otg_enabled & 1)
501			tg->funcs->clear_optc_underflow(tg);
502	}
503}
504
505static void dcn10_clear_hubp_underflow(struct dc *dc)
506{
507	struct resource_pool *pool = dc->res_pool;
508	int i;
509
510	for (i = 0; i < pool->pipe_count; i++) {
511		struct hubp *hubp = pool->hubps[i];
512		struct dcn_hubp_state *s = &(TO_DCN10_HUBP(hubp)->state);
513
514		hubp->funcs->hubp_read_state(hubp);
515
516		if (!s->blank_en)
517			hubp->funcs->hubp_clear_underflow(hubp);
518	}
519}
520
521void dcn10_clear_status_bits(struct dc *dc, unsigned int mask)
522{
523	/*
524	 *  Mask Format
525	 *  Bit 0 - 31: Status bit to clear
526	 *
527	 *  Mask = 0x0 means clear all status bits
528	 */
529	const unsigned int DC_HW_STATE_MASK_HUBP_UNDERFLOW	= 0x1;
530	const unsigned int DC_HW_STATE_MASK_OTPC_UNDERFLOW	= 0x2;
531
532	if (mask == 0x0)
533		mask = 0xFFFFFFFF;
534
535	if (mask & DC_HW_STATE_MASK_HUBP_UNDERFLOW)
536		dcn10_clear_hubp_underflow(dc);
537
538	if (mask & DC_HW_STATE_MASK_OTPC_UNDERFLOW)
539		dcn10_clear_otpc_underflow(dc);
540}
541
542void dcn10_get_hw_state(struct dc *dc, char *pBuf, unsigned int bufSize, unsigned int mask)
543{
544	/*
545	 *  Mask Format
546	 *  Bit 0 - 15: Hardware block mask
547	 *  Bit 15: 1 = Invariant Only, 0 = All
548	 */
549	const unsigned int DC_HW_STATE_MASK_HUBBUB			= 0x1;
550	const unsigned int DC_HW_STATE_MASK_HUBP			= 0x2;
551	const unsigned int DC_HW_STATE_MASK_RQ				= 0x4;
552	const unsigned int DC_HW_STATE_MASK_DLG				= 0x8;
553	const unsigned int DC_HW_STATE_MASK_TTU				= 0x10;
554	const unsigned int DC_HW_STATE_MASK_CM				= 0x20;
555	const unsigned int DC_HW_STATE_MASK_MPCC			= 0x40;
556	const unsigned int DC_HW_STATE_MASK_OTG				= 0x80;
557	const unsigned int DC_HW_STATE_MASK_CLOCKS			= 0x100;
558	const unsigned int DC_HW_STATE_INVAR_ONLY			= 0x8000;
559
560	unsigned int chars_printed = 0;
561	unsigned int remaining_buf_size = bufSize;
562
563	if (mask == 0x0)
564		mask = 0xFFFF; // Default, capture all, invariant only
565
566	if ((mask & DC_HW_STATE_MASK_HUBBUB) && remaining_buf_size > 0) {
567		chars_printed = dcn10_get_hubbub_state(dc, pBuf, remaining_buf_size);
568		pBuf += chars_printed;
569		remaining_buf_size -= chars_printed;
570	}
571
572	if ((mask & DC_HW_STATE_MASK_HUBP) && remaining_buf_size > 0) {
573		chars_printed = dcn10_get_hubp_states(dc, pBuf, remaining_buf_size, mask & DC_HW_STATE_INVAR_ONLY);
574		pBuf += chars_printed;
575		remaining_buf_size -= chars_printed;
576	}
577
578	if ((mask & DC_HW_STATE_MASK_RQ) && remaining_buf_size > 0) {
579		chars_printed = dcn10_get_rq_states(dc, pBuf, remaining_buf_size);
580		pBuf += chars_printed;
581		remaining_buf_size -= chars_printed;
582	}
583
584	if ((mask & DC_HW_STATE_MASK_DLG) && remaining_buf_size > 0) {
585		chars_printed = dcn10_get_dlg_states(dc, pBuf, remaining_buf_size);
586		pBuf += chars_printed;
587		remaining_buf_size -= chars_printed;
588	}
589
590	if ((mask & DC_HW_STATE_MASK_TTU) && remaining_buf_size > 0) {
591		chars_printed = dcn10_get_ttu_states(dc, pBuf, remaining_buf_size);
592		pBuf += chars_printed;
593		remaining_buf_size -= chars_printed;
594	}
595
596	if ((mask & DC_HW_STATE_MASK_CM) && remaining_buf_size > 0) {
597		chars_printed = dcn10_get_cm_states(dc, pBuf, remaining_buf_size);
598		pBuf += chars_printed;
599		remaining_buf_size -= chars_printed;
600	}
601
602	if ((mask & DC_HW_STATE_MASK_MPCC) && remaining_buf_size > 0) {
603		chars_printed = dcn10_get_mpcc_states(dc, pBuf, remaining_buf_size);
604		pBuf += chars_printed;
605		remaining_buf_size -= chars_printed;
606	}
607
608	if ((mask & DC_HW_STATE_MASK_OTG) && remaining_buf_size > 0) {
609		chars_printed = dcn10_get_otg_states(dc, pBuf, remaining_buf_size);
610		pBuf += chars_printed;
611		remaining_buf_size -= chars_printed;
612	}
613
614	if ((mask & DC_HW_STATE_MASK_CLOCKS) && remaining_buf_size > 0) {
615		chars_printed = dcn10_get_clock_states(dc, pBuf, remaining_buf_size);
616		pBuf += chars_printed;
617		remaining_buf_size -= chars_printed;
618	}
619}
620