From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Cai Yulong 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 --- 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