Merge branch 'drm-intel-next' of git://people.freedesktop.org/~keithp/linux into drm-core-next
* 'drm-intel-next' of git://people.freedesktop.org/~keithp/linux: drm/i915: Dumb down the semaphore logic drm/i915: pass ELD to HDMI/DP audio driver drm: support routines for HDMI/DP ELD drm/i915: Enable dither whenever display bpc < frame buffer bpc drm/i915: Enable dither whenever display bpc < frame buffer bpc
This commit is contained in:
commit
62addcb8c1
|
@ -1319,6 +1319,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
|
|||
#define HDMI_IDENTIFIER 0x000C03
|
||||
#define AUDIO_BLOCK 0x01
|
||||
#define VENDOR_BLOCK 0x03
|
||||
#define SPEAKER_BLOCK 0x04
|
||||
#define EDID_BASIC_AUDIO (1 << 6)
|
||||
|
||||
/**
|
||||
|
@ -1347,6 +1348,176 @@ u8 *drm_find_cea_extension(struct edid *edid)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_find_cea_extension);
|
||||
|
||||
static void
|
||||
parse_hdmi_vsdb(struct drm_connector *connector, uint8_t *db)
|
||||
{
|
||||
connector->eld[5] |= (db[6] >> 7) << 1; /* Supports_AI */
|
||||
|
||||
connector->dvi_dual = db[6] & 1;
|
||||
connector->max_tmds_clock = db[7] * 5;
|
||||
|
||||
connector->latency_present[0] = db[8] >> 7;
|
||||
connector->latency_present[1] = (db[8] >> 6) & 1;
|
||||
connector->video_latency[0] = db[9];
|
||||
connector->audio_latency[0] = db[10];
|
||||
connector->video_latency[1] = db[11];
|
||||
connector->audio_latency[1] = db[12];
|
||||
|
||||
DRM_LOG_KMS("HDMI: DVI dual %d, "
|
||||
"max TMDS clock %d, "
|
||||
"latency present %d %d, "
|
||||
"video latency %d %d, "
|
||||
"audio latency %d %d\n",
|
||||
connector->dvi_dual,
|
||||
connector->max_tmds_clock,
|
||||
(int) connector->latency_present[0],
|
||||
(int) connector->latency_present[1],
|
||||
connector->video_latency[0],
|
||||
connector->video_latency[1],
|
||||
connector->audio_latency[0],
|
||||
connector->audio_latency[1]);
|
||||
}
|
||||
|
||||
static void
|
||||
monitor_name(struct detailed_timing *t, void *data)
|
||||
{
|
||||
if (t->data.other_data.type == EDID_DETAIL_MONITOR_NAME)
|
||||
*(u8 **)data = t->data.other_data.data.str.str;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_edid_to_eld - build ELD from EDID
|
||||
* @connector: connector corresponding to the HDMI/DP sink
|
||||
* @edid: EDID to parse
|
||||
*
|
||||
* Fill the ELD (EDID-Like Data) buffer for passing to the audio driver.
|
||||
* Some ELD fields are left to the graphics driver caller:
|
||||
* - Conn_Type
|
||||
* - HDCP
|
||||
* - Port_ID
|
||||
*/
|
||||
void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
|
||||
{
|
||||
uint8_t *eld = connector->eld;
|
||||
u8 *cea;
|
||||
u8 *name;
|
||||
u8 *db;
|
||||
int sad_count = 0;
|
||||
int mnl;
|
||||
int dbl;
|
||||
|
||||
memset(eld, 0, sizeof(connector->eld));
|
||||
|
||||
cea = drm_find_cea_extension(edid);
|
||||
if (!cea) {
|
||||
DRM_DEBUG_KMS("ELD: no CEA Extension found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
name = NULL;
|
||||
drm_for_each_detailed_block((u8 *)edid, monitor_name, &name);
|
||||
for (mnl = 0; name && mnl < 13; mnl++) {
|
||||
if (name[mnl] == 0x0a)
|
||||
break;
|
||||
eld[20 + mnl] = name[mnl];
|
||||
}
|
||||
eld[4] = (cea[1] << 5) | mnl;
|
||||
DRM_DEBUG_KMS("ELD monitor %s\n", eld + 20);
|
||||
|
||||
eld[0] = 2 << 3; /* ELD version: 2 */
|
||||
|
||||
eld[16] = edid->mfg_id[0];
|
||||
eld[17] = edid->mfg_id[1];
|
||||
eld[18] = edid->prod_code[0];
|
||||
eld[19] = edid->prod_code[1];
|
||||
|
||||
for (db = cea + 4; db < cea + cea[2]; db += dbl + 1) {
|
||||
dbl = db[0] & 0x1f;
|
||||
|
||||
switch ((db[0] & 0xe0) >> 5) {
|
||||
case AUDIO_BLOCK: /* Audio Data Block, contains SADs */
|
||||
sad_count = dbl / 3;
|
||||
memcpy(eld + 20 + mnl, &db[1], dbl);
|
||||
break;
|
||||
case SPEAKER_BLOCK: /* Speaker Allocation Data Block */
|
||||
eld[7] = db[1];
|
||||
break;
|
||||
case VENDOR_BLOCK:
|
||||
/* HDMI Vendor-Specific Data Block */
|
||||
if (db[1] == 0x03 && db[2] == 0x0c && db[3] == 0)
|
||||
parse_hdmi_vsdb(connector, db);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
eld[5] |= sad_count << 4;
|
||||
eld[2] = (20 + mnl + sad_count * 3 + 3) / 4;
|
||||
|
||||
DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", (int)eld[2], sad_count);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_edid_to_eld);
|
||||
|
||||
/**
|
||||
* drm_av_sync_delay - HDMI/DP sink audio-video sync delay in millisecond
|
||||
* @connector: connector associated with the HDMI/DP sink
|
||||
* @mode: the display mode
|
||||
*/
|
||||
int drm_av_sync_delay(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
int i = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
|
||||
int a, v;
|
||||
|
||||
if (!connector->latency_present[0])
|
||||
return 0;
|
||||
if (!connector->latency_present[1])
|
||||
i = 0;
|
||||
|
||||
a = connector->audio_latency[i];
|
||||
v = connector->video_latency[i];
|
||||
|
||||
/*
|
||||
* HDMI/DP sink doesn't support audio or video?
|
||||
*/
|
||||
if (a == 255 || v == 255)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Convert raw EDID values to millisecond.
|
||||
* Treat unknown latency as 0ms.
|
||||
*/
|
||||
if (a)
|
||||
a = min(2 * (a - 1), 500);
|
||||
if (v)
|
||||
v = min(2 * (v - 1), 500);
|
||||
|
||||
return max(v - a, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_av_sync_delay);
|
||||
|
||||
/**
|
||||
* drm_select_eld - select one ELD from multiple HDMI/DP sinks
|
||||
* @encoder: the encoder just changed display mode
|
||||
* @mode: the adjusted display mode
|
||||
*
|
||||
* It's possible for one encoder to be associated with multiple HDMI/DP sinks.
|
||||
* The policy is now hard coded to simply use the first HDMI/DP sink's ELD.
|
||||
*/
|
||||
struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
|
||||
if (connector->encoder == encoder && connector->eld[0])
|
||||
return connector;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_select_eld);
|
||||
|
||||
/**
|
||||
* drm_detect_hdmi_monitor - detect whether monitor is hdmi.
|
||||
* @edid: monitor EDID information
|
||||
|
|
|
@ -209,6 +209,8 @@ struct drm_i915_display_funcs {
|
|||
struct drm_display_mode *adjusted_mode,
|
||||
int x, int y,
|
||||
struct drm_framebuffer *old_fb);
|
||||
void (*write_eld)(struct drm_connector *connector,
|
||||
struct drm_crtc *crtc);
|
||||
void (*fdi_link_train)(struct drm_crtc *crtc);
|
||||
void (*init_clock_gating)(struct drm_device *dev);
|
||||
void (*init_pch_clock_gating)(struct drm_device *dev);
|
||||
|
|
|
@ -784,7 +784,8 @@ i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj,
|
|||
}
|
||||
|
||||
from->sync_seqno[idx] = seqno;
|
||||
return intel_ring_sync(to, from, seqno - 1);
|
||||
|
||||
return to->sync_to(to, from, seqno - 1);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -194,6 +194,13 @@
|
|||
#define MI_SEMAPHORE_UPDATE (1<<21)
|
||||
#define MI_SEMAPHORE_COMPARE (1<<20)
|
||||
#define MI_SEMAPHORE_REGISTER (1<<18)
|
||||
#define MI_SEMAPHORE_SYNC_RV (2<<16)
|
||||
#define MI_SEMAPHORE_SYNC_RB (0<<16)
|
||||
#define MI_SEMAPHORE_SYNC_VR (0<<16)
|
||||
#define MI_SEMAPHORE_SYNC_VB (2<<16)
|
||||
#define MI_SEMAPHORE_SYNC_BR (2<<16)
|
||||
#define MI_SEMAPHORE_SYNC_BV (0<<16)
|
||||
#define MI_SEMAPHORE_SYNC_INVALID (1<<0)
|
||||
/*
|
||||
* 3D instructions used by the kernel
|
||||
*/
|
||||
|
@ -296,6 +303,12 @@
|
|||
#define RING_CTL(base) ((base)+0x3c)
|
||||
#define RING_SYNC_0(base) ((base)+0x40)
|
||||
#define RING_SYNC_1(base) ((base)+0x44)
|
||||
#define GEN6_RVSYNC (RING_SYNC_0(RENDER_RING_BASE))
|
||||
#define GEN6_RBSYNC (RING_SYNC_1(RENDER_RING_BASE))
|
||||
#define GEN6_VRSYNC (RING_SYNC_1(GEN6_BSD_RING_BASE))
|
||||
#define GEN6_VBSYNC (RING_SYNC_0(GEN6_BSD_RING_BASE))
|
||||
#define GEN6_BRSYNC (RING_SYNC_0(BLT_RING_BASE))
|
||||
#define GEN6_BVSYNC (RING_SYNC_1(BLT_RING_BASE))
|
||||
#define RING_MAX_IDLE(base) ((base)+0x54)
|
||||
#define RING_HWS_PGA(base) ((base)+0x80)
|
||||
#define RING_HWS_PGA_GEN6(base) ((base)+0x2080)
|
||||
|
@ -3470,4 +3483,29 @@
|
|||
#define GEN6_PCODE_DATA 0x138128
|
||||
#define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8
|
||||
|
||||
#define G4X_AUD_VID_DID 0x62020
|
||||
#define INTEL_AUDIO_DEVCL 0x808629FB
|
||||
#define INTEL_AUDIO_DEVBLC 0x80862801
|
||||
#define INTEL_AUDIO_DEVCTG 0x80862802
|
||||
|
||||
#define G4X_AUD_CNTL_ST 0x620B4
|
||||
#define G4X_ELDV_DEVCL_DEVBLC (1 << 13)
|
||||
#define G4X_ELDV_DEVCTG (1 << 14)
|
||||
#define G4X_ELD_ADDR (0xf << 5)
|
||||
#define G4X_ELD_ACK (1 << 4)
|
||||
#define G4X_HDMIW_HDMIEDID 0x6210C
|
||||
|
||||
#define GEN5_HDMIW_HDMIEDID_A 0xE2050
|
||||
#define GEN5_AUD_CNTL_ST_A 0xE20B4
|
||||
#define GEN5_ELD_BUFFER_SIZE (0x1f << 10)
|
||||
#define GEN5_ELD_ADDRESS (0x1f << 5)
|
||||
#define GEN5_ELD_ACK (1 << 4)
|
||||
#define GEN5_AUD_CNTL_ST2 0xE20C0
|
||||
#define GEN5_ELD_VALIDB (1 << 0)
|
||||
#define GEN5_CP_READYB (1 << 1)
|
||||
|
||||
#define GEN7_HDMIW_HDMIEDID_A 0xE5050
|
||||
#define GEN7_AUD_CNTRL_ST_A 0xE50B4
|
||||
#define GEN7_AUD_CNTRL_ST2 0xE50C0
|
||||
|
||||
#endif /* _I915_REG_H_ */
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vgaarb.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include "drmP.h"
|
||||
#include "intel_drv.h"
|
||||
#include "i915_drm.h"
|
||||
|
@ -4687,13 +4688,13 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
|
|||
bpc = 6; /* min is 18bpp */
|
||||
break;
|
||||
case 24:
|
||||
bpc = min((unsigned int)8, display_bpc);
|
||||
bpc = 8;
|
||||
break;
|
||||
case 30:
|
||||
bpc = min((unsigned int)10, display_bpc);
|
||||
bpc = 10;
|
||||
break;
|
||||
case 48:
|
||||
bpc = min((unsigned int)12, display_bpc);
|
||||
bpc = 12;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG("unsupported depth, assuming 24 bits\n");
|
||||
|
@ -4701,10 +4702,12 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
|
|||
break;
|
||||
}
|
||||
|
||||
display_bpc = min(display_bpc, bpc);
|
||||
|
||||
DRM_DEBUG_DRIVER("setting pipe bpc to %d (max display bpc %d)\n",
|
||||
bpc, display_bpc);
|
||||
|
||||
*pipe_bpp = bpc * 3;
|
||||
*pipe_bpp = display_bpc * 3;
|
||||
|
||||
return display_bpc != bpc;
|
||||
}
|
||||
|
@ -5667,6 +5670,131 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void g4x_write_eld(struct drm_connector *connector,
|
||||
struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||
uint8_t *eld = connector->eld;
|
||||
uint32_t eldv;
|
||||
uint32_t len;
|
||||
uint32_t i;
|
||||
|
||||
i = I915_READ(G4X_AUD_VID_DID);
|
||||
|
||||
if (i == INTEL_AUDIO_DEVBLC || i == INTEL_AUDIO_DEVCL)
|
||||
eldv = G4X_ELDV_DEVCL_DEVBLC;
|
||||
else
|
||||
eldv = G4X_ELDV_DEVCTG;
|
||||
|
||||
i = I915_READ(G4X_AUD_CNTL_ST);
|
||||
i &= ~(eldv | G4X_ELD_ADDR);
|
||||
len = (i >> 9) & 0x1f; /* ELD buffer size */
|
||||
I915_WRITE(G4X_AUD_CNTL_ST, i);
|
||||
|
||||
if (!eld[0])
|
||||
return;
|
||||
|
||||
len = min_t(uint8_t, eld[2], len);
|
||||
DRM_DEBUG_DRIVER("ELD size %d\n", len);
|
||||
for (i = 0; i < len; i++)
|
||||
I915_WRITE(G4X_HDMIW_HDMIEDID, *((uint32_t *)eld + i));
|
||||
|
||||
i = I915_READ(G4X_AUD_CNTL_ST);
|
||||
i |= eldv;
|
||||
I915_WRITE(G4X_AUD_CNTL_ST, i);
|
||||
}
|
||||
|
||||
static void ironlake_write_eld(struct drm_connector *connector,
|
||||
struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||
uint8_t *eld = connector->eld;
|
||||
uint32_t eldv;
|
||||
uint32_t i;
|
||||
int len;
|
||||
int hdmiw_hdmiedid;
|
||||
int aud_cntl_st;
|
||||
int aud_cntrl_st2;
|
||||
|
||||
if (IS_IVYBRIDGE(connector->dev)) {
|
||||
hdmiw_hdmiedid = GEN7_HDMIW_HDMIEDID_A;
|
||||
aud_cntl_st = GEN7_AUD_CNTRL_ST_A;
|
||||
aud_cntrl_st2 = GEN7_AUD_CNTRL_ST2;
|
||||
} else {
|
||||
hdmiw_hdmiedid = GEN5_HDMIW_HDMIEDID_A;
|
||||
aud_cntl_st = GEN5_AUD_CNTL_ST_A;
|
||||
aud_cntrl_st2 = GEN5_AUD_CNTL_ST2;
|
||||
}
|
||||
|
||||
i = to_intel_crtc(crtc)->pipe;
|
||||
hdmiw_hdmiedid += i * 0x100;
|
||||
aud_cntl_st += i * 0x100;
|
||||
|
||||
DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(i));
|
||||
|
||||
i = I915_READ(aud_cntl_st);
|
||||
i = (i >> 29) & 0x3; /* DIP_Port_Select, 0x1 = PortB */
|
||||
if (!i) {
|
||||
DRM_DEBUG_DRIVER("Audio directed to unknown port\n");
|
||||
/* operate blindly on all ports */
|
||||
eldv = GEN5_ELD_VALIDB;
|
||||
eldv |= GEN5_ELD_VALIDB << 4;
|
||||
eldv |= GEN5_ELD_VALIDB << 8;
|
||||
} else {
|
||||
DRM_DEBUG_DRIVER("ELD on port %c\n", 'A' + i);
|
||||
eldv = GEN5_ELD_VALIDB << ((i - 1) * 4);
|
||||
}
|
||||
|
||||
i = I915_READ(aud_cntrl_st2);
|
||||
i &= ~eldv;
|
||||
I915_WRITE(aud_cntrl_st2, i);
|
||||
|
||||
if (!eld[0])
|
||||
return;
|
||||
|
||||
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
|
||||
DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n");
|
||||
eld[5] |= (1 << 2); /* Conn_Type, 0x1 = DisplayPort */
|
||||
}
|
||||
|
||||
i = I915_READ(aud_cntl_st);
|
||||
i &= ~GEN5_ELD_ADDRESS;
|
||||
I915_WRITE(aud_cntl_st, i);
|
||||
|
||||
len = min_t(uint8_t, eld[2], 21); /* 84 bytes of hw ELD buffer */
|
||||
DRM_DEBUG_DRIVER("ELD size %d\n", len);
|
||||
for (i = 0; i < len; i++)
|
||||
I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i));
|
||||
|
||||
i = I915_READ(aud_cntrl_st2);
|
||||
i |= eldv;
|
||||
I915_WRITE(aud_cntrl_st2, i);
|
||||
}
|
||||
|
||||
void intel_write_eld(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
struct drm_connector *connector;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
connector = drm_select_eld(encoder, mode);
|
||||
if (!connector)
|
||||
return;
|
||||
|
||||
DRM_DEBUG_DRIVER("ELD on [CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
|
||||
connector->base.id,
|
||||
drm_get_connector_name(connector),
|
||||
connector->encoder->base.id,
|
||||
drm_get_encoder_name(connector->encoder));
|
||||
|
||||
connector->eld[6] = drm_av_sync_delay(connector, mode) / 2;
|
||||
|
||||
if (dev_priv->display.write_eld)
|
||||
dev_priv->display.write_eld(connector, crtc);
|
||||
}
|
||||
|
||||
/** Loads the palette/gamma unit for the CRTC with the prepared values */
|
||||
void intel_crtc_load_lut(struct drm_crtc *crtc)
|
||||
{
|
||||
|
@ -8183,6 +8311,7 @@ static void intel_init_display(struct drm_device *dev)
|
|||
}
|
||||
dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
|
||||
dev_priv->display.init_clock_gating = ironlake_init_clock_gating;
|
||||
dev_priv->display.write_eld = ironlake_write_eld;
|
||||
} else if (IS_GEN6(dev)) {
|
||||
if (SNB_READ_WM0_LATENCY()) {
|
||||
dev_priv->display.update_wm = sandybridge_update_wm;
|
||||
|
@ -8193,6 +8322,7 @@ static void intel_init_display(struct drm_device *dev)
|
|||
}
|
||||
dev_priv->display.fdi_link_train = gen6_fdi_link_train;
|
||||
dev_priv->display.init_clock_gating = gen6_init_clock_gating;
|
||||
dev_priv->display.write_eld = ironlake_write_eld;
|
||||
} else if (IS_IVYBRIDGE(dev)) {
|
||||
/* FIXME: detect B0+ stepping and use auto training */
|
||||
dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
|
||||
|
@ -8204,7 +8334,7 @@ static void intel_init_display(struct drm_device *dev)
|
|||
dev_priv->display.update_wm = NULL;
|
||||
}
|
||||
dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
|
||||
|
||||
dev_priv->display.write_eld = ironlake_write_eld;
|
||||
} else
|
||||
dev_priv->display.update_wm = NULL;
|
||||
} else if (IS_PINEVIEW(dev)) {
|
||||
|
@ -8224,6 +8354,7 @@ static void intel_init_display(struct drm_device *dev)
|
|||
dev_priv->display.update_wm = pineview_update_wm;
|
||||
dev_priv->display.init_clock_gating = gen3_init_clock_gating;
|
||||
} else if (IS_G4X(dev)) {
|
||||
dev_priv->display.write_eld = g4x_write_eld;
|
||||
dev_priv->display.update_wm = g4x_update_wm;
|
||||
dev_priv->display.init_clock_gating = g4x_init_clock_gating;
|
||||
} else if (IS_GEN4(dev)) {
|
||||
|
|
|
@ -773,8 +773,12 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|||
intel_dp->DP |= DP_PORT_WIDTH_4;
|
||||
break;
|
||||
}
|
||||
if (intel_dp->has_audio)
|
||||
if (intel_dp->has_audio) {
|
||||
DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
|
||||
pipe_name(intel_crtc->pipe));
|
||||
intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
|
||||
intel_write_eld(encoder, adjusted_mode);
|
||||
}
|
||||
|
||||
memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
|
||||
intel_dp->link_configuration[0] = intel_dp->link_bw;
|
||||
|
|
|
@ -380,4 +380,6 @@ extern void intel_fb_output_poll_changed(struct drm_device *dev);
|
|||
extern void intel_fb_restore_mode(struct drm_device *dev);
|
||||
|
||||
extern void intel_init_clock_gating(struct drm_device *dev);
|
||||
extern void intel_write_eld(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode);
|
||||
#endif /* __INTEL_DRV_H__ */
|
||||
|
|
|
@ -245,8 +245,11 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
|
|||
sdvox |= HDMI_MODE_SELECT;
|
||||
|
||||
if (intel_hdmi->has_audio) {
|
||||
DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
|
||||
pipe_name(intel_crtc->pipe));
|
||||
sdvox |= SDVO_AUDIO_ENABLE;
|
||||
sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC;
|
||||
intel_write_eld(encoder, adjusted_mode);
|
||||
}
|
||||
|
||||
if (intel_crtc->pipe == 1) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/fb.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include "drmP.h"
|
||||
#include "intel_drv.h"
|
||||
#include "i915_drv.h"
|
||||
|
@ -74,6 +75,7 @@ int intel_ddc_get_modes(struct drm_connector *connector,
|
|||
if (edid) {
|
||||
drm_mode_connector_update_edid_property(connector, edid);
|
||||
ret = drm_add_edid_modes(connector, edid);
|
||||
drm_edid_to_eld(connector, edid);
|
||||
connector->display_info.raw_edid = NULL;
|
||||
kfree(edid);
|
||||
}
|
||||
|
|
|
@ -315,79 +315,127 @@ static void render_ring_cleanup(struct intel_ring_buffer *ring)
|
|||
}
|
||||
|
||||
static void
|
||||
update_semaphore(struct intel_ring_buffer *ring, int i, u32 seqno)
|
||||
update_mboxes(struct intel_ring_buffer *ring,
|
||||
u32 seqno,
|
||||
u32 mmio_offset)
|
||||
{
|
||||
struct drm_device *dev = ring->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int id;
|
||||
|
||||
/*
|
||||
* cs -> 1 = vcs, 0 = bcs
|
||||
* vcs -> 1 = bcs, 0 = cs,
|
||||
* bcs -> 1 = cs, 0 = vcs.
|
||||
*/
|
||||
id = ring - dev_priv->ring;
|
||||
id += 2 - i;
|
||||
id %= 3;
|
||||
|
||||
intel_ring_emit(ring,
|
||||
MI_SEMAPHORE_MBOX |
|
||||
MI_SEMAPHORE_REGISTER |
|
||||
MI_SEMAPHORE_UPDATE);
|
||||
intel_ring_emit(ring, MI_SEMAPHORE_MBOX |
|
||||
MI_SEMAPHORE_GLOBAL_GTT |
|
||||
MI_SEMAPHORE_REGISTER |
|
||||
MI_SEMAPHORE_UPDATE);
|
||||
intel_ring_emit(ring, seqno);
|
||||
intel_ring_emit(ring,
|
||||
RING_SYNC_0(dev_priv->ring[id].mmio_base) + 4*i);
|
||||
intel_ring_emit(ring, mmio_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* gen6_add_request - Update the semaphore mailbox registers
|
||||
*
|
||||
* @ring - ring that is adding a request
|
||||
* @seqno - return seqno stuck into the ring
|
||||
*
|
||||
* Update the mailbox registers in the *other* rings with the current seqno.
|
||||
* This acts like a signal in the canonical semaphore.
|
||||
*/
|
||||
static int
|
||||
gen6_add_request(struct intel_ring_buffer *ring,
|
||||
u32 *result)
|
||||
u32 *seqno)
|
||||
{
|
||||
u32 seqno;
|
||||
u32 mbox1_reg;
|
||||
u32 mbox2_reg;
|
||||
int ret;
|
||||
|
||||
ret = intel_ring_begin(ring, 10);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
seqno = i915_gem_get_seqno(ring->dev);
|
||||
update_semaphore(ring, 0, seqno);
|
||||
update_semaphore(ring, 1, seqno);
|
||||
mbox1_reg = ring->signal_mbox[0];
|
||||
mbox2_reg = ring->signal_mbox[1];
|
||||
|
||||
*seqno = i915_gem_get_seqno(ring->dev);
|
||||
|
||||
update_mboxes(ring, *seqno, mbox1_reg);
|
||||
update_mboxes(ring, *seqno, mbox2_reg);
|
||||
intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
|
||||
intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
|
||||
intel_ring_emit(ring, seqno);
|
||||
intel_ring_emit(ring, *seqno);
|
||||
intel_ring_emit(ring, MI_USER_INTERRUPT);
|
||||
intel_ring_advance(ring);
|
||||
|
||||
*result = seqno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
intel_ring_sync(struct intel_ring_buffer *ring,
|
||||
struct intel_ring_buffer *to,
|
||||
/**
|
||||
* intel_ring_sync - sync the waiter to the signaller on seqno
|
||||
*
|
||||
* @waiter - ring that is waiting
|
||||
* @signaller - ring which has, or will signal
|
||||
* @seqno - seqno which the waiter will block on
|
||||
*/
|
||||
static int
|
||||
intel_ring_sync(struct intel_ring_buffer *waiter,
|
||||
struct intel_ring_buffer *signaller,
|
||||
int ring,
|
||||
u32 seqno)
|
||||
{
|
||||
int ret;
|
||||
u32 dw1 = MI_SEMAPHORE_MBOX |
|
||||
MI_SEMAPHORE_COMPARE |
|
||||
MI_SEMAPHORE_REGISTER;
|
||||
|
||||
ret = intel_ring_begin(ring, 4);
|
||||
ret = intel_ring_begin(waiter, 4);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
intel_ring_emit(ring,
|
||||
MI_SEMAPHORE_MBOX |
|
||||
MI_SEMAPHORE_REGISTER |
|
||||
intel_ring_sync_index(ring, to) << 17 |
|
||||
MI_SEMAPHORE_COMPARE);
|
||||
intel_ring_emit(ring, seqno);
|
||||
intel_ring_emit(ring, 0);
|
||||
intel_ring_emit(ring, MI_NOOP);
|
||||
intel_ring_advance(ring);
|
||||
intel_ring_emit(waiter, dw1 | signaller->semaphore_register[ring]);
|
||||
intel_ring_emit(waiter, seqno);
|
||||
intel_ring_emit(waiter, 0);
|
||||
intel_ring_emit(waiter, MI_NOOP);
|
||||
intel_ring_advance(waiter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* VCS->RCS (RVSYNC) or BCS->RCS (RBSYNC) */
|
||||
int
|
||||
render_ring_sync_to(struct intel_ring_buffer *waiter,
|
||||
struct intel_ring_buffer *signaller,
|
||||
u32 seqno)
|
||||
{
|
||||
WARN_ON(signaller->semaphore_register[RCS] == MI_SEMAPHORE_SYNC_INVALID);
|
||||
return intel_ring_sync(waiter,
|
||||
signaller,
|
||||
RCS,
|
||||
seqno);
|
||||
}
|
||||
|
||||
/* RCS->VCS (VRSYNC) or BCS->VCS (VBSYNC) */
|
||||
int
|
||||
gen6_bsd_ring_sync_to(struct intel_ring_buffer *waiter,
|
||||
struct intel_ring_buffer *signaller,
|
||||
u32 seqno)
|
||||
{
|
||||
WARN_ON(signaller->semaphore_register[VCS] == MI_SEMAPHORE_SYNC_INVALID);
|
||||
return intel_ring_sync(waiter,
|
||||
signaller,
|
||||
VCS,
|
||||
seqno);
|
||||
}
|
||||
|
||||
/* RCS->BCS (BRSYNC) or VCS->BCS (BVSYNC) */
|
||||
int
|
||||
gen6_blt_ring_sync_to(struct intel_ring_buffer *waiter,
|
||||
struct intel_ring_buffer *signaller,
|
||||
u32 seqno)
|
||||
{
|
||||
WARN_ON(signaller->semaphore_register[BCS] == MI_SEMAPHORE_SYNC_INVALID);
|
||||
return intel_ring_sync(waiter,
|
||||
signaller,
|
||||
BCS,
|
||||
seqno);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define PIPE_CONTROL_FLUSH(ring__, addr__) \
|
||||
do { \
|
||||
intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \
|
||||
|
@ -1027,6 +1075,11 @@ static const struct intel_ring_buffer render_ring = {
|
|||
.irq_put = render_ring_put_irq,
|
||||
.dispatch_execbuffer = render_ring_dispatch_execbuffer,
|
||||
.cleanup = render_ring_cleanup,
|
||||
.sync_to = render_ring_sync_to,
|
||||
.semaphore_register = {MI_SEMAPHORE_SYNC_INVALID,
|
||||
MI_SEMAPHORE_SYNC_RV,
|
||||
MI_SEMAPHORE_SYNC_RB},
|
||||
.signal_mbox = {GEN6_VRSYNC, GEN6_BRSYNC},
|
||||
};
|
||||
|
||||
/* ring buffer for bit-stream decoder */
|
||||
|
@ -1154,6 +1207,11 @@ static const struct intel_ring_buffer gen6_bsd_ring = {
|
|||
.irq_get = gen6_bsd_ring_get_irq,
|
||||
.irq_put = gen6_bsd_ring_put_irq,
|
||||
.dispatch_execbuffer = gen6_ring_dispatch_execbuffer,
|
||||
.sync_to = gen6_bsd_ring_sync_to,
|
||||
.semaphore_register = {MI_SEMAPHORE_SYNC_VR,
|
||||
MI_SEMAPHORE_SYNC_INVALID,
|
||||
MI_SEMAPHORE_SYNC_VB},
|
||||
.signal_mbox = {GEN6_RVSYNC, GEN6_BVSYNC},
|
||||
};
|
||||
|
||||
/* Blitter support (SandyBridge+) */
|
||||
|
@ -1281,10 +1339,15 @@ static const struct intel_ring_buffer gen6_blt_ring = {
|
|||
.flush = blt_ring_flush,
|
||||
.add_request = gen6_add_request,
|
||||
.get_seqno = ring_get_seqno,
|
||||
.irq_get = blt_ring_get_irq,
|
||||
.irq_put = blt_ring_put_irq,
|
||||
.irq_get = blt_ring_get_irq,
|
||||
.irq_put = blt_ring_put_irq,
|
||||
.dispatch_execbuffer = gen6_ring_dispatch_execbuffer,
|
||||
.cleanup = blt_ring_cleanup,
|
||||
.cleanup = blt_ring_cleanup,
|
||||
.sync_to = gen6_blt_ring_sync_to,
|
||||
.semaphore_register = {MI_SEMAPHORE_SYNC_BR,
|
||||
MI_SEMAPHORE_SYNC_BV,
|
||||
MI_SEMAPHORE_SYNC_INVALID},
|
||||
.signal_mbox = {GEN6_RBSYNC, GEN6_VBSYNC},
|
||||
};
|
||||
|
||||
int intel_init_render_ring_buffer(struct drm_device *dev)
|
||||
|
|
|
@ -75,7 +75,12 @@ struct intel_ring_buffer {
|
|||
int (*dispatch_execbuffer)(struct intel_ring_buffer *ring,
|
||||
u32 offset, u32 length);
|
||||
void (*cleanup)(struct intel_ring_buffer *ring);
|
||||
int (*sync_to)(struct intel_ring_buffer *ring,
|
||||
struct intel_ring_buffer *to,
|
||||
u32 seqno);
|
||||
|
||||
u32 semaphore_register[3]; /*our mbox written by others */
|
||||
u32 signal_mbox[2]; /* mboxes this ring signals to */
|
||||
/**
|
||||
* List of objects currently involved in rendering from the
|
||||
* ringbuffer.
|
||||
|
@ -180,9 +185,6 @@ static inline void intel_ring_emit(struct intel_ring_buffer *ring,
|
|||
void intel_ring_advance(struct intel_ring_buffer *ring);
|
||||
|
||||
u32 intel_ring_get_seqno(struct intel_ring_buffer *ring);
|
||||
int intel_ring_sync(struct intel_ring_buffer *ring,
|
||||
struct intel_ring_buffer *to,
|
||||
u32 seqno);
|
||||
|
||||
int intel_init_render_ring_buffer(struct drm_device *dev);
|
||||
int intel_init_bsd_ring_buffer(struct drm_device *dev);
|
||||
|
|
|
@ -466,6 +466,8 @@ enum drm_connector_force {
|
|||
/* DACs should rarely do this without a lot of testing */
|
||||
#define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2)
|
||||
|
||||
#define MAX_ELD_BYTES 128
|
||||
|
||||
/**
|
||||
* drm_connector - central DRM connector control structure
|
||||
* @crtc: CRTC this connector is currently connected to, NULL if none
|
||||
|
@ -523,6 +525,13 @@ struct drm_connector {
|
|||
uint32_t force_encoder_id;
|
||||
struct drm_encoder *encoder; /* currently active encoder */
|
||||
|
||||
/* EDID bits */
|
||||
uint8_t eld[MAX_ELD_BYTES];
|
||||
bool dvi_dual;
|
||||
int max_tmds_clock; /* in MHz */
|
||||
bool latency_present[2];
|
||||
int video_latency[2]; /* [0]: progressive, [1]: interlaced */
|
||||
int audio_latency[2];
|
||||
int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */
|
||||
};
|
||||
|
||||
|
|
|
@ -230,4 +230,13 @@ struct edid {
|
|||
|
||||
#define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))
|
||||
|
||||
struct drm_encoder;
|
||||
struct drm_connector;
|
||||
struct drm_display_mode;
|
||||
void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid);
|
||||
int drm_av_sync_delay(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode);
|
||||
struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode);
|
||||
|
||||
#endif /* __DRM_EDID_H__ */
|
||||
|
|
Loading…
Reference in New Issue