xref: /linux/drivers/gpu/drm/i915/gvt/display.c (revision d1a513be1f0a25f094e1577d059b9aebaa279bb2)
104d348aeSZhi Wang /*
204d348aeSZhi Wang  * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
304d348aeSZhi Wang  *
404d348aeSZhi Wang  * Permission is hereby granted, free of charge, to any person obtaining a
504d348aeSZhi Wang  * copy of this software and associated documentation files (the "Software"),
604d348aeSZhi Wang  * to deal in the Software without restriction, including without limitation
704d348aeSZhi Wang  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
804d348aeSZhi Wang  * and/or sell copies of the Software, and to permit persons to whom the
904d348aeSZhi Wang  * Software is furnished to do so, subject to the following conditions:
1004d348aeSZhi Wang  *
1104d348aeSZhi Wang  * The above copyright notice and this permission notice (including the next
1204d348aeSZhi Wang  * paragraph) shall be included in all copies or substantial portions of the
1304d348aeSZhi Wang  * Software.
1404d348aeSZhi Wang  *
1504d348aeSZhi Wang  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1604d348aeSZhi Wang  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1704d348aeSZhi Wang  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1804d348aeSZhi Wang  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1904d348aeSZhi Wang  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2004d348aeSZhi Wang  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2104d348aeSZhi Wang  * SOFTWARE.
2204d348aeSZhi Wang  *
2304d348aeSZhi Wang  * Authors:
2404d348aeSZhi Wang  *    Ke Yu
2504d348aeSZhi Wang  *    Zhiyuan Lv <zhiyuan.lv@intel.com>
2604d348aeSZhi Wang  *
2704d348aeSZhi Wang  * Contributors:
2804d348aeSZhi Wang  *    Terrence Xu <terrence.xu@intel.com>
2904d348aeSZhi Wang  *    Changbin Du <changbin.du@intel.com>
3004d348aeSZhi Wang  *    Bing Niu <bing.niu@intel.com>
3104d348aeSZhi Wang  *    Zhi Wang <zhi.a.wang@intel.com>
3204d348aeSZhi Wang  *
3304d348aeSZhi Wang  */
3404d348aeSZhi Wang 
3504d348aeSZhi Wang #include "i915_drv.h"
36feddf6e8SZhenyu Wang #include "gvt.h"
3704d348aeSZhi Wang 
3804d348aeSZhi Wang static int get_edp_pipe(struct intel_vgpu *vgpu)
3904d348aeSZhi Wang {
4004d348aeSZhi Wang 	u32 data = vgpu_vreg(vgpu, _TRANS_DDI_FUNC_CTL_EDP);
4104d348aeSZhi Wang 	int pipe = -1;
4204d348aeSZhi Wang 
4304d348aeSZhi Wang 	switch (data & TRANS_DDI_EDP_INPUT_MASK) {
4404d348aeSZhi Wang 	case TRANS_DDI_EDP_INPUT_A_ON:
4504d348aeSZhi Wang 	case TRANS_DDI_EDP_INPUT_A_ONOFF:
4604d348aeSZhi Wang 		pipe = PIPE_A;
4704d348aeSZhi Wang 		break;
4804d348aeSZhi Wang 	case TRANS_DDI_EDP_INPUT_B_ONOFF:
4904d348aeSZhi Wang 		pipe = PIPE_B;
5004d348aeSZhi Wang 		break;
5104d348aeSZhi Wang 	case TRANS_DDI_EDP_INPUT_C_ONOFF:
5204d348aeSZhi Wang 		pipe = PIPE_C;
5304d348aeSZhi Wang 		break;
5404d348aeSZhi Wang 	}
5504d348aeSZhi Wang 	return pipe;
5604d348aeSZhi Wang }
5704d348aeSZhi Wang 
5804d348aeSZhi Wang static int edp_pipe_is_enabled(struct intel_vgpu *vgpu)
5904d348aeSZhi Wang {
6004d348aeSZhi Wang 	struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
6104d348aeSZhi Wang 
6204d348aeSZhi Wang 	if (!(vgpu_vreg(vgpu, PIPECONF(_PIPE_EDP)) & PIPECONF_ENABLE))
6304d348aeSZhi Wang 		return 0;
6404d348aeSZhi Wang 
6504d348aeSZhi Wang 	if (!(vgpu_vreg(vgpu, _TRANS_DDI_FUNC_CTL_EDP) & TRANS_DDI_FUNC_ENABLE))
6604d348aeSZhi Wang 		return 0;
6704d348aeSZhi Wang 	return 1;
6804d348aeSZhi Wang }
6904d348aeSZhi Wang 
7004d348aeSZhi Wang static int pipe_is_enabled(struct intel_vgpu *vgpu, int pipe)
7104d348aeSZhi Wang {
7204d348aeSZhi Wang 	struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
7304d348aeSZhi Wang 
7404d348aeSZhi Wang 	if (WARN_ON(pipe < PIPE_A || pipe >= I915_MAX_PIPES))
7504d348aeSZhi Wang 		return -EINVAL;
7604d348aeSZhi Wang 
7704d348aeSZhi Wang 	if (vgpu_vreg(vgpu, PIPECONF(pipe)) & PIPECONF_ENABLE)
7804d348aeSZhi Wang 		return 1;
7904d348aeSZhi Wang 
8004d348aeSZhi Wang 	if (edp_pipe_is_enabled(vgpu) &&
8104d348aeSZhi Wang 			get_edp_pipe(vgpu) == pipe)
8204d348aeSZhi Wang 		return 1;
8304d348aeSZhi Wang 	return 0;
8404d348aeSZhi Wang }
8504d348aeSZhi Wang 
86bca5609fSZhenyu Wang static unsigned char virtual_dp_monitor_edid[GVT_EDID_NUM][EDID_SIZE] = {
87bca5609fSZhenyu Wang 	{
88bca5609fSZhenyu Wang /* EDID with 1024x768 as its resolution */
89bca5609fSZhenyu Wang 		/*Header*/
90bca5609fSZhenyu Wang 		0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
91bca5609fSZhenyu Wang 		/* Vendor & Product Identification */
92bca5609fSZhenyu Wang 		0x22, 0xf0, 0x54, 0x29, 0x00, 0x00, 0x00, 0x00, 0x04, 0x17,
93bca5609fSZhenyu Wang 		/* Version & Revision */
94bca5609fSZhenyu Wang 		0x01, 0x04,
95bca5609fSZhenyu Wang 		/* Basic Display Parameters & Features */
96bca5609fSZhenyu Wang 		0xa5, 0x34, 0x20, 0x78, 0x23,
97bca5609fSZhenyu Wang 		/* Color Characteristics */
98bca5609fSZhenyu Wang 		0xfc, 0x81, 0xa4, 0x55, 0x4d, 0x9d, 0x25, 0x12, 0x50, 0x54,
99bca5609fSZhenyu Wang 		/* Established Timings: maximum resolution is 1024x768 */
100bca5609fSZhenyu Wang 		0x21, 0x08, 0x00,
101bca5609fSZhenyu Wang 		/* Standard Timings. All invalid */
102bca5609fSZhenyu Wang 		0x00, 0xc0, 0x00, 0xc0, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00,
103bca5609fSZhenyu Wang 		0x00, 0x40, 0x00, 0x00, 0x00, 0x01,
104bca5609fSZhenyu Wang 		/* 18 Byte Data Blocks 1: invalid */
105bca5609fSZhenyu Wang 		0x00, 0x00, 0x80, 0xa0, 0x70, 0xb0,
106bca5609fSZhenyu Wang 		0x23, 0x40, 0x30, 0x20, 0x36, 0x00, 0x06, 0x44, 0x21, 0x00, 0x00, 0x1a,
107bca5609fSZhenyu Wang 		/* 18 Byte Data Blocks 2: invalid */
108bca5609fSZhenyu Wang 		0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x3c, 0x18, 0x50, 0x11, 0x00, 0x0a,
109bca5609fSZhenyu Wang 		0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
110bca5609fSZhenyu Wang 		/* 18 Byte Data Blocks 3: invalid */
111bca5609fSZhenyu Wang 		0x00, 0x00, 0x00, 0xfc, 0x00, 0x48,
112bca5609fSZhenyu Wang 		0x50, 0x20, 0x5a, 0x52, 0x32, 0x34, 0x34, 0x30, 0x77, 0x0a, 0x20, 0x20,
113bca5609fSZhenyu Wang 		/* 18 Byte Data Blocks 4: invalid */
114bca5609fSZhenyu Wang 		0x00, 0x00, 0x00, 0xff, 0x00, 0x43, 0x4e, 0x34, 0x33, 0x30, 0x34, 0x30,
115bca5609fSZhenyu Wang 		0x44, 0x58, 0x51, 0x0a, 0x20, 0x20,
116bca5609fSZhenyu Wang 		/* Extension Block Count */
117bca5609fSZhenyu Wang 		0x00,
118bca5609fSZhenyu Wang 		/* Checksum */
119bca5609fSZhenyu Wang 		0xef,
120bca5609fSZhenyu Wang 	},
121bca5609fSZhenyu Wang 	{
1222c883136SChuanxiao Dong /* EDID with 1920x1200 as its resolution */
12304d348aeSZhi Wang 		/*Header*/
12404d348aeSZhi Wang 		0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
12504d348aeSZhi Wang 		/* Vendor & Product Identification */
12604d348aeSZhi Wang 		0x22, 0xf0, 0x54, 0x29, 0x00, 0x00, 0x00, 0x00, 0x04, 0x17,
12704d348aeSZhi Wang 		/* Version & Revision */
12804d348aeSZhi Wang 		0x01, 0x04,
12904d348aeSZhi Wang 		/* Basic Display Parameters & Features */
13004d348aeSZhi Wang 		0xa5, 0x34, 0x20, 0x78, 0x23,
13104d348aeSZhi Wang 		/* Color Characteristics */
13204d348aeSZhi Wang 		0xfc, 0x81, 0xa4, 0x55, 0x4d, 0x9d, 0x25, 0x12, 0x50, 0x54,
13304d348aeSZhi Wang 		/* Established Timings: maximum resolution is 1024x768 */
13404d348aeSZhi Wang 		0x21, 0x08, 0x00,
1352c883136SChuanxiao Dong 		/*
1362c883136SChuanxiao Dong 		 * Standard Timings.
1372c883136SChuanxiao Dong 		 * below new resolutions can be supported:
1382c883136SChuanxiao Dong 		 * 1920x1080, 1280x720, 1280x960, 1280x1024,
1392c883136SChuanxiao Dong 		 * 1440x900, 1600x1200, 1680x1050
1402c883136SChuanxiao Dong 		 */
1412c883136SChuanxiao Dong 		0xd1, 0xc0, 0x81, 0xc0, 0x81, 0x40, 0x81, 0x80, 0x95, 0x00,
1422c883136SChuanxiao Dong 		0xa9, 0x40, 0xb3, 0x00, 0x01, 0x01,
1432c883136SChuanxiao Dong 		/* 18 Byte Data Blocks 1: max resolution is 1920x1200 */
1442c883136SChuanxiao Dong 		0x28, 0x3c, 0x80, 0xa0, 0x70, 0xb0,
14504d348aeSZhi Wang 		0x23, 0x40, 0x30, 0x20, 0x36, 0x00, 0x06, 0x44, 0x21, 0x00, 0x00, 0x1a,
14604d348aeSZhi Wang 		/* 18 Byte Data Blocks 2: invalid */
14704d348aeSZhi Wang 		0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x3c, 0x18, 0x50, 0x11, 0x00, 0x0a,
14804d348aeSZhi Wang 		0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
14904d348aeSZhi Wang 		/* 18 Byte Data Blocks 3: invalid */
15004d348aeSZhi Wang 		0x00, 0x00, 0x00, 0xfc, 0x00, 0x48,
15104d348aeSZhi Wang 		0x50, 0x20, 0x5a, 0x52, 0x32, 0x34, 0x34, 0x30, 0x77, 0x0a, 0x20, 0x20,
15204d348aeSZhi Wang 		/* 18 Byte Data Blocks 4: invalid */
15304d348aeSZhi Wang 		0x00, 0x00, 0x00, 0xff, 0x00, 0x43, 0x4e, 0x34, 0x33, 0x30, 0x34, 0x30,
15404d348aeSZhi Wang 		0x44, 0x58, 0x51, 0x0a, 0x20, 0x20,
15504d348aeSZhi Wang 		/* Extension Block Count */
15604d348aeSZhi Wang 		0x00,
15704d348aeSZhi Wang 		/* Checksum */
1582c883136SChuanxiao Dong 		0x45,
159bca5609fSZhenyu Wang 	},
16004d348aeSZhi Wang };
16104d348aeSZhi Wang 
16204d348aeSZhi Wang #define DPCD_HEADER_SIZE        0xb
16304d348aeSZhi Wang 
164999ccb40SDu, Changbin static u8 dpcd_fix_data[DPCD_HEADER_SIZE] = {
16504d348aeSZhi Wang 	0x11, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
16604d348aeSZhi Wang };
16704d348aeSZhi Wang 
16804d348aeSZhi Wang static void emulate_monitor_status_change(struct intel_vgpu *vgpu)
16904d348aeSZhi Wang {
17004d348aeSZhi Wang 	struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
17104d348aeSZhi Wang 	vgpu_vreg(vgpu, SDEISR) &= ~(SDE_PORTB_HOTPLUG_CPT |
17204d348aeSZhi Wang 			SDE_PORTC_HOTPLUG_CPT |
17304d348aeSZhi Wang 			SDE_PORTD_HOTPLUG_CPT);
17404d348aeSZhi Wang 
17504d348aeSZhi Wang 	if (IS_SKYLAKE(dev_priv))
17604d348aeSZhi Wang 		vgpu_vreg(vgpu, SDEISR) &= ~(SDE_PORTA_HOTPLUG_SPT |
17704d348aeSZhi Wang 				SDE_PORTE_HOTPLUG_SPT);
17804d348aeSZhi Wang 
17904d348aeSZhi Wang 	if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B))
18004d348aeSZhi Wang 		vgpu_vreg(vgpu, SDEISR) |= SDE_PORTB_HOTPLUG_CPT;
18104d348aeSZhi Wang 
18204d348aeSZhi Wang 	if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C))
18304d348aeSZhi Wang 		vgpu_vreg(vgpu, SDEISR) |= SDE_PORTC_HOTPLUG_CPT;
18404d348aeSZhi Wang 
18504d348aeSZhi Wang 	if (intel_vgpu_has_monitor_on_port(vgpu, PORT_D))
18604d348aeSZhi Wang 		vgpu_vreg(vgpu, SDEISR) |= SDE_PORTD_HOTPLUG_CPT;
18704d348aeSZhi Wang 
18804d348aeSZhi Wang 	if (IS_SKYLAKE(dev_priv) &&
18904d348aeSZhi Wang 			intel_vgpu_has_monitor_on_port(vgpu, PORT_E)) {
19004d348aeSZhi Wang 		vgpu_vreg(vgpu, SDEISR) |= SDE_PORTE_HOTPLUG_SPT;
19104d348aeSZhi Wang 	}
19204d348aeSZhi Wang 
19304d348aeSZhi Wang 	if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) {
19404d348aeSZhi Wang 		if (IS_BROADWELL(dev_priv))
19504d348aeSZhi Wang 			vgpu_vreg(vgpu, GEN8_DE_PORT_ISR) |=
19604d348aeSZhi Wang 				GEN8_PORT_DP_A_HOTPLUG;
19704d348aeSZhi Wang 		else
19804d348aeSZhi Wang 			vgpu_vreg(vgpu, SDEISR) |= SDE_PORTA_HOTPLUG_SPT;
19904d348aeSZhi Wang 	}
20004d348aeSZhi Wang }
20104d348aeSZhi Wang 
20204d348aeSZhi Wang static void clean_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num)
20304d348aeSZhi Wang {
20404d348aeSZhi Wang 	struct intel_vgpu_port *port = intel_vgpu_port(vgpu, port_num);
20504d348aeSZhi Wang 
20604d348aeSZhi Wang 	kfree(port->edid);
20704d348aeSZhi Wang 	port->edid = NULL;
20804d348aeSZhi Wang 
20904d348aeSZhi Wang 	kfree(port->dpcd);
21004d348aeSZhi Wang 	port->dpcd = NULL;
21104d348aeSZhi Wang }
21204d348aeSZhi Wang 
21304d348aeSZhi Wang static int setup_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num,
214*d1a513beSZhenyu Wang 				    int type, unsigned int resolution)
21504d348aeSZhi Wang {
21604d348aeSZhi Wang 	struct intel_vgpu_port *port = intel_vgpu_port(vgpu, port_num);
21704d348aeSZhi Wang 
218*d1a513beSZhenyu Wang 	if (WARN_ON(resolution >= GVT_EDID_NUM))
219*d1a513beSZhenyu Wang 		return -EINVAL;
220*d1a513beSZhenyu Wang 
22104d348aeSZhi Wang 	port->edid = kzalloc(sizeof(*(port->edid)), GFP_KERNEL);
22204d348aeSZhi Wang 	if (!port->edid)
22304d348aeSZhi Wang 		return -ENOMEM;
22404d348aeSZhi Wang 
22504d348aeSZhi Wang 	port->dpcd = kzalloc(sizeof(*(port->dpcd)), GFP_KERNEL);
22604d348aeSZhi Wang 	if (!port->dpcd) {
22704d348aeSZhi Wang 		kfree(port->edid);
22804d348aeSZhi Wang 		return -ENOMEM;
22904d348aeSZhi Wang 	}
23004d348aeSZhi Wang 
231*d1a513beSZhenyu Wang 	memcpy(port->edid->edid_block, virtual_dp_monitor_edid[resolution],
23204d348aeSZhi Wang 			EDID_SIZE);
23304d348aeSZhi Wang 	port->edid->data_valid = true;
23404d348aeSZhi Wang 
23504d348aeSZhi Wang 	memcpy(port->dpcd->data, dpcd_fix_data, DPCD_HEADER_SIZE);
23604d348aeSZhi Wang 	port->dpcd->data_valid = true;
23704d348aeSZhi Wang 	port->dpcd->data[DPCD_SINK_COUNT] = 0x1;
23804d348aeSZhi Wang 	port->type = type;
23904d348aeSZhi Wang 
24004d348aeSZhi Wang 	emulate_monitor_status_change(vgpu);
24104d348aeSZhi Wang 	return 0;
24204d348aeSZhi Wang }
24304d348aeSZhi Wang 
24404d348aeSZhi Wang /**
24504d348aeSZhi Wang  * intel_gvt_check_vblank_emulation - check if vblank emulation timer should
24604d348aeSZhi Wang  * be turned on/off when a virtual pipe is enabled/disabled.
24704d348aeSZhi Wang  * @gvt: a GVT device
24804d348aeSZhi Wang  *
24904d348aeSZhi Wang  * This function is used to turn on/off vblank timer according to currently
25004d348aeSZhi Wang  * enabled/disabled virtual pipes.
25104d348aeSZhi Wang  *
25204d348aeSZhi Wang  */
25304d348aeSZhi Wang void intel_gvt_check_vblank_emulation(struct intel_gvt *gvt)
25404d348aeSZhi Wang {
25504d348aeSZhi Wang 	struct intel_gvt_irq *irq = &gvt->irq;
25604d348aeSZhi Wang 	struct intel_vgpu *vgpu;
25704d348aeSZhi Wang 	bool have_enabled_pipe = false;
25804d348aeSZhi Wang 	int pipe, id;
25904d348aeSZhi Wang 
26004d348aeSZhi Wang 	if (WARN_ON(!mutex_is_locked(&gvt->lock)))
26104d348aeSZhi Wang 		return;
26204d348aeSZhi Wang 
26304d348aeSZhi Wang 	hrtimer_cancel(&irq->vblank_timer.timer);
26404d348aeSZhi Wang 
26504d348aeSZhi Wang 	for_each_active_vgpu(gvt, vgpu, id) {
26604d348aeSZhi Wang 		for (pipe = 0; pipe < I915_MAX_PIPES; pipe++) {
26704d348aeSZhi Wang 			have_enabled_pipe =
26804d348aeSZhi Wang 				pipe_is_enabled(vgpu, pipe);
26904d348aeSZhi Wang 			if (have_enabled_pipe)
27004d348aeSZhi Wang 				break;
27104d348aeSZhi Wang 		}
27204d348aeSZhi Wang 	}
27304d348aeSZhi Wang 
27404d348aeSZhi Wang 	if (have_enabled_pipe)
27504d348aeSZhi Wang 		hrtimer_start(&irq->vblank_timer.timer,
27604d348aeSZhi Wang 			ktime_add_ns(ktime_get(), irq->vblank_timer.period),
27704d348aeSZhi Wang 			HRTIMER_MODE_ABS);
27804d348aeSZhi Wang }
27904d348aeSZhi Wang 
28004d348aeSZhi Wang static void emulate_vblank_on_pipe(struct intel_vgpu *vgpu, int pipe)
28104d348aeSZhi Wang {
28204d348aeSZhi Wang 	struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
28304d348aeSZhi Wang 	struct intel_vgpu_irq *irq = &vgpu->irq;
28404d348aeSZhi Wang 	int vblank_event[] = {
28504d348aeSZhi Wang 		[PIPE_A] = PIPE_A_VBLANK,
28604d348aeSZhi Wang 		[PIPE_B] = PIPE_B_VBLANK,
28704d348aeSZhi Wang 		[PIPE_C] = PIPE_C_VBLANK,
28804d348aeSZhi Wang 	};
28904d348aeSZhi Wang 	int event;
29004d348aeSZhi Wang 
29104d348aeSZhi Wang 	if (pipe < PIPE_A || pipe > PIPE_C)
29204d348aeSZhi Wang 		return;
29304d348aeSZhi Wang 
29404d348aeSZhi Wang 	for_each_set_bit(event, irq->flip_done_event[pipe],
29504d348aeSZhi Wang 			INTEL_GVT_EVENT_MAX) {
29604d348aeSZhi Wang 		clear_bit(event, irq->flip_done_event[pipe]);
29704d348aeSZhi Wang 		if (!pipe_is_enabled(vgpu, pipe))
29804d348aeSZhi Wang 			continue;
29904d348aeSZhi Wang 
30004d348aeSZhi Wang 		vgpu_vreg(vgpu, PIPE_FLIPCOUNT_G4X(pipe))++;
30104d348aeSZhi Wang 		intel_vgpu_trigger_virtual_event(vgpu, event);
30204d348aeSZhi Wang 	}
30304d348aeSZhi Wang 
30404d348aeSZhi Wang 	if (pipe_is_enabled(vgpu, pipe)) {
30504d348aeSZhi Wang 		vgpu_vreg(vgpu, PIPE_FRMCOUNT_G4X(pipe))++;
30604d348aeSZhi Wang 		intel_vgpu_trigger_virtual_event(vgpu, vblank_event[pipe]);
30704d348aeSZhi Wang 	}
30804d348aeSZhi Wang }
30904d348aeSZhi Wang 
31004d348aeSZhi Wang static void emulate_vblank(struct intel_vgpu *vgpu)
31104d348aeSZhi Wang {
31204d348aeSZhi Wang 	int pipe;
31304d348aeSZhi Wang 
31404d348aeSZhi Wang 	for_each_pipe(vgpu->gvt->dev_priv, pipe)
31504d348aeSZhi Wang 		emulate_vblank_on_pipe(vgpu, pipe);
31604d348aeSZhi Wang }
31704d348aeSZhi Wang 
31804d348aeSZhi Wang /**
31904d348aeSZhi Wang  * intel_gvt_emulate_vblank - trigger vblank events for vGPUs on GVT device
32004d348aeSZhi Wang  * @gvt: a GVT device
32104d348aeSZhi Wang  *
32204d348aeSZhi Wang  * This function is used to trigger vblank interrupts for vGPUs on GVT device
32304d348aeSZhi Wang  *
32404d348aeSZhi Wang  */
32504d348aeSZhi Wang void intel_gvt_emulate_vblank(struct intel_gvt *gvt)
32604d348aeSZhi Wang {
32704d348aeSZhi Wang 	struct intel_vgpu *vgpu;
32804d348aeSZhi Wang 	int id;
32904d348aeSZhi Wang 
33004d348aeSZhi Wang 	if (WARN_ON(!mutex_is_locked(&gvt->lock)))
33104d348aeSZhi Wang 		return;
33204d348aeSZhi Wang 
33304d348aeSZhi Wang 	for_each_active_vgpu(gvt, vgpu, id)
33404d348aeSZhi Wang 		emulate_vblank(vgpu);
33504d348aeSZhi Wang }
33604d348aeSZhi Wang 
33704d348aeSZhi Wang /**
33804d348aeSZhi Wang  * intel_vgpu_clean_display - clean vGPU virtual display emulation
33904d348aeSZhi Wang  * @vgpu: a vGPU
34004d348aeSZhi Wang  *
34104d348aeSZhi Wang  * This function is used to clean vGPU virtual display emulation stuffs
34204d348aeSZhi Wang  *
34304d348aeSZhi Wang  */
34404d348aeSZhi Wang void intel_vgpu_clean_display(struct intel_vgpu *vgpu)
34504d348aeSZhi Wang {
34604d348aeSZhi Wang 	struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
34704d348aeSZhi Wang 
34804d348aeSZhi Wang 	if (IS_SKYLAKE(dev_priv))
34904d348aeSZhi Wang 		clean_virtual_dp_monitor(vgpu, PORT_D);
35004d348aeSZhi Wang 	else
35104d348aeSZhi Wang 		clean_virtual_dp_monitor(vgpu, PORT_B);
35204d348aeSZhi Wang }
35304d348aeSZhi Wang 
35404d348aeSZhi Wang /**
35504d348aeSZhi Wang  * intel_vgpu_init_display- initialize vGPU virtual display emulation
35604d348aeSZhi Wang  * @vgpu: a vGPU
35704d348aeSZhi Wang  *
35804d348aeSZhi Wang  * This function is used to initialize vGPU virtual display emulation stuffs
35904d348aeSZhi Wang  *
36004d348aeSZhi Wang  * Returns:
36104d348aeSZhi Wang  * Zero on success, negative error code if failed.
36204d348aeSZhi Wang  *
36304d348aeSZhi Wang  */
364*d1a513beSZhenyu Wang int intel_vgpu_init_display(struct intel_vgpu *vgpu, u64 resolution)
36504d348aeSZhi Wang {
36604d348aeSZhi Wang 	struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
36704d348aeSZhi Wang 
36804d348aeSZhi Wang 	intel_vgpu_init_i2c_edid(vgpu);
36904d348aeSZhi Wang 
37004d348aeSZhi Wang 	if (IS_SKYLAKE(dev_priv))
371*d1a513beSZhenyu Wang 		return setup_virtual_dp_monitor(vgpu, PORT_D, GVT_DP_D,
372*d1a513beSZhenyu Wang 						resolution);
37304d348aeSZhi Wang 	else
374*d1a513beSZhenyu Wang 		return setup_virtual_dp_monitor(vgpu, PORT_B, GVT_DP_B,
375*d1a513beSZhenyu Wang 						resolution);
37604d348aeSZhi Wang }
3776294b61bSChangbin Du 
3786294b61bSChangbin Du /**
3796294b61bSChangbin Du  * intel_vgpu_reset_display- reset vGPU virtual display emulation
3806294b61bSChangbin Du  * @vgpu: a vGPU
3816294b61bSChangbin Du  *
3826294b61bSChangbin Du  * This function is used to reset vGPU virtual display emulation stuffs
3836294b61bSChangbin Du  *
3846294b61bSChangbin Du  */
3856294b61bSChangbin Du void intel_vgpu_reset_display(struct intel_vgpu *vgpu)
3866294b61bSChangbin Du {
3876294b61bSChangbin Du 	emulate_monitor_status_change(vgpu);
3886294b61bSChangbin Du }
389