File Index
Files and directories
Sign in
FILE

dpu_hw_intf.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  4 * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  5 */
  6
  7#include "dpu_hwio.h"
  8#include "dpu_hw_catalog.h"
  9#include "dpu_hw_intf.h"
 10#include "dpu_kms.h"
 11#include "dpu_trace.h"
 12
 13#include <linux/iopoll.h>
 14
 15#include <drm/drm_managed.h>
 16
 17#define INTF_TIMING_ENGINE_EN           0x000
 18#define INTF_CONFIG                     0x004
 19#define INTF_HSYNC_CTL                  0x008
 20#define INTF_VSYNC_PERIOD_F0            0x00C
 21#define INTF_VSYNC_PERIOD_F1            0x010
 22#define INTF_VSYNC_PULSE_WIDTH_F0       0x014
 23#define INTF_VSYNC_PULSE_WIDTH_F1       0x018
 24#define INTF_DISPLAY_V_START_F0         0x01C
 25#define INTF_DISPLAY_V_START_F1         0x020
 26#define INTF_DISPLAY_V_END_F0           0x024
 27#define INTF_DISPLAY_V_END_F1           0x028
 28#define INTF_ACTIVE_V_START_F0          0x02C
 29#define INTF_ACTIVE_V_START_F1          0x030
 30#define INTF_ACTIVE_V_END_F0            0x034
 31#define INTF_ACTIVE_V_END_F1            0x038
 32#define INTF_DISPLAY_HCTL               0x03C
 33#define INTF_ACTIVE_HCTL                0x040
 34#define INTF_BORDER_COLOR               0x044
 35#define INTF_UNDERFLOW_COLOR            0x048
 36#define INTF_HSYNC_SKEW                 0x04C
 37#define INTF_POLARITY_CTL               0x050
 38#define INTF_TEST_CTL                   0x054
 39#define INTF_TP_COLOR0                  0x058
 40#define INTF_TP_COLOR1                  0x05C
 41#define INTF_CONFIG2                    0x060
 42#define INTF_DISPLAY_DATA_HCTL          0x064
 43#define INTF_ACTIVE_DATA_HCTL           0x068
 44
 45#define INTF_DSI_CMD_MODE_TRIGGER_EN    0x084
 46#define INTF_PANEL_FORMAT               0x090
 47
 48#define INTF_FRAME_LINE_COUNT_EN        0x0A8
 49#define INTF_FRAME_COUNT                0x0AC
 50#define INTF_LINE_COUNT                 0x0B0
 51
 52#define INTF_DEFLICKER_CONFIG           0x0F0
 53#define INTF_DEFLICKER_STRNG_COEFF      0x0F4
 54#define INTF_DEFLICKER_WEAK_COEFF       0x0F8
 55
 56#define INTF_TPG_ENABLE                 0x100
 57#define INTF_TPG_MAIN_CONTROL           0x104
 58#define INTF_TPG_VIDEO_CONFIG           0x108
 59#define INTF_TPG_COMPONENT_LIMITS       0x10C
 60#define INTF_TPG_RECTANGLE              0x110
 61#define INTF_TPG_INITIAL_VALUE          0x114
 62#define INTF_TPG_BLK_WHITE_PATTERN_FRAMES 0x118
 63#define INTF_TPG_RGB_MAPPING            0x11C
 64#define INTF_PROG_FETCH_START           0x170
 65#define INTF_PROG_ROT_START             0x174
 66
 67#define INTF_MISR_CTRL                  0x180
 68#define INTF_MISR_SIGNATURE             0x184
 69
 70#define INTF_WD_TIMER_0_CTL		0x230
 71#define INTF_WD_TIMER_0_CTL2		0x234
 72#define INTF_WD_TIMER_0_LOAD_VALUE	0x238
 73
 74#define INTF_MUX                        0x25C
 75#define INTF_STATUS                     0x26C
 76#define INTF_AVR_CONTROL                0x270
 77#define INTF_AVR_MODE                   0x274
 78#define INTF_AVR_TRIGGER                0x278
 79#define INTF_AVR_VTOTAL                 0x27C
 80#define INTF_TEAR_MDP_VSYNC_SEL         0x280
 81#define INTF_TEAR_TEAR_CHECK_EN         0x284
 82#define INTF_TEAR_SYNC_CONFIG_VSYNC     0x288
 83#define INTF_TEAR_SYNC_CONFIG_HEIGHT    0x28C
 84#define INTF_TEAR_SYNC_WRCOUNT          0x290
 85#define INTF_TEAR_VSYNC_INIT_VAL        0x294
 86#define INTF_TEAR_INT_COUNT_VAL         0x298
 87#define INTF_TEAR_SYNC_THRESH           0x29C
 88#define INTF_TEAR_START_POS             0x2A0
 89#define INTF_TEAR_RD_PTR_IRQ            0x2A4
 90#define INTF_TEAR_WR_PTR_IRQ            0x2A8
 91#define INTF_TEAR_OUT_LINE_COUNT        0x2AC
 92#define INTF_TEAR_LINE_COUNT            0x2B0
 93#define INTF_TEAR_AUTOREFRESH_CONFIG    0x2B4
 94
 95#define INTF_CFG_ACTIVE_H_EN	BIT(29)
 96#define INTF_CFG_ACTIVE_V_EN	BIT(30)
 97
 98#define INTF_CFG2_DATABUS_WIDEN	BIT(0)
 99#define INTF_CFG2_DATA_HCTL_EN	BIT(4)
100#define INTF_CFG2_DCE_DATA_COMPRESS     BIT(12)
101
102
103static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *intf,
104		const struct dpu_hw_intf_timing_params *p,
105		const struct msm_format *fmt)
106{
107	struct dpu_hw_blk_reg_map *c = &intf->hw;
108	u32 hsync_period, vsync_period;
109	u32 display_v_start, display_v_end;
110	u32 hsync_start_x, hsync_end_x;
111	u32 hsync_data_start_x, hsync_data_end_x;
112	u32 active_h_start, active_h_end;
113	u32 active_v_start, active_v_end;
114	u32 active_hctl, display_hctl, hsync_ctl;
115	u32 polarity_ctl, den_polarity;
116	u32 panel_format;
117	u32 intf_cfg, intf_cfg2 = 0;
118	u32 display_data_hctl = 0, active_data_hctl = 0;
119	u32 data_width;
120	bool dp_intf = false;
121
122	/* read interface_cfg */
123	intf_cfg = DPU_REG_READ(c, INTF_CONFIG);
124
125	if (intf->cap->type == INTF_DP)
126		dp_intf = true;
127
128	hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width +
129	p->h_front_porch;
130	vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height +
131	p->v_front_porch;
132
133	display_v_start = ((p->vsync_pulse_width + p->v_back_porch) *
134	hsync_period) + p->hsync_skew;
135	display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) +
136	p->hsync_skew - 1;
137
138	hsync_start_x = p->h_back_porch + p->hsync_pulse_width;
139	hsync_end_x = hsync_period - p->h_front_porch - 1;
140
141	if (p->width != p->xres) { /* border fill added */
142		active_h_start = hsync_start_x;
143		active_h_end = active_h_start + p->xres - 1;
144	} else {
145		active_h_start = 0;
146		active_h_end = 0;
147	}
148
149	if (p->height != p->yres) { /* border fill added */
150		active_v_start = display_v_start;
151		active_v_end = active_v_start + (p->yres * hsync_period) - 1;
152	} else {
153		active_v_start = 0;
154		active_v_end = 0;
155	}
156
157	if (active_h_end) {
158		active_hctl = (active_h_end << 16) | active_h_start;
159		intf_cfg |= INTF_CFG_ACTIVE_H_EN;
160	} else {
161		active_hctl = 0;
162	}
163
164	if (active_v_end)
165		intf_cfg |= INTF_CFG_ACTIVE_V_EN;
166
167	hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
168	display_hctl = (hsync_end_x << 16) | hsync_start_x;
169
170	if (p->wide_bus_en)
171		intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN;
172
173	data_width = p->width;
174
175	/*
176	 * If widebus is enabled, data is valid for only half the active window
177	 * since the data rate is doubled in this mode. But for the compression
178	 * mode in DP case, the p->width is already adjusted in
179	 * drm_mode_to_intf_timing_params()
180	 */
181	if (p->wide_bus_en && !dp_intf)
182		data_width = p->width >> 1;
183
184	/* TODO: handle DSC+DP case, we only handle DSC+DSI case so far */
185	if (p->compression_en && !dp_intf &&
186	    intf->mdss_ver->core_major_ver >= 7)
187		intf_cfg2 |= INTF_CFG2_DCE_DATA_COMPRESS;
188
189	hsync_data_start_x = hsync_start_x;
190	hsync_data_end_x =  hsync_start_x + data_width - 1;
191
192	display_data_hctl = (hsync_data_end_x << 16) | hsync_data_start_x;
193
194	if (dp_intf) {
195		/* DP timing adjustment */
196		display_v_start += p->hsync_pulse_width + p->h_back_porch;
197		display_v_end   -= p->h_front_porch;
198
199		active_h_start = hsync_start_x;
200		active_h_end = active_h_start + p->xres - 1;
201		active_v_start = display_v_start;
202		active_v_end = active_v_start + (p->yres * hsync_period) - 1;
203
204		active_hctl = (active_h_end << 16) | active_h_start;
205		display_hctl = active_hctl;
206
207		intf_cfg |= INTF_CFG_ACTIVE_H_EN | INTF_CFG_ACTIVE_V_EN;
208	}
209
210	den_polarity = 0;
211	polarity_ctl = (den_polarity << 2) | /*  DEN Polarity  */
212		(p->vsync_polarity << 1) | /* VSYNC Polarity */
213		(p->hsync_polarity << 0);  /* HSYNC Polarity */
214
215	if (!MSM_FORMAT_IS_YUV(fmt))
216		panel_format = (fmt->bpc_g_y |
217				(fmt->bpc_b_cb << 2) |
218				(fmt->bpc_r_cr << 4) |
219				(0x21 << 8));
220	else
221		/* Interface treats all the pixel data in RGB888 format */
222		panel_format = (BPC8 |
223				(BPC8 << 2) |
224				(BPC8 << 4) |
225				(0x21 << 8));
226
227	DPU_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl);
228	DPU_REG_WRITE(c, INTF_VSYNC_PERIOD_F0, vsync_period * hsync_period);
229	DPU_REG_WRITE(c, INTF_VSYNC_PULSE_WIDTH_F0,
230			p->vsync_pulse_width * hsync_period);
231	DPU_REG_WRITE(c, INTF_DISPLAY_HCTL, display_hctl);
232	DPU_REG_WRITE(c, INTF_DISPLAY_V_START_F0, display_v_start);
233	DPU_REG_WRITE(c, INTF_DISPLAY_V_END_F0, display_v_end);
234	DPU_REG_WRITE(c, INTF_ACTIVE_HCTL,  active_hctl);
235	DPU_REG_WRITE(c, INTF_ACTIVE_V_START_F0, active_v_start);
236	DPU_REG_WRITE(c, INTF_ACTIVE_V_END_F0, active_v_end);
237	DPU_REG_WRITE(c, INTF_BORDER_COLOR, p->border_clr);
238	DPU_REG_WRITE(c, INTF_UNDERFLOW_COLOR, p->underflow_clr);
239	DPU_REG_WRITE(c, INTF_HSYNC_SKEW, p->hsync_skew);
240	DPU_REG_WRITE(c, INTF_POLARITY_CTL, polarity_ctl);
241	DPU_REG_WRITE(c, INTF_FRAME_LINE_COUNT_EN, 0x3);
242	DPU_REG_WRITE(c, INTF_CONFIG, intf_cfg);
243	DPU_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format);
244	if (intf->mdss_ver->core_major_ver >= 5) {
245		/*
246		 * DATA_HCTL_EN controls data timing which can be different from
247		 * video timing. It is recommended to enable it for all cases, except
248		 * if compression is enabled in 1 pixel per clock mode
249		 */
250		if (!(p->compression_en && !p->wide_bus_en))
251			intf_cfg2 |= INTF_CFG2_DATA_HCTL_EN;
252
253		DPU_REG_WRITE(c, INTF_CONFIG2, intf_cfg2);
254		DPU_REG_WRITE(c, INTF_DISPLAY_DATA_HCTL, display_data_hctl);
255		DPU_REG_WRITE(c, INTF_ACTIVE_DATA_HCTL, active_data_hctl);
256	}
257}
258
259static void dpu_hw_intf_enable_timing_engine(
260		struct dpu_hw_intf *intf,
261		u8 enable)
262{
263	struct dpu_hw_blk_reg_map *c = &intf->hw;
264	/* Note: Display interface select is handled in top block hw layer */
265	DPU_REG_WRITE(c, INTF_TIMING_ENGINE_EN, enable != 0);
266}
267
268static void dpu_hw_intf_setup_prg_fetch(
269		struct dpu_hw_intf *intf,
270		const struct dpu_hw_intf_prog_fetch *fetch)
271{
272	struct dpu_hw_blk_reg_map *c = &intf->hw;
273	int fetch_enable;
274
275	/*
276	 * Fetch should always be outside the active lines. If the fetching
277	 * is programmed within active region, hardware behavior is unknown.
278	 */
279
280	fetch_enable = DPU_REG_READ(c, INTF_CONFIG);
281	if (fetch->enable) {
282		fetch_enable |= BIT(31);
283		DPU_REG_WRITE(c, INTF_PROG_FETCH_START,
284				fetch->fetch_start);
285	} else {
286		fetch_enable &= ~BIT(31);
287	}
288
289	DPU_REG_WRITE(c, INTF_CONFIG, fetch_enable);
290}
291
292static void dpu_hw_intf_bind_pingpong_blk(
293		struct dpu_hw_intf *intf,
294		const enum dpu_pingpong pp)
295{
296	struct dpu_hw_blk_reg_map *c = &intf->hw;
297	u32 mux_cfg;
298
299	mux_cfg = DPU_REG_READ(c, INTF_MUX);
300	mux_cfg &= ~0xf;
301
302	if (pp)
303		mux_cfg |= (pp - PINGPONG_0) & 0x7;
304	else
305		mux_cfg |= 0xf;
306
307	DPU_REG_WRITE(c, INTF_MUX, mux_cfg);
308}
309
310static void dpu_hw_intf_get_status(
311		struct dpu_hw_intf *intf,
312		struct dpu_hw_intf_status *s)
313{
314	struct dpu_hw_blk_reg_map *c = &intf->hw;
315
316	if (intf->mdss_ver->core_major_ver >= 5)
317		s->is_en = DPU_REG_READ(c, INTF_STATUS) & BIT(0);
318	else
319		s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
320
321	s->is_prog_fetch_en = !!(DPU_REG_READ(c, INTF_CONFIG) & BIT(31));
322	if (s->is_en) {
323		s->frame_count = DPU_REG_READ(c, INTF_FRAME_COUNT);
324		s->line_count = DPU_REG_READ(c, INTF_LINE_COUNT);
325	} else {
326		s->line_count = 0;
327		s->frame_count = 0;
328	}
329}
330
331static u32 dpu_hw_intf_get_line_count(struct dpu_hw_intf *intf)
332{
333	struct dpu_hw_blk_reg_map *c;
334
335	if (!intf)
336		return 0;
337
338	c = &intf->hw;
339
340	return DPU_REG_READ(c, INTF_LINE_COUNT);
341}
342
343static void dpu_hw_intf_setup_misr(struct dpu_hw_intf *intf)
344{
345	dpu_hw_setup_misr(&intf->hw, INTF_MISR_CTRL, 0x1);
346}
347
348static int dpu_hw_intf_collect_misr(struct dpu_hw_intf *intf, u32 *misr_value)
349{
350	return dpu_hw_collect_misr(&intf->hw, INTF_MISR_CTRL, INTF_MISR_SIGNATURE, misr_value);
351}
352
353static int dpu_hw_intf_enable_te(struct dpu_hw_intf *intf,
354		struct dpu_hw_tear_check *te)
355{
356	struct dpu_hw_blk_reg_map *c;
357	int cfg;
358
359	if (!intf)
360		return -EINVAL;
361
362	c = &intf->hw;
363
364	cfg = BIT(19); /* VSYNC_COUNTER_EN */
365	if (te->hw_vsync_mode)
366		cfg |= BIT(20);
367
368	cfg |= te->vsync_count;
369
370	DPU_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_VSYNC, cfg);
371	DPU_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_HEIGHT, te->sync_cfg_height);
372	DPU_REG_WRITE(c, INTF_TEAR_VSYNC_INIT_VAL, te->vsync_init_val);
373	DPU_REG_WRITE(c, INTF_TEAR_RD_PTR_IRQ, te->rd_ptr_irq);
374	DPU_REG_WRITE(c, INTF_TEAR_START_POS, te->start_pos);
375	DPU_REG_WRITE(c, INTF_TEAR_SYNC_THRESH,
376			((te->sync_threshold_continue << 16) |
377			 te->sync_threshold_start));
378	DPU_REG_WRITE(c, INTF_TEAR_SYNC_WRCOUNT,
379			(te->start_pos + te->sync_threshold_start + 1));
380
381	DPU_REG_WRITE(c, INTF_TEAR_TEAR_CHECK_EN, 1);
382
383	return 0;
384}
385
386static void dpu_hw_intf_setup_autorefresh_config(struct dpu_hw_intf *intf,
387		u32 frame_count, bool enable)
388{
389	struct dpu_hw_blk_reg_map *c;
390	u32 refresh_cfg;
391
392	c = &intf->hw;
393	refresh_cfg = DPU_REG_READ(c, INTF_TEAR_AUTOREFRESH_CONFIG);
394	if (enable)
395		refresh_cfg = BIT(31) | frame_count;
396	else
397		refresh_cfg &= ~BIT(31);
398
399	DPU_REG_WRITE(c, INTF_TEAR_AUTOREFRESH_CONFIG, refresh_cfg);
400}
401
402/*
403 * dpu_hw_intf_get_autorefresh_config - Get autorefresh config from HW
404 * @intf:        DPU intf structure
405 * @frame_count: Used to return the current frame count from hw
406 *
407 * Returns: True if autorefresh enabled, false if disabled.
408 */
409static bool dpu_hw_intf_get_autorefresh_config(struct dpu_hw_intf *intf,
410		u32 *frame_count)
411{
412	u32 val = DPU_REG_READ(&intf->hw, INTF_TEAR_AUTOREFRESH_CONFIG);
413
414	if (frame_count != NULL)
415		*frame_count = val & 0xffff;
416	return !!((val & BIT(31)) >> 31);
417}
418
419static int dpu_hw_intf_disable_te(struct dpu_hw_intf *intf)
420{
421	struct dpu_hw_blk_reg_map *c;
422
423	if (!intf)
424		return -EINVAL;
425
426	c = &intf->hw;
427	DPU_REG_WRITE(c, INTF_TEAR_TEAR_CHECK_EN, 0);
428	return 0;
429}
430
431static int dpu_hw_intf_connect_external_te(struct dpu_hw_intf *intf,
432		bool enable_external_te)
433{
434	struct dpu_hw_blk_reg_map *c = &intf->hw;
435	u32 cfg;
436	int orig;
437
438	if (!intf)
439		return -EINVAL;
440
441	c = &intf->hw;
442	cfg = DPU_REG_READ(c, INTF_TEAR_SYNC_CONFIG_VSYNC);
443	orig = (bool)(cfg & BIT(20));
444	if (enable_external_te)
445		cfg |= BIT(20);
446	else
447		cfg &= ~BIT(20);
448	DPU_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_VSYNC, cfg);
449	trace_dpu_intf_connect_ext_te(intf->idx - INTF_0, cfg);
450
451	return orig;
452}
453
454static int dpu_hw_intf_get_vsync_info(struct dpu_hw_intf *intf,
455		struct dpu_hw_pp_vsync_info *info)
456{
457	struct dpu_hw_blk_reg_map *c = &intf->hw;
458	u32 val;
459
460	if (!intf || !info)
461		return -EINVAL;
462
463	c = &intf->hw;
464
465	val = DPU_REG_READ(c, INTF_TEAR_VSYNC_INIT_VAL);
466	info->rd_ptr_init_val = val & 0xffff;
467
468	val = DPU_REG_READ(c, INTF_TEAR_INT_COUNT_VAL);
469	info->rd_ptr_frame_count = (val & 0xffff0000) >> 16;
470	info->rd_ptr_line_count = val & 0xffff;
471
472	val = DPU_REG_READ(c, INTF_TEAR_LINE_COUNT);
473	info->wr_ptr_line_count = val & 0xffff;
474
475	val = DPU_REG_READ(c, INTF_FRAME_COUNT);
476	info->intf_frame_count = val;
477
478	return 0;
479}
480
481static void dpu_hw_intf_vsync_sel(struct dpu_hw_intf *intf,
482				  struct dpu_vsync_source_cfg *cfg)
483{
484	struct dpu_hw_blk_reg_map *c;
485
486	if (!intf)
487		return;
488
489	c = &intf->hw;
490
491	DPU_REG_WRITE(c, INTF_TEAR_MDP_VSYNC_SEL, (cfg->vsync_source & 0xf));
492}
493
494static void dpu_hw_intf_vsync_sel_v8(struct dpu_hw_intf *intf,
495				  struct dpu_vsync_source_cfg *cfg)
496{
497	struct dpu_hw_blk_reg_map *c;
498
499	if (!intf)
500		return;
501
502	c = &intf->hw;
503
504	if (cfg->vsync_source >= DPU_VSYNC_SOURCE_WD_TIMER_4 &&
505	    cfg->vsync_source <= DPU_VSYNC_SOURCE_WD_TIMER_1) {
506		pr_warn_once("DPU 8.x supports only GPIOs and timer0 as TE sources\n");
507		return;
508	}
509
510	if (cfg->vsync_source == DPU_VSYNC_SOURCE_WD_TIMER_0) {
511		u32 reg;
512
513		DPU_REG_WRITE(c, INTF_WD_TIMER_0_LOAD_VALUE,
514			      CALCULATE_WD_LOAD_VALUE(cfg->frame_rate));
515
516		DPU_REG_WRITE(c, INTF_WD_TIMER_0_CTL, BIT(0)); /* clear timer */
517
518		reg  = BIT(8);		/* enable heartbeat timer */
519		reg |= BIT(0);		/* enable WD timer */
520		reg |= BIT(1);		/* select default 16 clock ticks */
521		DPU_REG_WRITE(c, INTF_WD_TIMER_0_CTL2, reg);
522
523		/* make sure that timers are enabled/disabled for vsync state */
524		wmb();
525	}
526
527	dpu_hw_intf_vsync_sel(intf, cfg);
528}
529
530static void dpu_hw_intf_disable_autorefresh(struct dpu_hw_intf *intf,
531					    uint32_t encoder_id, u16 vdisplay)
532{
533	struct dpu_hw_pp_vsync_info info;
534	int trial = 0;
535
536	/* If autorefresh is already disabled, we have nothing to do */
537	if (!dpu_hw_intf_get_autorefresh_config(intf, NULL))
538		return;
539
540	/*
541	 * If autorefresh is enabled, disable it and make sure it is safe to
542	 * proceed with current frame commit/push. Sequence followed is,
543	 * 1. Disable TE
544	 * 2. Disable autorefresh config
545	 * 4. Poll for frame transfer ongoing to be false
546	 * 5. Enable TE back
547	 */
548
549	dpu_hw_intf_connect_external_te(intf, false);
550	dpu_hw_intf_setup_autorefresh_config(intf, 0, false);
551
552	do {
553		udelay(DPU_ENC_MAX_POLL_TIMEOUT_US);
554		if ((trial * DPU_ENC_MAX_POLL_TIMEOUT_US)
555				> (KICKOFF_TIMEOUT_MS * USEC_PER_MSEC)) {
556			DPU_ERROR("enc%d intf%d disable autorefresh failed\n",
557				  encoder_id, intf->idx - INTF_0);
558			break;
559		}
560
561		trial++;
562
563		dpu_hw_intf_get_vsync_info(intf, &info);
564	} while (info.wr_ptr_line_count > 0 &&
565		 info.wr_ptr_line_count < vdisplay);
566
567	dpu_hw_intf_connect_external_te(intf, true);
568
569	DPU_DEBUG("enc%d intf%d disabled autorefresh\n",
570		  encoder_id, intf->idx - INTF_0);
571
572}
573
574static void dpu_hw_intf_program_intf_cmd_cfg(struct dpu_hw_intf *intf,
575					     struct dpu_hw_intf_cmd_mode_cfg *cmd_mode_cfg)
576{
577	u32 intf_cfg2 = DPU_REG_READ(&intf->hw, INTF_CONFIG2);
578
579	if (cmd_mode_cfg->data_compress)
580		intf_cfg2 |= INTF_CFG2_DCE_DATA_COMPRESS;
581
582	if (cmd_mode_cfg->wide_bus_en)
583		intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN;
584
585	DPU_REG_WRITE(&intf->hw, INTF_CONFIG2, intf_cfg2);
586}
587
588/**
589 * dpu_hw_intf_init() - Initializes the INTF driver for the passed
590 * interface catalog entry.
591 * @dev:  Corresponding device for devres management
592 * @cfg:  interface catalog entry for which driver object is required
593 * @addr: mapped register io address of MDP
594 * @mdss_rev: dpu core's major and minor versions
595 */
596struct dpu_hw_intf *dpu_hw_intf_init(struct drm_device *dev,
597				     const struct dpu_intf_cfg *cfg,
598				     void __iomem *addr,
599				     const struct dpu_mdss_version *mdss_rev)
600{
601	struct dpu_hw_intf *c;
602
603	if (cfg->type == INTF_NONE) {
604		DPU_DEBUG("Skip intf %d with type NONE\n", cfg->id - INTF_0);
605		return NULL;
606	}
607
608	c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL);
609	if (!c)
610		return ERR_PTR(-ENOMEM);
611
612	c->hw.blk_addr = addr + cfg->base;
613	c->hw.log_mask = DPU_DBG_MASK_INTF;
614
615	/*
616	 * Assign ops
617	 */
618	c->idx = cfg->id;
619	c->cap = cfg;
620
621	c->mdss_ver = mdss_rev;
622
623	c->ops.setup_timing_gen = dpu_hw_intf_setup_timing_engine;
624	c->ops.setup_prg_fetch  = dpu_hw_intf_setup_prg_fetch;
625	c->ops.get_status = dpu_hw_intf_get_status;
626	c->ops.enable_timing = dpu_hw_intf_enable_timing_engine;
627	c->ops.get_line_count = dpu_hw_intf_get_line_count;
628	c->ops.setup_misr = dpu_hw_intf_setup_misr;
629	c->ops.collect_misr = dpu_hw_intf_collect_misr;
630
631	if (mdss_rev->core_major_ver >= 5)
632		c->ops.bind_pingpong_blk = dpu_hw_intf_bind_pingpong_blk;
633
634	/* INTF TE is only for DSI interfaces */
635	if (mdss_rev->core_major_ver >= 5 && cfg->type == INTF_DSI) {
636		WARN_ON(!cfg->intr_tear_rd_ptr);
637
638		c->ops.enable_tearcheck = dpu_hw_intf_enable_te;
639		c->ops.disable_tearcheck = dpu_hw_intf_disable_te;
640		c->ops.connect_external_te = dpu_hw_intf_connect_external_te;
641		if (mdss_rev->core_major_ver >= 8)
642			c->ops.vsync_sel = dpu_hw_intf_vsync_sel_v8;
643		else
644			c->ops.vsync_sel = dpu_hw_intf_vsync_sel;
645		c->ops.disable_autorefresh = dpu_hw_intf_disable_autorefresh;
646	}
647
648	/* Technically, INTF_CONFIG2 is present for DPU 5.0+, but
649	 * we can configure it for DPU 7.0+ since the wide bus and DSC flags
650	 * would not be set for DPU < 7.0 anyways
651	 */
652	if (mdss_rev->core_major_ver >= 7)
653		c->ops.program_intf_cmd_cfg = dpu_hw_intf_program_intf_cmd_cfg;
654
655	return c;
656}
~/ Read-only file preview.