clear-pkgs-linux-iot-lts2018/1214-drm-i915-gvt-create-ed...

176 lines
6.2 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Cai Yulong <yulongc@hwtc.com.cn>
Date: Fri, 17 May 2019 15:16:38 +0800
Subject: [PATCH] drm/i915/gvt: create edid from drm_display_mode instance for
fixed-mode panel
Current gvt display pipe iteration code use intel_connector.detect_edid
to see if there is monitor attached to the connector, this will fail with
those panel which only contains a fixed mode, e.g. MIPI-DSI panel
.
This patch create a edid based on the panel's fixed mode and make
fixed-mode panel available during virutal monitor setup.
Tracked-On: projectacrn/acrn-hypervisor#3196
Signed-off-by: Cai Yulong <yulongc@hwtc.com.cn>
---
drivers/gpu/drm/i915/gvt/display.c | 18 +++++--
drivers/gpu/drm/i915/gvt/edid.c | 86 ++++++++++++++++++++++++++++++
drivers/gpu/drm/i915/gvt/edid.h | 2 +
3 files changed, 102 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c
index 1c905d9e063b..290d5b380a3e 100644
--- a/drivers/gpu/drm/i915/gvt/display.c
+++ b/drivers/gpu/drm/i915/gvt/display.c
@@ -576,6 +576,7 @@ int setup_virtual_monitors(struct intel_vgpu *vgpu)
struct intel_connector *connector = NULL;
struct drm_connector_list_iter conn_iter;
struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
+ struct edid *edid;
int pipe = 0;
int ret = 0;
int type = gvt_emulate_hdmi ? GVT_HDMI_A : GVT_DP_A;
@@ -587,17 +588,26 @@ int setup_virtual_monitors(struct intel_vgpu *vgpu)
drm_connector_list_iter_begin(&vgpu->gvt->dev_priv->drm, &conn_iter);
for_each_intel_connector_iter(connector, &conn_iter) {
- if (connector->encoder->get_hw_state(connector->encoder, &pipe)
- && connector->detect_edid) {
+ if (connector->encoder->get_hw_state(connector->encoder,
+ &pipe)) {
/* if no planes are allocated for this pipe, skip it */
if (i915_modparams.avail_planes_per_pipe &&
!bxt_check_planes(vgpu, pipe))
continue;
+
+ if (connector->panel.fixed_mode) {
+ edid = intel_gvt_create_edid_from_mode(
+ connector->panel.fixed_mode);
+ } else if (connector->detect_edid) {
+ edid = connector->detect_edid;
+ } else {
+ continue;
+ }
+
/* Get (Dom0) port associated with current pipe. */
port = connector->encoder->port;
ret = setup_virtual_monitor(vgpu, port,
- type, 0, connector->detect_edid,
- !gvt_emulate_hdmi);
+ type, 0, edid, !gvt_emulate_hdmi);
if (ret)
return ret;
type++;
diff --git a/drivers/gpu/drm/i915/gvt/edid.c b/drivers/gpu/drm/i915/gvt/edid.c
index c4bf4800f72f..97d16834368c 100644
--- a/drivers/gpu/drm/i915/gvt/edid.c
+++ b/drivers/gpu/drm/i915/gvt/edid.c
@@ -426,6 +426,92 @@ static inline int get_aux_ch_reg(unsigned int offset)
return reg;
}
+static u8 edid_checksum(struct edid *edid)
+{
+ u8 *raw = (u8 *)edid, csum = 0;
+ int i;
+
+ for (i = 0; i < EDID_LENGTH; i++)
+ csum += raw[i];
+
+ return csum;
+}
+
+struct edid *intel_gvt_create_edid_from_mode(struct drm_display_mode *mode)
+{
+ struct edid *edid = NULL;
+ struct detailed_pixel_timing *pt;
+
+ edid = kzalloc(sizeof(struct edid), GFP_KERNEL);
+ if (edid) {
+ /* EDID header */
+ memset(&edid->header[1], 0xff, 6);
+ /* Vendor & product info */
+ edid->mfg_id[0] = 0x22, edid->mfg_id[1] = 0xf0;
+ edid->prod_code[0] = 0x54, edid->prod_code[1] = 0x29;
+ edid->serial = 0x00000000;
+ edid->mfg_week = 0x05, edid->mfg_year = 0x19;
+ /* EDID version */
+ edid->version = 0x01, edid->revision = 0x04;
+ /* Display info */
+ edid->input = 0xa5;
+ edid->width_cm = 0x34;
+ edid->height_cm = 0x20;
+ edid->gamma = 0x78;
+ edid->features = 0x23;
+ /* Color characteristics */
+ edid->red_green_lo = 0xfc;
+ edid->black_white_lo = 0x81;
+ edid->red_x = 0xa4, edid->red_y = 0x55;
+ edid->green_x = 0x4d, edid->green_y = 0x9d;
+ edid->blue_x = 0x25, edid->blue_y = 0x12;
+ edid->white_x = 0x50, edid->white_y = 0x54;
+ /* Detailed timings */
+ edid->detailed_timings[0].pixel_clock =
+ cpu_to_le16(mode->clock / 10);
+ pt = &edid->detailed_timings[0].data.pixel_data;
+ pt->hactive_lo = mode->hdisplay & 0xff;
+ pt->hblank_lo = (mode->htotal - mode->hdisplay) & 0xff;
+ pt->hactive_hblank_hi = (mode->hdisplay & 0xf00) >> 4
+ | ((mode->htotal - mode->hdisplay) & 0xf00) >> 8;
+ pt->vactive_lo = mode->vdisplay & 0xff;
+ pt->vblank_lo = (mode->vtotal - mode->vdisplay) & 0xff;
+ pt->vactive_vblank_hi = (mode->vdisplay & 0xf00) >> 4
+ | ((mode->vtotal - mode->vdisplay) & 0xf00) >> 8;
+ pt->hsync_offset_lo =
+ (mode->hsync_start - mode->hdisplay) & 0xff;
+ pt->hsync_pulse_width_lo =
+ (mode->hsync_end - mode->hsync_start) & 0xff;
+ pt->vsync_offset_pulse_width_lo =
+ ((mode->vsync_start - mode->vdisplay) & 0x0f) << 4;
+ pt->vsync_offset_pulse_width_lo |=
+ (mode->vsync_end - mode->vsync_start) & 0x0f;
+ pt->hsync_vsync_offset_pulse_width_hi =
+ ((mode->hsync_start - mode->hdisplay) & 0x300) >> 2;
+ pt->hsync_vsync_offset_pulse_width_hi |=
+ ((mode->hsync_end - mode->hsync_start) & 0x300) >> 4;
+ pt->hsync_vsync_offset_pulse_width_hi |=
+ ((mode->vsync_start - mode->vdisplay) & 0x30) >> 2;
+ pt->hsync_vsync_offset_pulse_width_hi |=
+ ((mode->vsync_end - mode->vsync_start) & 0x30) >> 4;
+ pt->width_mm_lo = mode->width_mm & 0xff;
+ pt->height_mm_lo = mode->height_mm & 0xff;
+ pt->width_height_mm_hi = (mode->width_mm & 0xf00) >> 4;
+ pt->width_height_mm_hi |= (mode->height_mm & 0xf00) >> 8;
+
+ pt->misc = mode->flags & DRM_MODE_FLAG_PHSYNC ?
+ DRM_EDID_PT_HSYNC_POSITIVE : 0;
+ pt->misc |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
+ DRM_EDID_PT_VSYNC_POSITIVE : 0;
+ pt->misc |= mode->flags & DRM_MODE_FLAG_INTERLACE ?
+ DRM_EDID_PT_INTERLACED : 0;
+
+ edid->checksum = 0 - edid_checksum(edid);
+ }
+
+ return edid;
+}
+
#define AUX_CTL_MSG_LENGTH(reg) \
((reg & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >> \
DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT)
diff --git a/drivers/gpu/drm/i915/gvt/edid.h b/drivers/gpu/drm/i915/gvt/edid.h
index 11a75d69062d..fb9a37f61b73 100644
--- a/drivers/gpu/drm/i915/gvt/edid.h
+++ b/drivers/gpu/drm/i915/gvt/edid.h
@@ -147,4 +147,6 @@ void intel_gvt_i2c_handle_aux_ch_write(struct intel_vgpu *vgpu,
unsigned int offset,
void *p_data);
+struct edid *intel_gvt_create_edid_from_mode(struct drm_display_mode *mode);
+
#endif /*_GVT_EDID_H_*/
--
https://clearlinux.org