mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-17 17:24:17 +08:00
Merge tag 'drm-intel-next-2014-09-05' of git://anongit.freedesktop.org/drm-intel into drm-next
- final bits (again) for the rotation support (Sonika Jindal) - support bl_power in the intel backlight (Jani) - vdd handling improvements from Ville - i830M fixes from Ville - piles of prep work all over to make skl enabling just plug in (Damien, Sonika) - rename DP training defines to reflect latest edp standards, this touches all drm drivers supporting DP (Sonika Jindal) - cache edids during single detect cycle to avoid re-reading it for e.g. audio, from Chris - move w/a for registers which are stored in the hw context to the context init code (Arun&Damien) - edp panel power sequencer fixes, helps chv a lot (Ville) - piles of other chv fixes all over - much more paranoid pageflip handling with stall detection and better recovery from Chris - small things all over, as usual * tag 'drm-intel-next-2014-09-05' of git://anongit.freedesktop.org/drm-intel: (114 commits) drm/i915: Update DRIVER_DATE to 20140905 drm/i915: Decouple the stuck pageflip on modeset drm/i915: Check for a stalled page flip after each vblank drm/i915: Introduce a for_each_plane() macro drm/i915: Rewrite ABS_DIFF() in a safer manner drm/i915: Add comments explaining the vdd on/off functions drm/i915: Move DP port disable to post_disable for pch platforms drm/i915: Enable DP port earlier drm/i915: Turn on panel power before doing aux transfers drm/i915: Be more careful when picking the initial power sequencer pipe drm/i915: Reset power sequencer pipe tracking when disp2d is off drm/i915: Track which port is using which pipe's power sequencer drm/i915: Fix edp vdd locking drm/i915: Reset the HEAD pointer for the ring after writing START drm/i915: Fix unsafe vma iteration in i915_drop_caches drm/i915: init sprites with univeral plane init function drm/i915: Check of !HAS_PCH_SPLIT() in PCH transcoder funcs drm/i915: Use HAS_GMCH_DISPLAY un underrun reporting code drm/i915: Use IS_BROADWELL() instead of IS_GEN8() in forcewake code drm/i915: Don't call gen8_fbc_sw_flush() on chv ...
This commit is contained in:
commit
40d201af0b
@ -3091,7 +3091,7 @@ F: include/drm/drm_panel.h
|
||||
F: Documentation/devicetree/bindings/panel/
|
||||
|
||||
INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
|
||||
M: Daniel Vetter <daniel.vetter@ffwll.ch>
|
||||
M: Daniel Vetter <daniel.vetter@intel.com>
|
||||
M: Jani Nikula <jani.nikula@linux.intel.com>
|
||||
L: intel-gfx@lists.freedesktop.org
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
|
@ -329,8 +329,8 @@ static int exynos_dp_link_start(struct exynos_dp_device *dp)
|
||||
return retval;
|
||||
|
||||
for (lane = 0; lane < lane_count; lane++)
|
||||
buf[lane] = DP_TRAIN_PRE_EMPHASIS_0 |
|
||||
DP_TRAIN_VOLTAGE_SWING_400;
|
||||
buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 |
|
||||
DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
|
||||
|
||||
retval = exynos_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET,
|
||||
lane_count, buf);
|
||||
|
@ -1089,7 +1089,7 @@ static char *link_train_names[] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#define CDV_DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200
|
||||
#define CDV_DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_LEVEL_3
|
||||
/*
|
||||
static uint8_t
|
||||
cdv_intel_dp_pre_emphasis_max(uint8_t voltage_swing)
|
||||
@ -1276,7 +1276,7 @@ cdv_intel_dp_set_vswing_premph(struct gma_encoder *encoder, uint8_t signal_level
|
||||
cdv_sb_write(dev, ddi_reg->VSwing2, dp_vswing_premph_table[index]);
|
||||
|
||||
/* ;gfx_dpio_set_reg(0x814c, 0x40802040) */
|
||||
if ((vswing + premph) == DP_TRAIN_VOLTAGE_SWING_1200)
|
||||
if ((vswing + premph) == DP_TRAIN_VOLTAGE_SWING_LEVEL_3)
|
||||
cdv_sb_write(dev, ddi_reg->VSwing3, 0x70802040);
|
||||
else
|
||||
cdv_sb_write(dev, ddi_reg->VSwing3, 0x40802040);
|
||||
|
@ -116,30 +116,30 @@ parse_edp(struct drm_psb_private *dev_priv, struct bdb_header *bdb)
|
||||
|
||||
switch (edp_link_params->preemphasis) {
|
||||
case 0:
|
||||
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
|
||||
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_0;
|
||||
break;
|
||||
case 1:
|
||||
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
|
||||
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_1;
|
||||
break;
|
||||
case 2:
|
||||
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
|
||||
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_2;
|
||||
break;
|
||||
case 3:
|
||||
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
|
||||
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_3;
|
||||
break;
|
||||
}
|
||||
switch (edp_link_params->vswing) {
|
||||
case 0:
|
||||
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400;
|
||||
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
|
||||
break;
|
||||
case 1:
|
||||
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600;
|
||||
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_1;
|
||||
break;
|
||||
case 2:
|
||||
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800;
|
||||
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
|
||||
break;
|
||||
case 3:
|
||||
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200;
|
||||
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
|
||||
break;
|
||||
}
|
||||
DRM_DEBUG_KMS("VBT reports EDP: VSwing %d, Preemph %d\n",
|
||||
|
@ -60,16 +60,297 @@
|
||||
|
||||
#define NS2501_REGC 0x0c
|
||||
|
||||
enum {
|
||||
MODE_640x480,
|
||||
MODE_800x600,
|
||||
MODE_1024x768,
|
||||
};
|
||||
|
||||
struct ns2501_reg {
|
||||
uint8_t offset;
|
||||
uint8_t value;
|
||||
};
|
||||
|
||||
/*
|
||||
* Magic values based on what the BIOS on
|
||||
* Fujitsu-Siemens Lifebook S6010 programs (1024x768 panel).
|
||||
*/
|
||||
static const struct ns2501_reg regs_1024x768[][86] = {
|
||||
[MODE_640x480] = {
|
||||
[0] = { .offset = 0x0a, .value = 0x81, },
|
||||
[1] = { .offset = 0x18, .value = 0x07, },
|
||||
[2] = { .offset = 0x19, .value = 0x00, },
|
||||
[3] = { .offset = 0x1a, .value = 0x00, },
|
||||
[4] = { .offset = 0x1b, .value = 0x11, },
|
||||
[5] = { .offset = 0x1c, .value = 0x54, },
|
||||
[6] = { .offset = 0x1d, .value = 0x03, },
|
||||
[7] = { .offset = 0x1e, .value = 0x02, },
|
||||
[8] = { .offset = 0xf3, .value = 0x90, },
|
||||
[9] = { .offset = 0xf9, .value = 0x00, },
|
||||
[10] = { .offset = 0xc1, .value = 0x90, },
|
||||
[11] = { .offset = 0xc2, .value = 0x00, },
|
||||
[12] = { .offset = 0xc3, .value = 0x0f, },
|
||||
[13] = { .offset = 0xc4, .value = 0x03, },
|
||||
[14] = { .offset = 0xc5, .value = 0x16, },
|
||||
[15] = { .offset = 0xc6, .value = 0x00, },
|
||||
[16] = { .offset = 0xc7, .value = 0x02, },
|
||||
[17] = { .offset = 0xc8, .value = 0x02, },
|
||||
[18] = { .offset = 0xf4, .value = 0x00, },
|
||||
[19] = { .offset = 0x80, .value = 0xff, },
|
||||
[20] = { .offset = 0x81, .value = 0x07, },
|
||||
[21] = { .offset = 0x82, .value = 0x3d, },
|
||||
[22] = { .offset = 0x83, .value = 0x05, },
|
||||
[23] = { .offset = 0x94, .value = 0x00, },
|
||||
[24] = { .offset = 0x95, .value = 0x00, },
|
||||
[25] = { .offset = 0x96, .value = 0x05, },
|
||||
[26] = { .offset = 0x97, .value = 0x00, },
|
||||
[27] = { .offset = 0x9a, .value = 0x88, },
|
||||
[28] = { .offset = 0x9b, .value = 0x00, },
|
||||
[29] = { .offset = 0x98, .value = 0x00, },
|
||||
[30] = { .offset = 0x99, .value = 0x00, },
|
||||
[31] = { .offset = 0xf7, .value = 0x88, },
|
||||
[32] = { .offset = 0xf8, .value = 0x0a, },
|
||||
[33] = { .offset = 0x9c, .value = 0x24, },
|
||||
[34] = { .offset = 0x9d, .value = 0x00, },
|
||||
[35] = { .offset = 0x9e, .value = 0x25, },
|
||||
[36] = { .offset = 0x9f, .value = 0x03, },
|
||||
[37] = { .offset = 0xa0, .value = 0x28, },
|
||||
[38] = { .offset = 0xa1, .value = 0x01, },
|
||||
[39] = { .offset = 0xa2, .value = 0x28, },
|
||||
[40] = { .offset = 0xa3, .value = 0x05, },
|
||||
[41] = { .offset = 0xb6, .value = 0x09, },
|
||||
[42] = { .offset = 0xb8, .value = 0x00, },
|
||||
[43] = { .offset = 0xb9, .value = 0xa0, },
|
||||
[44] = { .offset = 0xba, .value = 0x00, },
|
||||
[45] = { .offset = 0xbb, .value = 0x20, },
|
||||
[46] = { .offset = 0x10, .value = 0x00, },
|
||||
[47] = { .offset = 0x11, .value = 0xa0, },
|
||||
[48] = { .offset = 0x12, .value = 0x02, },
|
||||
[49] = { .offset = 0x20, .value = 0x00, },
|
||||
[50] = { .offset = 0x22, .value = 0x00, },
|
||||
[51] = { .offset = 0x23, .value = 0x00, },
|
||||
[52] = { .offset = 0x24, .value = 0x00, },
|
||||
[53] = { .offset = 0x25, .value = 0x00, },
|
||||
[54] = { .offset = 0x8c, .value = 0x10, },
|
||||
[55] = { .offset = 0x8d, .value = 0x02, },
|
||||
[56] = { .offset = 0x8e, .value = 0x10, },
|
||||
[57] = { .offset = 0x8f, .value = 0x00, },
|
||||
[58] = { .offset = 0x90, .value = 0xff, },
|
||||
[59] = { .offset = 0x91, .value = 0x07, },
|
||||
[60] = { .offset = 0x92, .value = 0xa0, },
|
||||
[61] = { .offset = 0x93, .value = 0x02, },
|
||||
[62] = { .offset = 0xa5, .value = 0x00, },
|
||||
[63] = { .offset = 0xa6, .value = 0x00, },
|
||||
[64] = { .offset = 0xa7, .value = 0x00, },
|
||||
[65] = { .offset = 0xa8, .value = 0x00, },
|
||||
[66] = { .offset = 0xa9, .value = 0x04, },
|
||||
[67] = { .offset = 0xaa, .value = 0x70, },
|
||||
[68] = { .offset = 0xab, .value = 0x4f, },
|
||||
[69] = { .offset = 0xac, .value = 0x00, },
|
||||
[70] = { .offset = 0xa4, .value = 0x84, },
|
||||
[71] = { .offset = 0x7e, .value = 0x18, },
|
||||
[72] = { .offset = 0x84, .value = 0x00, },
|
||||
[73] = { .offset = 0x85, .value = 0x00, },
|
||||
[74] = { .offset = 0x86, .value = 0x00, },
|
||||
[75] = { .offset = 0x87, .value = 0x00, },
|
||||
[76] = { .offset = 0x88, .value = 0x00, },
|
||||
[77] = { .offset = 0x89, .value = 0x00, },
|
||||
[78] = { .offset = 0x8a, .value = 0x00, },
|
||||
[79] = { .offset = 0x8b, .value = 0x00, },
|
||||
[80] = { .offset = 0x26, .value = 0x00, },
|
||||
[81] = { .offset = 0x27, .value = 0x00, },
|
||||
[82] = { .offset = 0xad, .value = 0x00, },
|
||||
[83] = { .offset = 0x08, .value = 0x30, }, /* 0x31 */
|
||||
[84] = { .offset = 0x41, .value = 0x00, },
|
||||
[85] = { .offset = 0xc0, .value = 0x05, },
|
||||
},
|
||||
[MODE_800x600] = {
|
||||
[0] = { .offset = 0x0a, .value = 0x81, },
|
||||
[1] = { .offset = 0x18, .value = 0x07, },
|
||||
[2] = { .offset = 0x19, .value = 0x00, },
|
||||
[3] = { .offset = 0x1a, .value = 0x00, },
|
||||
[4] = { .offset = 0x1b, .value = 0x19, },
|
||||
[5] = { .offset = 0x1c, .value = 0x64, },
|
||||
[6] = { .offset = 0x1d, .value = 0x02, },
|
||||
[7] = { .offset = 0x1e, .value = 0x02, },
|
||||
[8] = { .offset = 0xf3, .value = 0x90, },
|
||||
[9] = { .offset = 0xf9, .value = 0x00, },
|
||||
[10] = { .offset = 0xc1, .value = 0xd7, },
|
||||
[11] = { .offset = 0xc2, .value = 0x00, },
|
||||
[12] = { .offset = 0xc3, .value = 0xf8, },
|
||||
[13] = { .offset = 0xc4, .value = 0x03, },
|
||||
[14] = { .offset = 0xc5, .value = 0x1a, },
|
||||
[15] = { .offset = 0xc6, .value = 0x00, },
|
||||
[16] = { .offset = 0xc7, .value = 0x73, },
|
||||
[17] = { .offset = 0xc8, .value = 0x02, },
|
||||
[18] = { .offset = 0xf4, .value = 0x00, },
|
||||
[19] = { .offset = 0x80, .value = 0x27, },
|
||||
[20] = { .offset = 0x81, .value = 0x03, },
|
||||
[21] = { .offset = 0x82, .value = 0x41, },
|
||||
[22] = { .offset = 0x83, .value = 0x05, },
|
||||
[23] = { .offset = 0x94, .value = 0x00, },
|
||||
[24] = { .offset = 0x95, .value = 0x00, },
|
||||
[25] = { .offset = 0x96, .value = 0x05, },
|
||||
[26] = { .offset = 0x97, .value = 0x00, },
|
||||
[27] = { .offset = 0x9a, .value = 0x88, },
|
||||
[28] = { .offset = 0x9b, .value = 0x00, },
|
||||
[29] = { .offset = 0x98, .value = 0x00, },
|
||||
[30] = { .offset = 0x99, .value = 0x00, },
|
||||
[31] = { .offset = 0xf7, .value = 0x88, },
|
||||
[32] = { .offset = 0xf8, .value = 0x06, },
|
||||
[33] = { .offset = 0x9c, .value = 0x23, },
|
||||
[34] = { .offset = 0x9d, .value = 0x00, },
|
||||
[35] = { .offset = 0x9e, .value = 0x25, },
|
||||
[36] = { .offset = 0x9f, .value = 0x03, },
|
||||
[37] = { .offset = 0xa0, .value = 0x28, },
|
||||
[38] = { .offset = 0xa1, .value = 0x01, },
|
||||
[39] = { .offset = 0xa2, .value = 0x28, },
|
||||
[40] = { .offset = 0xa3, .value = 0x05, },
|
||||
[41] = { .offset = 0xb6, .value = 0x09, },
|
||||
[42] = { .offset = 0xb8, .value = 0x30, },
|
||||
[43] = { .offset = 0xb9, .value = 0xc8, },
|
||||
[44] = { .offset = 0xba, .value = 0x00, },
|
||||
[45] = { .offset = 0xbb, .value = 0x20, },
|
||||
[46] = { .offset = 0x10, .value = 0x20, },
|
||||
[47] = { .offset = 0x11, .value = 0xc8, },
|
||||
[48] = { .offset = 0x12, .value = 0x02, },
|
||||
[49] = { .offset = 0x20, .value = 0x00, },
|
||||
[50] = { .offset = 0x22, .value = 0x00, },
|
||||
[51] = { .offset = 0x23, .value = 0x00, },
|
||||
[52] = { .offset = 0x24, .value = 0x00, },
|
||||
[53] = { .offset = 0x25, .value = 0x00, },
|
||||
[54] = { .offset = 0x8c, .value = 0x10, },
|
||||
[55] = { .offset = 0x8d, .value = 0x02, },
|
||||
[56] = { .offset = 0x8e, .value = 0x04, },
|
||||
[57] = { .offset = 0x8f, .value = 0x00, },
|
||||
[58] = { .offset = 0x90, .value = 0xff, },
|
||||
[59] = { .offset = 0x91, .value = 0x07, },
|
||||
[60] = { .offset = 0x92, .value = 0xa0, },
|
||||
[61] = { .offset = 0x93, .value = 0x02, },
|
||||
[62] = { .offset = 0xa5, .value = 0x00, },
|
||||
[63] = { .offset = 0xa6, .value = 0x00, },
|
||||
[64] = { .offset = 0xa7, .value = 0x00, },
|
||||
[65] = { .offset = 0xa8, .value = 0x00, },
|
||||
[66] = { .offset = 0xa9, .value = 0x83, },
|
||||
[67] = { .offset = 0xaa, .value = 0x40, },
|
||||
[68] = { .offset = 0xab, .value = 0x32, },
|
||||
[69] = { .offset = 0xac, .value = 0x00, },
|
||||
[70] = { .offset = 0xa4, .value = 0x80, },
|
||||
[71] = { .offset = 0x7e, .value = 0x18, },
|
||||
[72] = { .offset = 0x84, .value = 0x00, },
|
||||
[73] = { .offset = 0x85, .value = 0x00, },
|
||||
[74] = { .offset = 0x86, .value = 0x00, },
|
||||
[75] = { .offset = 0x87, .value = 0x00, },
|
||||
[76] = { .offset = 0x88, .value = 0x00, },
|
||||
[77] = { .offset = 0x89, .value = 0x00, },
|
||||
[78] = { .offset = 0x8a, .value = 0x00, },
|
||||
[79] = { .offset = 0x8b, .value = 0x00, },
|
||||
[80] = { .offset = 0x26, .value = 0x00, },
|
||||
[81] = { .offset = 0x27, .value = 0x00, },
|
||||
[82] = { .offset = 0xad, .value = 0x00, },
|
||||
[83] = { .offset = 0x08, .value = 0x30, }, /* 0x31 */
|
||||
[84] = { .offset = 0x41, .value = 0x00, },
|
||||
[85] = { .offset = 0xc0, .value = 0x07, },
|
||||
},
|
||||
[MODE_1024x768] = {
|
||||
[0] = { .offset = 0x0a, .value = 0x81, },
|
||||
[1] = { .offset = 0x18, .value = 0x07, },
|
||||
[2] = { .offset = 0x19, .value = 0x00, },
|
||||
[3] = { .offset = 0x1a, .value = 0x00, },
|
||||
[4] = { .offset = 0x1b, .value = 0x11, },
|
||||
[5] = { .offset = 0x1c, .value = 0x54, },
|
||||
[6] = { .offset = 0x1d, .value = 0x03, },
|
||||
[7] = { .offset = 0x1e, .value = 0x02, },
|
||||
[8] = { .offset = 0xf3, .value = 0x90, },
|
||||
[9] = { .offset = 0xf9, .value = 0x00, },
|
||||
[10] = { .offset = 0xc1, .value = 0x90, },
|
||||
[11] = { .offset = 0xc2, .value = 0x00, },
|
||||
[12] = { .offset = 0xc3, .value = 0x0f, },
|
||||
[13] = { .offset = 0xc4, .value = 0x03, },
|
||||
[14] = { .offset = 0xc5, .value = 0x16, },
|
||||
[15] = { .offset = 0xc6, .value = 0x00, },
|
||||
[16] = { .offset = 0xc7, .value = 0x02, },
|
||||
[17] = { .offset = 0xc8, .value = 0x02, },
|
||||
[18] = { .offset = 0xf4, .value = 0x00, },
|
||||
[19] = { .offset = 0x80, .value = 0xff, },
|
||||
[20] = { .offset = 0x81, .value = 0x07, },
|
||||
[21] = { .offset = 0x82, .value = 0x3d, },
|
||||
[22] = { .offset = 0x83, .value = 0x05, },
|
||||
[23] = { .offset = 0x94, .value = 0x00, },
|
||||
[24] = { .offset = 0x95, .value = 0x00, },
|
||||
[25] = { .offset = 0x96, .value = 0x05, },
|
||||
[26] = { .offset = 0x97, .value = 0x00, },
|
||||
[27] = { .offset = 0x9a, .value = 0x88, },
|
||||
[28] = { .offset = 0x9b, .value = 0x00, },
|
||||
[29] = { .offset = 0x98, .value = 0x00, },
|
||||
[30] = { .offset = 0x99, .value = 0x00, },
|
||||
[31] = { .offset = 0xf7, .value = 0x88, },
|
||||
[32] = { .offset = 0xf8, .value = 0x0a, },
|
||||
[33] = { .offset = 0x9c, .value = 0x24, },
|
||||
[34] = { .offset = 0x9d, .value = 0x00, },
|
||||
[35] = { .offset = 0x9e, .value = 0x25, },
|
||||
[36] = { .offset = 0x9f, .value = 0x03, },
|
||||
[37] = { .offset = 0xa0, .value = 0x28, },
|
||||
[38] = { .offset = 0xa1, .value = 0x01, },
|
||||
[39] = { .offset = 0xa2, .value = 0x28, },
|
||||
[40] = { .offset = 0xa3, .value = 0x05, },
|
||||
[41] = { .offset = 0xb6, .value = 0x09, },
|
||||
[42] = { .offset = 0xb8, .value = 0x00, },
|
||||
[43] = { .offset = 0xb9, .value = 0xa0, },
|
||||
[44] = { .offset = 0xba, .value = 0x00, },
|
||||
[45] = { .offset = 0xbb, .value = 0x20, },
|
||||
[46] = { .offset = 0x10, .value = 0x00, },
|
||||
[47] = { .offset = 0x11, .value = 0xa0, },
|
||||
[48] = { .offset = 0x12, .value = 0x02, },
|
||||
[49] = { .offset = 0x20, .value = 0x00, },
|
||||
[50] = { .offset = 0x22, .value = 0x00, },
|
||||
[51] = { .offset = 0x23, .value = 0x00, },
|
||||
[52] = { .offset = 0x24, .value = 0x00, },
|
||||
[53] = { .offset = 0x25, .value = 0x00, },
|
||||
[54] = { .offset = 0x8c, .value = 0x10, },
|
||||
[55] = { .offset = 0x8d, .value = 0x02, },
|
||||
[56] = { .offset = 0x8e, .value = 0x10, },
|
||||
[57] = { .offset = 0x8f, .value = 0x00, },
|
||||
[58] = { .offset = 0x90, .value = 0xff, },
|
||||
[59] = { .offset = 0x91, .value = 0x07, },
|
||||
[60] = { .offset = 0x92, .value = 0xa0, },
|
||||
[61] = { .offset = 0x93, .value = 0x02, },
|
||||
[62] = { .offset = 0xa5, .value = 0x00, },
|
||||
[63] = { .offset = 0xa6, .value = 0x00, },
|
||||
[64] = { .offset = 0xa7, .value = 0x00, },
|
||||
[65] = { .offset = 0xa8, .value = 0x00, },
|
||||
[66] = { .offset = 0xa9, .value = 0x04, },
|
||||
[67] = { .offset = 0xaa, .value = 0x70, },
|
||||
[68] = { .offset = 0xab, .value = 0x4f, },
|
||||
[69] = { .offset = 0xac, .value = 0x00, },
|
||||
[70] = { .offset = 0xa4, .value = 0x84, },
|
||||
[71] = { .offset = 0x7e, .value = 0x18, },
|
||||
[72] = { .offset = 0x84, .value = 0x00, },
|
||||
[73] = { .offset = 0x85, .value = 0x00, },
|
||||
[74] = { .offset = 0x86, .value = 0x00, },
|
||||
[75] = { .offset = 0x87, .value = 0x00, },
|
||||
[76] = { .offset = 0x88, .value = 0x00, },
|
||||
[77] = { .offset = 0x89, .value = 0x00, },
|
||||
[78] = { .offset = 0x8a, .value = 0x00, },
|
||||
[79] = { .offset = 0x8b, .value = 0x00, },
|
||||
[80] = { .offset = 0x26, .value = 0x00, },
|
||||
[81] = { .offset = 0x27, .value = 0x00, },
|
||||
[82] = { .offset = 0xad, .value = 0x00, },
|
||||
[83] = { .offset = 0x08, .value = 0x34, }, /* 0x35 */
|
||||
[84] = { .offset = 0x41, .value = 0x00, },
|
||||
[85] = { .offset = 0xc0, .value = 0x01, },
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ns2501_reg regs_init[] = {
|
||||
[0] = { .offset = 0x35, .value = 0xff, },
|
||||
[1] = { .offset = 0x34, .value = 0x00, },
|
||||
[2] = { .offset = 0x08, .value = 0x30, },
|
||||
};
|
||||
|
||||
struct ns2501_priv {
|
||||
//I2CDevRec d;
|
||||
bool quiet;
|
||||
int reg_8_shadow;
|
||||
int reg_8_set;
|
||||
// Shadow registers for i915
|
||||
int dvoc;
|
||||
int pll_a;
|
||||
int srcdim;
|
||||
int fw_blc;
|
||||
const struct ns2501_reg *regs;
|
||||
};
|
||||
|
||||
#define NSPTR(d) ((NS2501Ptr)(d->DriverPrivate.ptr))
|
||||
@ -205,11 +486,9 @@ static bool ns2501_init(struct intel_dvo_device *dvo,
|
||||
goto out;
|
||||
}
|
||||
ns->quiet = false;
|
||||
ns->reg_8_set = 0;
|
||||
ns->reg_8_shadow =
|
||||
NS2501_8_PD | NS2501_8_BPAS | NS2501_8_VEN | NS2501_8_HEN;
|
||||
|
||||
DRM_DEBUG_KMS("init ns2501 dvo controller successfully!\n");
|
||||
|
||||
return true;
|
||||
|
||||
out:
|
||||
@ -242,9 +521,9 @@ static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo,
|
||||
* of the panel in here so we could always accept it
|
||||
* by disabling the scaler.
|
||||
*/
|
||||
if ((mode->hdisplay == 800 && mode->vdisplay == 600) ||
|
||||
(mode->hdisplay == 640 && mode->vdisplay == 480) ||
|
||||
(mode->hdisplay == 1024 && mode->vdisplay == 768)) {
|
||||
if ((mode->hdisplay == 640 && mode->vdisplay == 480 && mode->clock == 25175) ||
|
||||
(mode->hdisplay == 800 && mode->vdisplay == 600 && mode->clock == 40000) ||
|
||||
(mode->hdisplay == 1024 && mode->vdisplay == 768 && mode->clock == 65000)) {
|
||||
return MODE_OK;
|
||||
} else {
|
||||
return MODE_ONE_SIZE; /* Is this a reasonable error? */
|
||||
@ -255,180 +534,30 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
bool ok;
|
||||
int retries = 10;
|
||||
struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
|
||||
int mode_idx, i;
|
||||
|
||||
DRM_DEBUG_KMS
|
||||
("set mode (hdisplay=%d,htotal=%d,vdisplay=%d,vtotal=%d).\n",
|
||||
mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal);
|
||||
|
||||
/*
|
||||
* Where do I find the native resolution for which scaling is not required???
|
||||
*
|
||||
* First trigger the DVO on as otherwise the chip does not appear on the i2c
|
||||
* bus.
|
||||
*/
|
||||
do {
|
||||
ok = true;
|
||||
if (mode->hdisplay == 640 && mode->vdisplay == 480)
|
||||
mode_idx = MODE_640x480;
|
||||
else if (mode->hdisplay == 800 && mode->vdisplay == 600)
|
||||
mode_idx = MODE_800x600;
|
||||
else if (mode->hdisplay == 1024 && mode->vdisplay == 768)
|
||||
mode_idx = MODE_1024x768;
|
||||
else
|
||||
return;
|
||||
|
||||
if (mode->hdisplay == 800 && mode->vdisplay == 600) {
|
||||
/* mode 277 */
|
||||
ns->reg_8_shadow &= ~NS2501_8_BPAS;
|
||||
DRM_DEBUG_KMS("switching to 800x600\n");
|
||||
/* Hopefully doing it every time won't hurt... */
|
||||
for (i = 0; i < ARRAY_SIZE(regs_init); i++)
|
||||
ns2501_writeb(dvo, regs_init[i].offset, regs_init[i].value);
|
||||
|
||||
/*
|
||||
* No, I do not know where this data comes from.
|
||||
* It is just what the video bios left in the DVO, so
|
||||
* I'm just copying it here over.
|
||||
* This also means that I cannot support any other modes
|
||||
* except the ones supported by the bios.
|
||||
*/
|
||||
ok &= ns2501_writeb(dvo, 0x11, 0xc8); // 0xc7 also works.
|
||||
ok &= ns2501_writeb(dvo, 0x1b, 0x19);
|
||||
ok &= ns2501_writeb(dvo, 0x1c, 0x62); // VBIOS left 0x64 here, but 0x62 works nicer
|
||||
ok &= ns2501_writeb(dvo, 0x1d, 0x02);
|
||||
ns->regs = regs_1024x768[mode_idx];
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x34, 0x03);
|
||||
ok &= ns2501_writeb(dvo, 0x35, 0xff);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x80, 0x27);
|
||||
ok &= ns2501_writeb(dvo, 0x81, 0x03);
|
||||
ok &= ns2501_writeb(dvo, 0x82, 0x41);
|
||||
ok &= ns2501_writeb(dvo, 0x83, 0x05);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x8d, 0x02);
|
||||
ok &= ns2501_writeb(dvo, 0x8e, 0x04);
|
||||
ok &= ns2501_writeb(dvo, 0x8f, 0x00);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x90, 0xfe); /* vertical. VBIOS left 0xff here, but 0xfe works better */
|
||||
ok &= ns2501_writeb(dvo, 0x91, 0x07);
|
||||
ok &= ns2501_writeb(dvo, 0x94, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0x95, 0x00);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x96, 0x00);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x99, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0x9a, 0x88);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x9c, 0x23); /* Looks like first and last line of the image. */
|
||||
ok &= ns2501_writeb(dvo, 0x9d, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0x9e, 0x25);
|
||||
ok &= ns2501_writeb(dvo, 0x9f, 0x03);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xa4, 0x80);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xb6, 0x00);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xb9, 0xc8); /* horizontal? */
|
||||
ok &= ns2501_writeb(dvo, 0xba, 0x00); /* horizontal? */
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc0, 0x05); /* horizontal? */
|
||||
ok &= ns2501_writeb(dvo, 0xc1, 0xd7);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc2, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0xc3, 0xf8);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc4, 0x03);
|
||||
ok &= ns2501_writeb(dvo, 0xc5, 0x1a);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc6, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0xc7, 0x73);
|
||||
ok &= ns2501_writeb(dvo, 0xc8, 0x02);
|
||||
|
||||
} else if (mode->hdisplay == 640 && mode->vdisplay == 480) {
|
||||
/* mode 274 */
|
||||
DRM_DEBUG_KMS("switching to 640x480\n");
|
||||
/*
|
||||
* No, I do not know where this data comes from.
|
||||
* It is just what the video bios left in the DVO, so
|
||||
* I'm just copying it here over.
|
||||
* This also means that I cannot support any other modes
|
||||
* except the ones supported by the bios.
|
||||
*/
|
||||
ns->reg_8_shadow &= ~NS2501_8_BPAS;
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x11, 0xa0);
|
||||
ok &= ns2501_writeb(dvo, 0x1b, 0x11);
|
||||
ok &= ns2501_writeb(dvo, 0x1c, 0x54);
|
||||
ok &= ns2501_writeb(dvo, 0x1d, 0x03);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x34, 0x03);
|
||||
ok &= ns2501_writeb(dvo, 0x35, 0xff);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x80, 0xff);
|
||||
ok &= ns2501_writeb(dvo, 0x81, 0x07);
|
||||
ok &= ns2501_writeb(dvo, 0x82, 0x3d);
|
||||
ok &= ns2501_writeb(dvo, 0x83, 0x05);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x8d, 0x02);
|
||||
ok &= ns2501_writeb(dvo, 0x8e, 0x10);
|
||||
ok &= ns2501_writeb(dvo, 0x8f, 0x00);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x90, 0xff); /* vertical */
|
||||
ok &= ns2501_writeb(dvo, 0x91, 0x07);
|
||||
ok &= ns2501_writeb(dvo, 0x94, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0x95, 0x00);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x96, 0x05);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x99, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0x9a, 0x88);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0x9c, 0x24);
|
||||
ok &= ns2501_writeb(dvo, 0x9d, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0x9e, 0x25);
|
||||
ok &= ns2501_writeb(dvo, 0x9f, 0x03);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xa4, 0x84);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xb6, 0x09);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xb9, 0xa0); /* horizontal? */
|
||||
ok &= ns2501_writeb(dvo, 0xba, 0x00); /* horizontal? */
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc0, 0x05); /* horizontal? */
|
||||
ok &= ns2501_writeb(dvo, 0xc1, 0x90);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc2, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0xc3, 0x0f);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc4, 0x03);
|
||||
ok &= ns2501_writeb(dvo, 0xc5, 0x16);
|
||||
|
||||
ok &= ns2501_writeb(dvo, 0xc6, 0x00);
|
||||
ok &= ns2501_writeb(dvo, 0xc7, 0x02);
|
||||
ok &= ns2501_writeb(dvo, 0xc8, 0x02);
|
||||
|
||||
} else if (mode->hdisplay == 1024 && mode->vdisplay == 768) {
|
||||
/* mode 280 */
|
||||
DRM_DEBUG_KMS("switching to 1024x768\n");
|
||||
/*
|
||||
* This might or might not work, actually. I'm silently
|
||||
* assuming here that the native panel resolution is
|
||||
* 1024x768. If not, then this leaves the scaler disabled
|
||||
* generating a picture that is likely not the expected.
|
||||
*
|
||||
* Problem is that I do not know where to take the panel
|
||||
* dimensions from.
|
||||
*
|
||||
* Enable the bypass, scaling not required.
|
||||
*
|
||||
* The scaler registers are irrelevant here....
|
||||
*
|
||||
*/
|
||||
ns->reg_8_shadow |= NS2501_8_BPAS;
|
||||
ok &= ns2501_writeb(dvo, 0x37, 0x44);
|
||||
} else {
|
||||
/*
|
||||
* Data not known. Bummer!
|
||||
* Hopefully, the code should not go here
|
||||
* as mode_OK delivered no other modes.
|
||||
*/
|
||||
ns->reg_8_shadow |= NS2501_8_BPAS;
|
||||
}
|
||||
ok &= ns2501_writeb(dvo, NS2501_REG8, ns->reg_8_shadow);
|
||||
} while (!ok && retries--);
|
||||
for (i = 0; i < 84; i++)
|
||||
ns2501_writeb(dvo, ns->regs[i].offset, ns->regs[i].value);
|
||||
}
|
||||
|
||||
/* set the NS2501 power state */
|
||||
@ -439,62 +568,48 @@ static bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
|
||||
if (!ns2501_readb(dvo, NS2501_REG8, &ch))
|
||||
return false;
|
||||
|
||||
if (ch & NS2501_8_PD)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
return ch & NS2501_8_PD;
|
||||
}
|
||||
|
||||
/* set the NS2501 power state */
|
||||
static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
|
||||
{
|
||||
bool ok;
|
||||
int retries = 10;
|
||||
struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
|
||||
unsigned char ch;
|
||||
|
||||
DRM_DEBUG_KMS("Trying set the dpms of the DVO to %i\n", enable);
|
||||
|
||||
ch = ns->reg_8_shadow;
|
||||
if (enable) {
|
||||
if (WARN_ON(ns->regs[83].offset != 0x08 ||
|
||||
ns->regs[84].offset != 0x41 ||
|
||||
ns->regs[85].offset != 0xc0))
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
ch |= NS2501_8_PD;
|
||||
else
|
||||
ch &= ~NS2501_8_PD;
|
||||
ns2501_writeb(dvo, 0xc0, ns->regs[85].value | 0x08);
|
||||
|
||||
if (ns->reg_8_set == 0 || ns->reg_8_shadow != ch) {
|
||||
ns->reg_8_set = 1;
|
||||
ns->reg_8_shadow = ch;
|
||||
ns2501_writeb(dvo, 0x41, ns->regs[84].value);
|
||||
|
||||
do {
|
||||
ok = true;
|
||||
ok &= ns2501_writeb(dvo, NS2501_REG8, ch);
|
||||
ok &=
|
||||
ns2501_writeb(dvo, 0x34,
|
||||
enable ? 0x03 : 0x00);
|
||||
ok &=
|
||||
ns2501_writeb(dvo, 0x35,
|
||||
enable ? 0xff : 0x00);
|
||||
} while (!ok && retries--);
|
||||
ns2501_writeb(dvo, 0x34, 0x01);
|
||||
msleep(15);
|
||||
|
||||
ns2501_writeb(dvo, 0x08, 0x35);
|
||||
if (!(ns->regs[83].value & NS2501_8_BPAS))
|
||||
ns2501_writeb(dvo, 0x08, 0x31);
|
||||
msleep(200);
|
||||
|
||||
ns2501_writeb(dvo, 0x34, 0x03);
|
||||
|
||||
ns2501_writeb(dvo, 0xc0, ns->regs[85].value);
|
||||
} else {
|
||||
ns2501_writeb(dvo, 0x34, 0x01);
|
||||
msleep(200);
|
||||
|
||||
ns2501_writeb(dvo, 0x08, 0x34);
|
||||
msleep(15);
|
||||
|
||||
ns2501_writeb(dvo, 0x34, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
static void ns2501_dump_regs(struct intel_dvo_device *dvo)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
ns2501_readb(dvo, NS2501_FREQ_LO, &val);
|
||||
DRM_DEBUG_KMS("NS2501_FREQ_LO: 0x%02x\n", val);
|
||||
ns2501_readb(dvo, NS2501_FREQ_HI, &val);
|
||||
DRM_DEBUG_KMS("NS2501_FREQ_HI: 0x%02x\n", val);
|
||||
ns2501_readb(dvo, NS2501_REG8, &val);
|
||||
DRM_DEBUG_KMS("NS2501_REG8: 0x%02x\n", val);
|
||||
ns2501_readb(dvo, NS2501_REG9, &val);
|
||||
DRM_DEBUG_KMS("NS2501_REG9: 0x%02x\n", val);
|
||||
ns2501_readb(dvo, NS2501_REGC, &val);
|
||||
DRM_DEBUG_KMS("NS2501_REGC: 0x%02x\n", val);
|
||||
}
|
||||
|
||||
static void ns2501_destroy(struct intel_dvo_device *dvo)
|
||||
{
|
||||
struct ns2501_priv *ns = dvo->dev_priv;
|
||||
@ -512,6 +627,5 @@ struct intel_dvo_dev_ops ns2501_ops = {
|
||||
.mode_set = ns2501_mode_set,
|
||||
.dpms = ns2501_dpms,
|
||||
.get_hw_state = ns2501_get_hw_state,
|
||||
.dump_regs = ns2501_dump_regs,
|
||||
.destroy = ns2501_destroy,
|
||||
};
|
||||
|
@ -136,7 +136,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
|
||||
obj->last_read_seqno,
|
||||
obj->last_write_seqno,
|
||||
obj->last_fenced_seqno,
|
||||
i915_cache_level_str(obj->cache_level),
|
||||
i915_cache_level_str(to_i915(obj->base.dev), obj->cache_level),
|
||||
obj->dirty ? " dirty" : "",
|
||||
obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
|
||||
if (obj->base.name)
|
||||
@ -515,6 +515,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long flags;
|
||||
struct intel_crtc *crtc;
|
||||
int ret;
|
||||
@ -534,6 +535,8 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
|
||||
seq_printf(m, "No flip due on pipe %c (plane %c)\n",
|
||||
pipe, plane);
|
||||
} else {
|
||||
u32 addr;
|
||||
|
||||
if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
|
||||
seq_printf(m, "Flip queued on pipe %c (plane %c)\n",
|
||||
pipe, plane);
|
||||
@ -541,23 +544,35 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
|
||||
seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n",
|
||||
pipe, plane);
|
||||
}
|
||||
if (work->flip_queued_ring) {
|
||||
seq_printf(m, "Flip queued on %s at seqno %u, next seqno %u [current breadcrumb %u], completed? %d\n",
|
||||
work->flip_queued_ring->name,
|
||||
work->flip_queued_seqno,
|
||||
dev_priv->next_seqno,
|
||||
work->flip_queued_ring->get_seqno(work->flip_queued_ring, true),
|
||||
i915_seqno_passed(work->flip_queued_ring->get_seqno(work->flip_queued_ring, true),
|
||||
work->flip_queued_seqno));
|
||||
} else
|
||||
seq_printf(m, "Flip not associated with any ring\n");
|
||||
seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
|
||||
work->flip_queued_vblank,
|
||||
work->flip_ready_vblank,
|
||||
drm_vblank_count(dev, crtc->pipe));
|
||||
if (work->enable_stall_check)
|
||||
seq_puts(m, "Stall check enabled, ");
|
||||
else
|
||||
seq_puts(m, "Stall check waiting for page flip ioctl, ");
|
||||
seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
|
||||
|
||||
if (work->old_fb_obj) {
|
||||
struct drm_i915_gem_object *obj = work->old_fb_obj;
|
||||
if (obj)
|
||||
seq_printf(m, "Old framebuffer gtt_offset 0x%08lx\n",
|
||||
i915_gem_obj_ggtt_offset(obj));
|
||||
}
|
||||
if (INTEL_INFO(dev)->gen >= 4)
|
||||
addr = I915_HI_DISPBASE(I915_READ(DSPSURF(crtc->plane)));
|
||||
else
|
||||
addr = I915_READ(DSPADDR(crtc->plane));
|
||||
seq_printf(m, "Current scanout address 0x%08x\n", addr);
|
||||
|
||||
if (work->pending_flip_obj) {
|
||||
struct drm_i915_gem_object *obj = work->pending_flip_obj;
|
||||
if (obj)
|
||||
seq_printf(m, "New framebuffer gtt_offset 0x%08lx\n",
|
||||
i915_gem_obj_ggtt_offset(obj));
|
||||
seq_printf(m, "New framebuffer address 0x%08lx\n", (long)work->gtt_offset);
|
||||
seq_printf(m, "MMIO update completed? %d\n", addr == work->gtt_offset);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
@ -650,7 +665,6 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
|
||||
intel_runtime_pm_get(dev_priv);
|
||||
|
||||
if (IS_CHERRYVIEW(dev)) {
|
||||
int i;
|
||||
seq_printf(m, "Master Interrupt Control:\t%08x\n",
|
||||
I915_READ(GEN8_MASTER_IRQ));
|
||||
|
||||
@ -662,7 +676,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
|
||||
I915_READ(VLV_IIR_RW));
|
||||
seq_printf(m, "Display IMR:\t%08x\n",
|
||||
I915_READ(VLV_IMR));
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
seq_printf(m, "Pipe %c stat:\t%08x\n",
|
||||
pipe_name(pipe),
|
||||
I915_READ(PIPESTAT(pipe)));
|
||||
@ -702,7 +716,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
|
||||
i, I915_READ(GEN8_GT_IER(i)));
|
||||
}
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
if (!intel_display_power_enabled(dev_priv,
|
||||
POWER_DOMAIN_PIPE(pipe))) {
|
||||
seq_printf(m, "Pipe %c power disabled\n",
|
||||
@ -749,7 +763,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
|
||||
I915_READ(VLV_IIR_RW));
|
||||
seq_printf(m, "Display IMR:\t%08x\n",
|
||||
I915_READ(VLV_IMR));
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
seq_printf(m, "Pipe %c stat:\t%08x\n",
|
||||
pipe_name(pipe),
|
||||
I915_READ(PIPESTAT(pipe)));
|
||||
@ -785,7 +799,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
|
||||
I915_READ(IIR));
|
||||
seq_printf(m, "Interrupt mask: %08x\n",
|
||||
I915_READ(IMR));
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
seq_printf(m, "Pipe %c stat: %08x\n",
|
||||
pipe_name(pipe),
|
||||
I915_READ(PIPESTAT(pipe)));
|
||||
@ -933,7 +947,7 @@ static ssize_t i915_error_state_read(struct file *file, char __user *userbuf,
|
||||
ssize_t ret_count = 0;
|
||||
int ret;
|
||||
|
||||
ret = i915_error_state_buf_init(&error_str, count, *pos);
|
||||
ret = i915_error_state_buf_init(&error_str, to_i915(error_priv->dev), count, *pos);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1030,6 +1044,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
|
||||
u32 rpstat, cagf, reqf;
|
||||
u32 rpupei, rpcurup, rpprevup;
|
||||
u32 rpdownei, rpcurdown, rpprevdown;
|
||||
u32 pm_ier, pm_imr, pm_isr, pm_iir, pm_mask;
|
||||
int max_freq;
|
||||
|
||||
/* RPSTAT1 is in the GT power well */
|
||||
@ -1067,12 +1082,21 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
|
||||
gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (IS_GEN6(dev) || IS_GEN7(dev)) {
|
||||
pm_ier = I915_READ(GEN6_PMIER);
|
||||
pm_imr = I915_READ(GEN6_PMIMR);
|
||||
pm_isr = I915_READ(GEN6_PMISR);
|
||||
pm_iir = I915_READ(GEN6_PMIIR);
|
||||
pm_mask = I915_READ(GEN6_PMINTRMSK);
|
||||
} else {
|
||||
pm_ier = I915_READ(GEN8_GT_IER(2));
|
||||
pm_imr = I915_READ(GEN8_GT_IMR(2));
|
||||
pm_isr = I915_READ(GEN8_GT_ISR(2));
|
||||
pm_iir = I915_READ(GEN8_GT_IIR(2));
|
||||
pm_mask = I915_READ(GEN6_PMINTRMSK);
|
||||
}
|
||||
seq_printf(m, "PM IER=0x%08x IMR=0x%08x ISR=0x%08x IIR=0x%08x, MASK=0x%08x\n",
|
||||
I915_READ(GEN6_PMIER),
|
||||
I915_READ(GEN6_PMIMR),
|
||||
I915_READ(GEN6_PMISR),
|
||||
I915_READ(GEN6_PMIIR),
|
||||
I915_READ(GEN6_PMINTRMSK));
|
||||
pm_ier, pm_imr, pm_isr, pm_iir, pm_mask);
|
||||
seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
|
||||
seq_printf(m, "Render p-state ratio: %d\n",
|
||||
(gt_perf_status & 0xff00) >> 8);
|
||||
@ -1371,7 +1395,7 @@ static int i915_drpc_info(struct seq_file *m, void *unused)
|
||||
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
return vlv_drpc_info(m);
|
||||
else if (IS_GEN6(dev) || IS_GEN7(dev))
|
||||
else if (INTEL_INFO(dev)->gen >= 6)
|
||||
return gen6_drpc_info(m);
|
||||
else
|
||||
return ironlake_drpc_info(m);
|
||||
@ -2618,6 +2642,40 @@ static int i915_shared_dplls_info(struct seq_file *m, void *unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_wa_registers(struct seq_file *m, void *unused)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->struct_mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
intel_runtime_pm_get(dev_priv);
|
||||
|
||||
seq_printf(m, "Workarounds applied: %d\n", dev_priv->num_wa_regs);
|
||||
for (i = 0; i < dev_priv->num_wa_regs; ++i) {
|
||||
u32 addr, mask;
|
||||
|
||||
addr = dev_priv->intel_wa_regs[i].addr;
|
||||
mask = dev_priv->intel_wa_regs[i].mask;
|
||||
dev_priv->intel_wa_regs[i].value = I915_READ(addr) | mask;
|
||||
if (dev_priv->intel_wa_regs[i].addr)
|
||||
seq_printf(m, "0x%X: 0x%08X, mask: 0x%08X\n",
|
||||
dev_priv->intel_wa_regs[i].addr,
|
||||
dev_priv->intel_wa_regs[i].value,
|
||||
dev_priv->intel_wa_regs[i].mask);
|
||||
}
|
||||
|
||||
intel_runtime_pm_put(dev_priv);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct pipe_crc_info {
|
||||
const char *name;
|
||||
struct drm_device *dev;
|
||||
@ -3769,8 +3827,6 @@ i915_drop_caches_set(void *data, u64 val)
|
||||
struct drm_device *dev = data;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj, *next;
|
||||
struct i915_address_space *vm;
|
||||
struct i915_vma *vma, *x;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG("Dropping caches: 0x%08llx\n", val);
|
||||
@ -3791,16 +3847,23 @@ i915_drop_caches_set(void *data, u64 val)
|
||||
i915_gem_retire_requests(dev);
|
||||
|
||||
if (val & DROP_BOUND) {
|
||||
list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
|
||||
list_for_each_entry_safe(vma, x, &vm->inactive_list,
|
||||
mm_list) {
|
||||
list_for_each_entry_safe(obj, next, &dev_priv->mm.bound_list,
|
||||
global_list) {
|
||||
struct i915_vma *vma, *v;
|
||||
|
||||
ret = 0;
|
||||
drm_gem_object_reference(&obj->base);
|
||||
list_for_each_entry_safe(vma, v, &obj->vma_list, vma_link) {
|
||||
if (vma->pin_count)
|
||||
continue;
|
||||
|
||||
ret = i915_vma_unbind(vma);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
break;
|
||||
}
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4149,6 +4212,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
|
||||
{"i915_semaphore_status", i915_semaphore_status, 0},
|
||||
{"i915_shared_dplls_info", i915_shared_dplls_info, 0},
|
||||
{"i915_dp_mst_info", i915_dp_mst_info, 0},
|
||||
{"i915_wa_registers", i915_wa_registers, 0},
|
||||
};
|
||||
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
|
||||
|
||||
@ -4178,7 +4242,7 @@ void intel_display_crc_init(struct drm_device *dev)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
enum pipe pipe;
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
|
||||
|
||||
pipe_crc->opened = false;
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/async.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
@ -1381,7 +1382,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
|
||||
* scanning against hotplug events. Hence do this first and ignore the
|
||||
* tiny window where we will loose hotplug notifactions.
|
||||
*/
|
||||
intel_fbdev_initial_config(dev);
|
||||
async_schedule(intel_fbdev_initial_config, dev_priv);
|
||||
|
||||
drm_kms_helper_poll_init(dev);
|
||||
|
||||
@ -1534,10 +1535,10 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
|
||||
info = (struct intel_device_info *)&dev_priv->info;
|
||||
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
info->num_sprites[pipe] = 2;
|
||||
else
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
info->num_sprites[pipe] = 1;
|
||||
|
||||
if (i915.disable_display) {
|
||||
|
@ -844,7 +844,13 @@ int i915_reset(struct drm_device *dev)
|
||||
!dev_priv->ums.mm_suspended) {
|
||||
dev_priv->ums.mm_suspended = 0;
|
||||
|
||||
/* Used to prevent gem_check_wedged returning -EAGAIN during gpu reset */
|
||||
dev_priv->gpu_error.reload_in_reset = true;
|
||||
|
||||
ret = i915_gem_init_hw(dev);
|
||||
|
||||
dev_priv->gpu_error.reload_in_reset = false;
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed hw init on reset %d\n", ret);
|
||||
@ -1456,13 +1462,29 @@ static int intel_runtime_suspend(struct device *device)
|
||||
dev_priv->pm.suspended = true;
|
||||
|
||||
/*
|
||||
* current versions of firmware which depend on this opregion
|
||||
* notification have repurposed the D1 definition to mean
|
||||
* "runtime suspended" vs. what you would normally expect (D3)
|
||||
* to distinguish it from notifications that might be sent
|
||||
* via the suspend path.
|
||||
* FIXME: We really should find a document that references the arguments
|
||||
* used below!
|
||||
*/
|
||||
intel_opregion_notify_adapter(dev, PCI_D1);
|
||||
if (IS_HASWELL(dev)) {
|
||||
/*
|
||||
* current versions of firmware which depend on this opregion
|
||||
* notification have repurposed the D1 definition to mean
|
||||
* "runtime suspended" vs. what you would normally expect (D3)
|
||||
* to distinguish it from notifications that might be sent via
|
||||
* the suspend path.
|
||||
*/
|
||||
intel_opregion_notify_adapter(dev, PCI_D1);
|
||||
} else {
|
||||
/*
|
||||
* On Broadwell, if we use PCI_D1 the PCH DDI ports will stop
|
||||
* being detected, and the call we do at intel_runtime_resume()
|
||||
* won't be able to restore them. Since PCI_D3hot matches the
|
||||
* actual specification and appears to be working, use it. Let's
|
||||
* assume the other non-Haswell platforms will stay the same as
|
||||
* Broadwell.
|
||||
*/
|
||||
intel_opregion_notify_adapter(dev, PCI_D3hot);
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("Device suspended\n");
|
||||
return 0;
|
||||
@ -1685,6 +1707,8 @@ static void __exit i915_exit(void)
|
||||
module_init(i915_init);
|
||||
module_exit(i915_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_AUTHOR("Tungsten Graphics, Inc.");
|
||||
MODULE_AUTHOR("Intel Corporation");
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "intel_ringbuffer.h"
|
||||
#include "intel_lrc.h"
|
||||
#include "i915_gem_gtt.h"
|
||||
#include "i915_gem_render_state.h"
|
||||
#include <linux/io-mapping.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
@ -51,11 +52,9 @@
|
||||
/* General customization:
|
||||
*/
|
||||
|
||||
#define DRIVER_AUTHOR "Tungsten Graphics, Inc."
|
||||
|
||||
#define DRIVER_NAME "i915"
|
||||
#define DRIVER_DESC "Intel Graphics"
|
||||
#define DRIVER_DATE "20140822"
|
||||
#define DRIVER_DATE "20140905"
|
||||
|
||||
enum pipe {
|
||||
INVALID_PIPE = -1,
|
||||
@ -164,7 +163,10 @@ enum hpd_pin {
|
||||
I915_GEM_DOMAIN_INSTRUCTION | \
|
||||
I915_GEM_DOMAIN_VERTEX)
|
||||
|
||||
#define for_each_pipe(p) for ((p) = 0; (p) < INTEL_INFO(dev)->num_pipes; (p)++)
|
||||
#define for_each_pipe(__dev_priv, __p) \
|
||||
for ((__p) = 0; (__p) < INTEL_INFO(__dev_priv)->num_pipes; (__p)++)
|
||||
#define for_each_plane(pipe, p) \
|
||||
for ((p) = 0; (p) < INTEL_INFO(dev)->num_sprites[(pipe)] + 1; (p)++)
|
||||
#define for_each_sprite(p, s) for ((s) = 0; (s) < INTEL_INFO(dev)->num_sprites[(p)]; (s)++)
|
||||
|
||||
#define for_each_crtc(dev, crtc) \
|
||||
@ -639,6 +641,7 @@ struct intel_context {
|
||||
} legacy_hw_ctx;
|
||||
|
||||
/* Execlists */
|
||||
bool rcs_initialized;
|
||||
struct {
|
||||
struct drm_i915_gem_object *state;
|
||||
struct intel_ringbuffer *ringbuf;
|
||||
@ -712,6 +715,7 @@ enum intel_sbi_destination {
|
||||
#define QUIRK_LVDS_SSC_DISABLE (1<<1)
|
||||
#define QUIRK_INVERT_BRIGHTNESS (1<<2)
|
||||
#define QUIRK_BACKLIGHT_PRESENT (1<<3)
|
||||
#define QUIRK_PIPEB_FORCE (1<<4)
|
||||
|
||||
struct intel_fbdev;
|
||||
struct intel_fbc_work;
|
||||
@ -941,6 +945,23 @@ struct intel_rps_ei {
|
||||
u32 media_c0;
|
||||
};
|
||||
|
||||
struct intel_rps_bdw_cal {
|
||||
u32 it_threshold_pct; /* interrupt, in percentage */
|
||||
u32 eval_interval; /* evaluation interval, in us */
|
||||
u32 last_ts;
|
||||
u32 last_c0;
|
||||
bool is_up;
|
||||
};
|
||||
|
||||
struct intel_rps_bdw_turbo {
|
||||
struct intel_rps_bdw_cal up;
|
||||
struct intel_rps_bdw_cal down;
|
||||
struct timer_list flip_timer;
|
||||
u32 timeout;
|
||||
atomic_t flip_received;
|
||||
struct work_struct work_max_freq;
|
||||
};
|
||||
|
||||
struct intel_gen6_power_mgmt {
|
||||
/* work and pm_iir are protected by dev_priv->irq_lock */
|
||||
struct work_struct work;
|
||||
@ -974,6 +995,9 @@ struct intel_gen6_power_mgmt {
|
||||
bool enabled;
|
||||
struct delayed_work delayed_resume_work;
|
||||
|
||||
bool is_bdw_sw_turbo; /* Switch of BDW software turbo */
|
||||
struct intel_rps_bdw_turbo sw_turbo; /* Calculate RP interrupt timing */
|
||||
|
||||
/* manual wa residency calculations */
|
||||
struct intel_rps_ei up_ei, down_ei;
|
||||
|
||||
@ -1171,6 +1195,7 @@ struct i915_gem_mm {
|
||||
};
|
||||
|
||||
struct drm_i915_error_state_buf {
|
||||
struct drm_i915_private *i915;
|
||||
unsigned bytes;
|
||||
unsigned size;
|
||||
int err;
|
||||
@ -1243,6 +1268,9 @@ struct i915_gpu_error {
|
||||
|
||||
/* For missed irq/seqno simulation. */
|
||||
unsigned int test_irq_rings;
|
||||
|
||||
/* Used to prevent gem_check_wedged returning -EAGAIN during gpu reset */
|
||||
bool reload_in_reset;
|
||||
};
|
||||
|
||||
enum modeset_restore {
|
||||
@ -1505,6 +1533,9 @@ struct drm_i915_private {
|
||||
/* LVDS info */
|
||||
bool no_aux_handshake;
|
||||
|
||||
/* protects panel power sequencer state */
|
||||
struct mutex pps_mutex;
|
||||
|
||||
struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 965 */
|
||||
int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
|
||||
int num_fence_regs; /* 8 on pre-965, 16 otherwise */
|
||||
@ -1556,6 +1587,20 @@ struct drm_i915_private {
|
||||
struct intel_shared_dpll shared_dplls[I915_NUM_PLLS];
|
||||
int dpio_phy_iosf_port[I915_NUM_PHYS_VLV];
|
||||
|
||||
/*
|
||||
* workarounds are currently applied at different places and
|
||||
* changes are being done to consolidate them so exact count is
|
||||
* not clear at this point, use a max value for now.
|
||||
*/
|
||||
#define I915_MAX_WA_REGS 16
|
||||
struct {
|
||||
u32 addr;
|
||||
u32 value;
|
||||
/* bitmask representing WA bits */
|
||||
u32 mask;
|
||||
} intel_wa_regs[I915_MAX_WA_REGS];
|
||||
u32 num_wa_regs;
|
||||
|
||||
/* Reclocking support */
|
||||
bool render_reclock_avail;
|
||||
bool lvds_downclock_avail;
|
||||
@ -1639,6 +1684,8 @@ struct drm_i915_private {
|
||||
*/
|
||||
struct workqueue_struct *dp_wq;
|
||||
|
||||
uint32_t bios_vgacntr;
|
||||
|
||||
/* Old dri1 support infrastructure, beware the dragons ya fools entering
|
||||
* here! */
|
||||
struct i915_dri1_state dri1;
|
||||
@ -2596,8 +2643,6 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
|
||||
int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file);
|
||||
|
||||
/* i915_gem_render_state.c */
|
||||
int i915_gem_render_state_init(struct intel_engine_cs *ring);
|
||||
/* i915_gem_evict.c */
|
||||
int __must_check i915_gem_evict_something(struct drm_device *dev,
|
||||
struct i915_address_space *vm,
|
||||
@ -2665,6 +2710,7 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...);
|
||||
int i915_error_state_to_str(struct drm_i915_error_state_buf *estr,
|
||||
const struct i915_error_state_file_priv *error);
|
||||
int i915_error_state_buf_init(struct drm_i915_error_state_buf *eb,
|
||||
struct drm_i915_private *i915,
|
||||
size_t count, loff_t pos);
|
||||
static inline void i915_error_state_buf_release(
|
||||
struct drm_i915_error_state_buf *eb)
|
||||
@ -2679,7 +2725,7 @@ void i915_error_state_put(struct i915_error_state_file_priv *error_priv);
|
||||
void i915_destroy_error_state(struct drm_device *dev);
|
||||
|
||||
void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone);
|
||||
const char *i915_cache_level_str(int type);
|
||||
const char *i915_cache_level_str(struct drm_i915_private *i915, int type);
|
||||
|
||||
/* i915_cmd_parser.c */
|
||||
int i915_cmd_parser_get_version(void);
|
||||
@ -2771,10 +2817,13 @@ extern void intel_modeset_setup_hw_state(struct drm_device *dev,
|
||||
extern void i915_redisable_vga(struct drm_device *dev);
|
||||
extern void i915_redisable_vga_power_on(struct drm_device *dev);
|
||||
extern bool intel_fbc_enabled(struct drm_device *dev);
|
||||
extern void gen8_fbc_sw_flush(struct drm_device *dev, u32 value);
|
||||
extern void intel_disable_fbc(struct drm_device *dev);
|
||||
extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
|
||||
extern void intel_init_pch_refclk(struct drm_device *dev);
|
||||
extern void gen6_set_rps(struct drm_device *dev, u8 val);
|
||||
extern void bdw_software_turbo(struct drm_device *dev);
|
||||
extern void gen8_flip_interrupt(struct drm_device *dev);
|
||||
extern void valleyview_set_rps(struct drm_device *dev, u8 val);
|
||||
extern void intel_set_memory_cxsr(struct drm_i915_private *dev_priv,
|
||||
bool enable);
|
||||
|
@ -1085,7 +1085,13 @@ i915_gem_check_wedge(struct i915_gpu_error *error,
|
||||
if (i915_terminally_wedged(error))
|
||||
return -EIO;
|
||||
|
||||
return -EAGAIN;
|
||||
/*
|
||||
* Check if GPU Reset is in progress - we need intel_ring_begin
|
||||
* to work properly to reinit the hw state while the gpu is
|
||||
* still marked as reset-in-progress. Handle this with a flag.
|
||||
*/
|
||||
if (!error->reload_in_reset)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2982,9 +2988,11 @@ int i915_gpu_idle(struct drm_device *dev)
|
||||
|
||||
/* Flush everything onto the inactive list. */
|
||||
for_each_ring(ring, dev_priv, i) {
|
||||
ret = i915_switch_context(ring, ring->default_context);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!i915.enable_execlists) {
|
||||
ret = i915_switch_context(ring, ring->default_context);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = intel_ring_idle(ring);
|
||||
if (ret)
|
||||
@ -4658,11 +4666,46 @@ intel_enable_blt(struct drm_device *dev)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void init_unused_ring(struct drm_device *dev, u32 base)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
I915_WRITE(RING_CTL(base), 0);
|
||||
I915_WRITE(RING_HEAD(base), 0);
|
||||
I915_WRITE(RING_TAIL(base), 0);
|
||||
I915_WRITE(RING_START(base), 0);
|
||||
}
|
||||
|
||||
static void init_unused_rings(struct drm_device *dev)
|
||||
{
|
||||
if (IS_I830(dev)) {
|
||||
init_unused_ring(dev, PRB1_BASE);
|
||||
init_unused_ring(dev, SRB0_BASE);
|
||||
init_unused_ring(dev, SRB1_BASE);
|
||||
init_unused_ring(dev, SRB2_BASE);
|
||||
init_unused_ring(dev, SRB3_BASE);
|
||||
} else if (IS_GEN2(dev)) {
|
||||
init_unused_ring(dev, SRB0_BASE);
|
||||
init_unused_ring(dev, SRB1_BASE);
|
||||
} else if (IS_GEN3(dev)) {
|
||||
init_unused_ring(dev, PRB1_BASE);
|
||||
init_unused_ring(dev, PRB2_BASE);
|
||||
}
|
||||
}
|
||||
|
||||
int i915_gem_init_rings(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* At least 830 can leave some of the unused rings
|
||||
* "active" (ie. head != tail) after resume which
|
||||
* will prevent c3 entry. Makes sure all unused rings
|
||||
* are totally idle.
|
||||
*/
|
||||
init_unused_rings(dev);
|
||||
|
||||
ret = intel_init_render_ring_buffer(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -289,34 +289,23 @@ void i915_gem_context_reset(struct drm_device *dev)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int i;
|
||||
|
||||
/* Prevent the hardware from restoring the last context (which hung) on
|
||||
* the next switch */
|
||||
/* In execlists mode we will unreference the context when the execlist
|
||||
* queue is cleared and the requests destroyed.
|
||||
*/
|
||||
if (i915.enable_execlists)
|
||||
return;
|
||||
|
||||
for (i = 0; i < I915_NUM_RINGS; i++) {
|
||||
struct intel_engine_cs *ring = &dev_priv->ring[i];
|
||||
struct intel_context *dctx = ring->default_context;
|
||||
struct intel_context *lctx = ring->last_context;
|
||||
|
||||
/* Do a fake switch to the default context */
|
||||
if (lctx == dctx)
|
||||
continue;
|
||||
if (lctx) {
|
||||
if (lctx->legacy_hw_ctx.rcs_state && i == RCS)
|
||||
i915_gem_object_ggtt_unpin(lctx->legacy_hw_ctx.rcs_state);
|
||||
|
||||
if (!lctx)
|
||||
continue;
|
||||
|
||||
if (dctx->legacy_hw_ctx.rcs_state && i == RCS) {
|
||||
WARN_ON(i915_gem_obj_ggtt_pin(dctx->legacy_hw_ctx.rcs_state,
|
||||
get_context_alignment(dev), 0));
|
||||
/* Fake a finish/inactive */
|
||||
dctx->legacy_hw_ctx.rcs_state->base.write_domain = 0;
|
||||
dctx->legacy_hw_ctx.rcs_state->active = 0;
|
||||
i915_gem_context_unreference(lctx);
|
||||
ring->last_context = NULL;
|
||||
}
|
||||
|
||||
if (lctx->legacy_hw_ctx.rcs_state && i == RCS)
|
||||
i915_gem_object_ggtt_unpin(lctx->legacy_hw_ctx.rcs_state);
|
||||
|
||||
i915_gem_context_unreference(lctx);
|
||||
i915_gem_context_reference(dctx);
|
||||
ring->last_context = dctx;
|
||||
}
|
||||
}
|
||||
|
||||
@ -412,12 +401,11 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)
|
||||
struct intel_engine_cs *ring;
|
||||
int ret, i;
|
||||
|
||||
/* FIXME: We should make this work, even in reset */
|
||||
if (i915_reset_in_progress(&dev_priv->gpu_error))
|
||||
return 0;
|
||||
|
||||
BUG_ON(!dev_priv->ring[RCS].default_context);
|
||||
|
||||
if (i915.enable_execlists)
|
||||
return 0;
|
||||
|
||||
for_each_ring(ring, dev_priv, i) {
|
||||
ret = i915_switch_context(ring, ring->default_context);
|
||||
if (ret)
|
||||
@ -479,6 +467,7 @@ mi_set_context(struct intel_engine_cs *ring,
|
||||
struct intel_context *new_context,
|
||||
u32 hw_flags)
|
||||
{
|
||||
u32 flags = hw_flags | MI_MM_SPACE_GTT;
|
||||
int ret;
|
||||
|
||||
/* w/a: If Flush TLB Invalidation Mode is enabled, driver must do a TLB
|
||||
@ -492,6 +481,10 @@ mi_set_context(struct intel_engine_cs *ring,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* These flags are for resource streamer on HSW+ */
|
||||
if (!IS_HASWELL(ring->dev) && INTEL_INFO(ring->dev)->gen < 8)
|
||||
flags |= (MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN);
|
||||
|
||||
ret = intel_ring_begin(ring, 6);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -505,10 +498,7 @@ mi_set_context(struct intel_engine_cs *ring,
|
||||
intel_ring_emit(ring, MI_NOOP);
|
||||
intel_ring_emit(ring, MI_SET_CONTEXT);
|
||||
intel_ring_emit(ring, i915_gem_obj_ggtt_offset(new_context->legacy_hw_ctx.rcs_state) |
|
||||
MI_MM_SPACE_GTT |
|
||||
MI_SAVE_EXT_STATE_EN |
|
||||
MI_RESTORE_EXT_STATE_EN |
|
||||
hw_flags);
|
||||
flags);
|
||||
/*
|
||||
* w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
|
||||
* WaMiSetContext_Hang:snb,ivb,vlv
|
||||
@ -558,7 +548,7 @@ static int do_switch(struct intel_engine_cs *ring,
|
||||
from = ring->last_context;
|
||||
|
||||
if (to->ppgtt) {
|
||||
ret = to->ppgtt->switch_mm(to->ppgtt, ring, false);
|
||||
ret = to->ppgtt->switch_mm(to->ppgtt, ring);
|
||||
if (ret)
|
||||
goto unpin_out;
|
||||
}
|
||||
@ -638,6 +628,12 @@ done:
|
||||
ring->last_context = to;
|
||||
|
||||
if (uninitialized) {
|
||||
if (ring->init_context) {
|
||||
ret = ring->init_context(ring);
|
||||
if (ret)
|
||||
DRM_ERROR("ring init context: %d\n", ret);
|
||||
}
|
||||
|
||||
ret = i915_gem_render_state_init(ring);
|
||||
if (ret)
|
||||
DRM_ERROR("init render state: %d\n", ret);
|
||||
@ -658,14 +654,19 @@ unpin_out:
|
||||
*
|
||||
* The context life cycle is simple. The context refcount is incremented and
|
||||
* decremented by 1 and create and destroy. If the context is in use by the GPU,
|
||||
* it will have a refoucnt > 1. This allows us to destroy the context abstract
|
||||
* it will have a refcount > 1. This allows us to destroy the context abstract
|
||||
* object while letting the normal object tracking destroy the backing BO.
|
||||
*
|
||||
* This function should not be used in execlists mode. Instead the context is
|
||||
* switched by writing to the ELSP and requests keep a reference to their
|
||||
* context.
|
||||
*/
|
||||
int i915_switch_context(struct intel_engine_cs *ring,
|
||||
struct intel_context *to)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = ring->dev->dev_private;
|
||||
|
||||
WARN_ON(i915.enable_execlists);
|
||||
WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
|
||||
|
||||
if (to->legacy_hw_ctx.rcs_state == NULL) { /* We have the fake context */
|
||||
|
@ -204,19 +204,12 @@ static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
|
||||
|
||||
/* Broadwell Page Directory Pointer Descriptors */
|
||||
static int gen8_write_pdp(struct intel_engine_cs *ring, unsigned entry,
|
||||
uint64_t val, bool synchronous)
|
||||
uint64_t val)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = ring->dev->dev_private;
|
||||
int ret;
|
||||
|
||||
BUG_ON(entry >= 4);
|
||||
|
||||
if (synchronous) {
|
||||
I915_WRITE(GEN8_RING_PDP_UDW(ring, entry), val >> 32);
|
||||
I915_WRITE(GEN8_RING_PDP_LDW(ring, entry), (u32)val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = intel_ring_begin(ring, 6);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -233,8 +226,7 @@ static int gen8_write_pdp(struct intel_engine_cs *ring, unsigned entry,
|
||||
}
|
||||
|
||||
static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
||||
struct intel_engine_cs *ring,
|
||||
bool synchronous)
|
||||
struct intel_engine_cs *ring)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
@ -243,7 +235,7 @@ static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
||||
|
||||
for (i = used_pd - 1; i >= 0; i--) {
|
||||
dma_addr_t addr = ppgtt->pd_dma_addr[i];
|
||||
ret = gen8_write_pdp(ring, i, addr, synchronous);
|
||||
ret = gen8_write_pdp(ring, i, addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -708,29 +700,10 @@ static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt)
|
||||
}
|
||||
|
||||
static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
||||
struct intel_engine_cs *ring,
|
||||
bool synchronous)
|
||||
struct intel_engine_cs *ring)
|
||||
{
|
||||
struct drm_device *dev = ppgtt->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
|
||||
/* If we're in reset, we can assume the GPU is sufficiently idle to
|
||||
* manually frob these bits. Ideally we could use the ring functions,
|
||||
* except our error handling makes it quite difficult (can't use
|
||||
* intel_ring_begin, ring->flush, or intel_ring_advance)
|
||||
*
|
||||
* FIXME: We should try not to special case reset
|
||||
*/
|
||||
if (synchronous ||
|
||||
i915_reset_in_progress(&dev_priv->gpu_error)) {
|
||||
WARN_ON(ppgtt != dev_priv->mm.aliasing_ppgtt);
|
||||
I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
|
||||
I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
|
||||
POSTING_READ(RING_PP_DIR_BASE(ring));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NB: TLBs must be flushed and invalidated before a switch */
|
||||
ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
|
||||
if (ret)
|
||||
@ -752,29 +725,10 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
||||
}
|
||||
|
||||
static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
||||
struct intel_engine_cs *ring,
|
||||
bool synchronous)
|
||||
struct intel_engine_cs *ring)
|
||||
{
|
||||
struct drm_device *dev = ppgtt->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
|
||||
/* If we're in reset, we can assume the GPU is sufficiently idle to
|
||||
* manually frob these bits. Ideally we could use the ring functions,
|
||||
* except our error handling makes it quite difficult (can't use
|
||||
* intel_ring_begin, ring->flush, or intel_ring_advance)
|
||||
*
|
||||
* FIXME: We should try not to special case reset
|
||||
*/
|
||||
if (synchronous ||
|
||||
i915_reset_in_progress(&dev_priv->gpu_error)) {
|
||||
WARN_ON(ppgtt != dev_priv->mm.aliasing_ppgtt);
|
||||
I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
|
||||
I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
|
||||
POSTING_READ(RING_PP_DIR_BASE(ring));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NB: TLBs must be flushed and invalidated before a switch */
|
||||
ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
|
||||
if (ret)
|
||||
@ -803,14 +757,11 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
||||
}
|
||||
|
||||
static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt,
|
||||
struct intel_engine_cs *ring,
|
||||
bool synchronous)
|
||||
struct intel_engine_cs *ring)
|
||||
{
|
||||
struct drm_device *dev = ppgtt->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (!synchronous)
|
||||
return 0;
|
||||
|
||||
I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
|
||||
I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
|
||||
@ -826,12 +777,6 @@ static void gen8_ppgtt_enable(struct drm_device *dev)
|
||||
struct intel_engine_cs *ring;
|
||||
int j;
|
||||
|
||||
/* In the case of execlists, PPGTT is enabled by the context descriptor
|
||||
* and the PDPs are contained within the context itself. We don't
|
||||
* need to do anything here. */
|
||||
if (i915.enable_execlists)
|
||||
return;
|
||||
|
||||
for_each_ring(ring, dev_priv, j) {
|
||||
I915_WRITE(RING_MODE_GEN7(ring),
|
||||
_MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
|
||||
@ -1175,6 +1120,12 @@ int i915_ppgtt_init_hw(struct drm_device *dev)
|
||||
struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
|
||||
int i, ret = 0;
|
||||
|
||||
/* In the case of execlists, PPGTT is enabled by the context descriptor
|
||||
* and the PDPs are contained within the context itself. We don't
|
||||
* need to do anything here. */
|
||||
if (i915.enable_execlists)
|
||||
return 0;
|
||||
|
||||
if (!USES_PPGTT(dev))
|
||||
return 0;
|
||||
|
||||
@ -1189,7 +1140,7 @@ int i915_ppgtt_init_hw(struct drm_device *dev)
|
||||
|
||||
if (ppgtt) {
|
||||
for_each_ring(ring, dev_priv, i) {
|
||||
ret = ppgtt->switch_mm(ppgtt, ring, true);
|
||||
ret = ppgtt->switch_mm(ppgtt, ring);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
@ -2190,8 +2141,10 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
|
||||
/* Keep GGTT vmas first to make debug easier */
|
||||
if (i915_is_ggtt(vm))
|
||||
list_add(&vma->vma_link, &obj->vma_list);
|
||||
else
|
||||
else {
|
||||
list_add_tail(&vma->vma_link, &obj->vma_list);
|
||||
i915_ppgtt_get(i915_vm_to_ppgtt(vm));
|
||||
}
|
||||
|
||||
return vma;
|
||||
}
|
||||
@ -2206,8 +2159,5 @@ i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
|
||||
if (!vma)
|
||||
vma = __i915_gem_vma_create(obj, vm);
|
||||
|
||||
if (!i915_is_ggtt(vm))
|
||||
i915_ppgtt_get(i915_vm_to_ppgtt(vm));
|
||||
|
||||
return vma;
|
||||
}
|
||||
|
@ -264,8 +264,7 @@ struct i915_hw_ppgtt {
|
||||
|
||||
int (*enable)(struct i915_hw_ppgtt *ppgtt);
|
||||
int (*switch_mm)(struct i915_hw_ppgtt *ppgtt,
|
||||
struct intel_engine_cs *ring,
|
||||
bool synchronous);
|
||||
struct intel_engine_cs *ring);
|
||||
void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m);
|
||||
};
|
||||
|
||||
|
@ -28,13 +28,6 @@
|
||||
#include "i915_drv.h"
|
||||
#include "intel_renderstate.h"
|
||||
|
||||
struct render_state {
|
||||
const struct intel_renderstate_rodata *rodata;
|
||||
struct drm_i915_gem_object *obj;
|
||||
u64 ggtt_offset;
|
||||
int gen;
|
||||
};
|
||||
|
||||
static const struct intel_renderstate_rodata *
|
||||
render_state_get_rodata(struct drm_device *dev, const int gen)
|
||||
{
|
||||
@ -127,31 +120,48 @@ static int render_state_setup(struct render_state *so)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void render_state_fini(struct render_state *so)
|
||||
void i915_gem_render_state_fini(struct render_state *so)
|
||||
{
|
||||
i915_gem_object_ggtt_unpin(so->obj);
|
||||
drm_gem_object_unreference(&so->obj->base);
|
||||
}
|
||||
|
||||
int i915_gem_render_state_prepare(struct intel_engine_cs *ring,
|
||||
struct render_state *so)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(ring->id != RCS))
|
||||
return -ENOENT;
|
||||
|
||||
ret = render_state_init(so, ring->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (so->rodata == NULL)
|
||||
return 0;
|
||||
|
||||
ret = render_state_setup(so);
|
||||
if (ret) {
|
||||
i915_gem_render_state_fini(so);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i915_gem_render_state_init(struct intel_engine_cs *ring)
|
||||
{
|
||||
struct render_state so;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(ring->id != RCS))
|
||||
return -ENOENT;
|
||||
|
||||
ret = render_state_init(&so, ring->dev);
|
||||
ret = i915_gem_render_state_prepare(ring, &so);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (so.rodata == NULL)
|
||||
return 0;
|
||||
|
||||
ret = render_state_setup(&so);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = ring->dispatch_execbuffer(ring,
|
||||
so.ggtt_offset,
|
||||
so.rodata->batch_items * 4,
|
||||
@ -164,6 +174,6 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring)
|
||||
ret = __i915_add_request(ring, NULL, so.obj, NULL);
|
||||
/* __i915_add_request moves object to inactive if it fails */
|
||||
out:
|
||||
render_state_fini(&so);
|
||||
i915_gem_render_state_fini(&so);
|
||||
return ret;
|
||||
}
|
||||
|
47
drivers/gpu/drm/i915/i915_gem_render_state.h
Normal file
47
drivers/gpu/drm/i915/i915_gem_render_state.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright © 2014 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _I915_GEM_RENDER_STATE_H_
|
||||
#define _I915_GEM_RENDER_STATE_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct intel_renderstate_rodata {
|
||||
const u32 *reloc;
|
||||
const u32 *batch;
|
||||
const u32 batch_items;
|
||||
};
|
||||
|
||||
struct render_state {
|
||||
const struct intel_renderstate_rodata *rodata;
|
||||
struct drm_i915_gem_object *obj;
|
||||
u64 ggtt_offset;
|
||||
int gen;
|
||||
};
|
||||
|
||||
int i915_gem_render_state_init(struct intel_engine_cs *ring);
|
||||
void i915_gem_render_state_fini(struct render_state *so);
|
||||
int i915_gem_render_state_prepare(struct intel_engine_cs *ring,
|
||||
struct render_state *so);
|
||||
|
||||
#endif /* _I915_GEM_RENDER_STATE_H_ */
|
@ -91,7 +91,14 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
|
||||
uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
|
||||
if (IS_VALLEYVIEW(dev)) {
|
||||
if (INTEL_INFO(dev)->gen >= 8 || IS_VALLEYVIEW(dev)) {
|
||||
/*
|
||||
* On BDW+, swizzling is not used. We leave the CPU memory
|
||||
* controller in charge of optimizing memory accesses without
|
||||
* the extra address manipulation GPU side.
|
||||
*
|
||||
* VLV and CHV don't have GPU swizzling.
|
||||
*/
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
|
||||
} else if (INTEL_INFO(dev)->gen >= 6) {
|
||||
|
@ -208,7 +208,7 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m,
|
||||
err_puts(m, err->userptr ? " userptr" : "");
|
||||
err_puts(m, err->ring != -1 ? " " : "");
|
||||
err_puts(m, ring_str(err->ring));
|
||||
err_puts(m, i915_cache_level_str(err->cache_level));
|
||||
err_puts(m, i915_cache_level_str(m->i915, err->cache_level));
|
||||
|
||||
if (err->name)
|
||||
err_printf(m, " (name: %d)", err->name);
|
||||
@ -494,9 +494,11 @@ out:
|
||||
}
|
||||
|
||||
int i915_error_state_buf_init(struct drm_i915_error_state_buf *ebuf,
|
||||
struct drm_i915_private *i915,
|
||||
size_t count, loff_t pos)
|
||||
{
|
||||
memset(ebuf, 0, sizeof(*ebuf));
|
||||
ebuf->i915 = i915;
|
||||
|
||||
/* We need to have enough room to store any i915_error_state printf
|
||||
* so that we can move it to start position.
|
||||
@ -558,24 +560,54 @@ static void i915_error_state_free(struct kref *error_ref)
|
||||
}
|
||||
|
||||
static struct drm_i915_error_object *
|
||||
i915_error_object_create_sized(struct drm_i915_private *dev_priv,
|
||||
struct drm_i915_gem_object *src,
|
||||
struct i915_address_space *vm,
|
||||
const int num_pages)
|
||||
i915_error_object_create(struct drm_i915_private *dev_priv,
|
||||
struct drm_i915_gem_object *src,
|
||||
struct i915_address_space *vm)
|
||||
{
|
||||
struct drm_i915_error_object *dst;
|
||||
int i;
|
||||
int num_pages;
|
||||
bool use_ggtt;
|
||||
int i = 0;
|
||||
u32 reloc_offset;
|
||||
|
||||
if (src == NULL || src->pages == NULL)
|
||||
return NULL;
|
||||
|
||||
num_pages = src->base.size >> PAGE_SHIFT;
|
||||
|
||||
dst = kmalloc(sizeof(*dst) + num_pages * sizeof(u32 *), GFP_ATOMIC);
|
||||
if (dst == NULL)
|
||||
return NULL;
|
||||
|
||||
reloc_offset = dst->gtt_offset = i915_gem_obj_offset(src, vm);
|
||||
for (i = 0; i < num_pages; i++) {
|
||||
if (i915_gem_obj_bound(src, vm))
|
||||
dst->gtt_offset = i915_gem_obj_offset(src, vm);
|
||||
else
|
||||
dst->gtt_offset = -1;
|
||||
|
||||
reloc_offset = dst->gtt_offset;
|
||||
use_ggtt = (src->cache_level == I915_CACHE_NONE &&
|
||||
i915_is_ggtt(vm) &&
|
||||
src->has_global_gtt_mapping &&
|
||||
reloc_offset + num_pages * PAGE_SIZE <= dev_priv->gtt.mappable_end);
|
||||
|
||||
/* Cannot access stolen address directly, try to use the aperture */
|
||||
if (src->stolen) {
|
||||
use_ggtt = true;
|
||||
|
||||
if (!src->has_global_gtt_mapping)
|
||||
goto unwind;
|
||||
|
||||
reloc_offset = i915_gem_obj_ggtt_offset(src);
|
||||
if (reloc_offset + num_pages * PAGE_SIZE > dev_priv->gtt.mappable_end)
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
/* Cannot access snooped pages through the aperture */
|
||||
if (use_ggtt && src->cache_level != I915_CACHE_NONE && !HAS_LLC(dev_priv->dev))
|
||||
goto unwind;
|
||||
|
||||
dst->page_count = num_pages;
|
||||
while (num_pages--) {
|
||||
unsigned long flags;
|
||||
void *d;
|
||||
|
||||
@ -584,10 +616,7 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv,
|
||||
goto unwind;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (src->cache_level == I915_CACHE_NONE &&
|
||||
reloc_offset < dev_priv->gtt.mappable_end &&
|
||||
src->has_global_gtt_mapping &&
|
||||
i915_is_ggtt(vm)) {
|
||||
if (use_ggtt) {
|
||||
void __iomem *s;
|
||||
|
||||
/* Simply ignore tiling or any overlapping fence.
|
||||
@ -599,14 +628,6 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv,
|
||||
reloc_offset);
|
||||
memcpy_fromio(d, s, PAGE_SIZE);
|
||||
io_mapping_unmap_atomic(s);
|
||||
} else if (src->stolen) {
|
||||
unsigned long offset;
|
||||
|
||||
offset = dev_priv->mm.stolen_base;
|
||||
offset += src->stolen->start;
|
||||
offset += i << PAGE_SHIFT;
|
||||
|
||||
memcpy_fromio(d, (void __iomem *) offset, PAGE_SIZE);
|
||||
} else {
|
||||
struct page *page;
|
||||
void *s;
|
||||
@ -623,11 +644,9 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv,
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
|
||||
dst->pages[i] = d;
|
||||
|
||||
dst->pages[i++] = d;
|
||||
reloc_offset += PAGE_SIZE;
|
||||
}
|
||||
dst->page_count = num_pages;
|
||||
|
||||
return dst;
|
||||
|
||||
@ -637,13 +656,8 @@ unwind:
|
||||
kfree(dst);
|
||||
return NULL;
|
||||
}
|
||||
#define i915_error_object_create(dev_priv, src, vm) \
|
||||
i915_error_object_create_sized((dev_priv), (src), (vm), \
|
||||
(src)->base.size>>PAGE_SHIFT)
|
||||
|
||||
#define i915_error_ggtt_object_create(dev_priv, src) \
|
||||
i915_error_object_create_sized((dev_priv), (src), &(dev_priv)->gtt.base, \
|
||||
(src)->base.size>>PAGE_SHIFT)
|
||||
i915_error_object_create((dev_priv), (src), &(dev_priv)->gtt.base)
|
||||
|
||||
static void capture_bo(struct drm_i915_error_buffer *err,
|
||||
struct i915_vma *vma)
|
||||
@ -900,9 +914,6 @@ static void i915_record_ring_state(struct drm_device *dev,
|
||||
ering->hws = I915_READ(mmio);
|
||||
}
|
||||
|
||||
ering->cpu_ring_head = ring->buffer->head;
|
||||
ering->cpu_ring_tail = ring->buffer->tail;
|
||||
|
||||
ering->hangcheck_score = ring->hangcheck.score;
|
||||
ering->hangcheck_action = ring->hangcheck.action;
|
||||
|
||||
@ -965,6 +976,7 @@ static void i915_gem_record_rings(struct drm_device *dev,
|
||||
|
||||
for (i = 0; i < I915_NUM_RINGS; i++) {
|
||||
struct intel_engine_cs *ring = &dev_priv->ring[i];
|
||||
struct intel_ringbuffer *rbuf;
|
||||
|
||||
error->ring[i].pid = -1;
|
||||
|
||||
@ -992,8 +1004,7 @@ static void i915_gem_record_rings(struct drm_device *dev,
|
||||
request->batch_obj,
|
||||
vm);
|
||||
|
||||
if (HAS_BROKEN_CS_TLB(dev_priv->dev) &&
|
||||
ring->scratch.obj)
|
||||
if (HAS_BROKEN_CS_TLB(dev_priv->dev))
|
||||
error->ring[i].wa_batchbuffer =
|
||||
i915_error_ggtt_object_create(dev_priv,
|
||||
ring->scratch.obj);
|
||||
@ -1012,12 +1023,27 @@ static void i915_gem_record_rings(struct drm_device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
error->ring[i].ringbuffer =
|
||||
i915_error_ggtt_object_create(dev_priv, ring->buffer->obj);
|
||||
if (i915.enable_execlists) {
|
||||
/* TODO: This is only a small fix to keep basic error
|
||||
* capture working, but we need to add more information
|
||||
* for it to be useful (e.g. dump the context being
|
||||
* executed).
|
||||
*/
|
||||
if (request)
|
||||
rbuf = request->ctx->engine[ring->id].ringbuf;
|
||||
else
|
||||
rbuf = ring->default_context->engine[ring->id].ringbuf;
|
||||
} else
|
||||
rbuf = ring->buffer;
|
||||
|
||||
if (ring->status_page.obj)
|
||||
error->ring[i].hws_page =
|
||||
i915_error_ggtt_object_create(dev_priv, ring->status_page.obj);
|
||||
error->ring[i].cpu_ring_head = rbuf->head;
|
||||
error->ring[i].cpu_ring_tail = rbuf->tail;
|
||||
|
||||
error->ring[i].ringbuffer =
|
||||
i915_error_ggtt_object_create(dev_priv, rbuf->obj);
|
||||
|
||||
error->ring[i].hws_page =
|
||||
i915_error_ggtt_object_create(dev_priv, ring->status_page.obj);
|
||||
|
||||
i915_gem_record_active_context(ring, error, &error->ring[i]);
|
||||
|
||||
@ -1331,11 +1357,11 @@ void i915_destroy_error_state(struct drm_device *dev)
|
||||
kref_put(&error->ref, i915_error_state_free);
|
||||
}
|
||||
|
||||
const char *i915_cache_level_str(int type)
|
||||
const char *i915_cache_level_str(struct drm_i915_private *i915, int type)
|
||||
{
|
||||
switch (type) {
|
||||
case I915_CACHE_NONE: return " uncached";
|
||||
case I915_CACHE_LLC: return " snooped or LLC";
|
||||
case I915_CACHE_LLC: return HAS_LLC(i915) ? " LLC" : " snooped";
|
||||
case I915_CACHE_L3_LLC: return " L3+LLC";
|
||||
case I915_CACHE_WT: return " WT";
|
||||
default: return "";
|
||||
|
@ -238,7 +238,7 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
|
||||
|
||||
assert_spin_locked(&dev_priv->irq_lock);
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
|
||||
|
||||
if (crtc->cpu_fifo_underrun_disabled)
|
||||
@ -296,7 +296,7 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
|
||||
|
||||
assert_spin_locked(&dev_priv->irq_lock);
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
|
||||
|
||||
if (crtc->pch_fifo_underrun_disabled)
|
||||
@ -497,7 +497,7 @@ static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
|
||||
old = !intel_crtc->cpu_fifo_underrun_disabled;
|
||||
intel_crtc->cpu_fifo_underrun_disabled = !enable;
|
||||
|
||||
if (INTEL_INFO(dev)->gen < 5 || IS_VALLEYVIEW(dev))
|
||||
if (HAS_GMCH_DISPLAY(dev))
|
||||
i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old);
|
||||
else if (IS_GEN5(dev) || IS_GEN6(dev))
|
||||
ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
|
||||
@ -1979,6 +1979,27 @@ static void i9xx_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe)
|
||||
res1, res2);
|
||||
}
|
||||
|
||||
void gen8_flip_interrupt(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (!dev_priv->rps.is_bdw_sw_turbo)
|
||||
return;
|
||||
|
||||
if(atomic_read(&dev_priv->rps.sw_turbo.flip_received)) {
|
||||
mod_timer(&dev_priv->rps.sw_turbo.flip_timer,
|
||||
usecs_to_jiffies(dev_priv->rps.sw_turbo.timeout) + jiffies);
|
||||
}
|
||||
else {
|
||||
dev_priv->rps.sw_turbo.flip_timer.expires =
|
||||
usecs_to_jiffies(dev_priv->rps.sw_turbo.timeout) + jiffies;
|
||||
add_timer(&dev_priv->rps.sw_turbo.flip_timer);
|
||||
atomic_set(&dev_priv->rps.sw_turbo.flip_received, true);
|
||||
}
|
||||
|
||||
bdw_software_turbo(dev);
|
||||
}
|
||||
|
||||
/* The RPS events need forcewake, so we add them to a work queue and mask their
|
||||
* IMR bits until the work is done. Other interrupts can be processed without
|
||||
* the work queue. */
|
||||
@ -2020,7 +2041,7 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
|
||||
int pipe;
|
||||
|
||||
spin_lock(&dev_priv->irq_lock);
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
int reg;
|
||||
u32 mask, iir_bit = 0;
|
||||
|
||||
@ -2065,9 +2086,10 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
|
||||
}
|
||||
spin_unlock(&dev_priv->irq_lock);
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
|
||||
intel_pipe_handle_vblank(dev, pipe);
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
|
||||
intel_pipe_handle_vblank(dev, pipe))
|
||||
intel_check_page_flip(dev, pipe);
|
||||
|
||||
if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) {
|
||||
intel_prepare_page_flip(dev, pipe);
|
||||
@ -2234,7 +2256,7 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
|
||||
DRM_ERROR("PCH poison interrupt\n");
|
||||
|
||||
if (pch_iir & SDE_FDI_MASK)
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
DRM_DEBUG_DRIVER(" pipe %c FDI IIR: 0x%08x\n",
|
||||
pipe_name(pipe),
|
||||
I915_READ(FDI_RX_IIR(pipe)));
|
||||
@ -2265,7 +2287,7 @@ static void ivb_err_int_handler(struct drm_device *dev)
|
||||
if (err_int & ERR_INT_POISON)
|
||||
DRM_ERROR("Poison interrupt\n");
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) {
|
||||
if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
|
||||
false))
|
||||
@ -2342,7 +2364,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
|
||||
DRM_DEBUG_DRIVER("Audio CP change interrupt\n");
|
||||
|
||||
if (pch_iir & SDE_FDI_MASK_CPT)
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
DRM_DEBUG_DRIVER(" pipe %c FDI IIR: 0x%08x\n",
|
||||
pipe_name(pipe),
|
||||
I915_READ(FDI_RX_IIR(pipe)));
|
||||
@ -2365,9 +2387,10 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
|
||||
if (de_iir & DE_POISON)
|
||||
DRM_ERROR("Poison interrupt\n");
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
if (de_iir & DE_PIPE_VBLANK(pipe))
|
||||
intel_pipe_handle_vblank(dev, pipe);
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
if (de_iir & DE_PIPE_VBLANK(pipe) &&
|
||||
intel_pipe_handle_vblank(dev, pipe))
|
||||
intel_check_page_flip(dev, pipe);
|
||||
|
||||
if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
|
||||
if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
|
||||
@ -2415,9 +2438,10 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
|
||||
if (de_iir & DE_GSE_IVB)
|
||||
intel_opregion_asle_intr(dev);
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
|
||||
intel_pipe_handle_vblank(dev, pipe);
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)) &&
|
||||
intel_pipe_handle_vblank(dev, pipe))
|
||||
intel_check_page_flip(dev, pipe);
|
||||
|
||||
/* plane/pipes map 1:1 on ilk+ */
|
||||
if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
|
||||
@ -2562,7 +2586,7 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
|
||||
DRM_ERROR("The master control interrupt lied (DE PORT)!\n");
|
||||
}
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
uint32_t pipe_iir;
|
||||
|
||||
if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe)))
|
||||
@ -2572,8 +2596,9 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
|
||||
if (pipe_iir) {
|
||||
ret = IRQ_HANDLED;
|
||||
I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir);
|
||||
if (pipe_iir & GEN8_PIPE_VBLANK)
|
||||
intel_pipe_handle_vblank(dev, pipe);
|
||||
if (pipe_iir & GEN8_PIPE_VBLANK &&
|
||||
intel_pipe_handle_vblank(dev, pipe))
|
||||
intel_check_page_flip(dev, pipe);
|
||||
|
||||
if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) {
|
||||
intel_prepare_page_flip(dev, pipe);
|
||||
@ -2781,7 +2806,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
|
||||
|
||||
if (eir & I915_ERROR_MEMORY_REFRESH) {
|
||||
pr_err("memory refresh error:\n");
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
pr_err("pipe %c stat: 0x%08x\n",
|
||||
pipe_name(pipe), I915_READ(PIPESTAT(pipe)));
|
||||
/* pipestat has already been acked */
|
||||
@ -2878,52 +2903,6 @@ void i915_handle_error(struct drm_device *dev, bool wedged,
|
||||
schedule_work(&dev_priv->gpu_error.work);
|
||||
}
|
||||
|
||||
static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct drm_i915_gem_object *obj;
|
||||
struct intel_unpin_work *work;
|
||||
unsigned long flags;
|
||||
bool stall_detected;
|
||||
|
||||
/* Ignore early vblank irqs */
|
||||
if (intel_crtc == NULL)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
work = intel_crtc->unpin_work;
|
||||
|
||||
if (work == NULL ||
|
||||
atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE ||
|
||||
!work->enable_stall_check) {
|
||||
/* Either the pending flip IRQ arrived, or we're too early. Don't check */
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Potential stall - if we see that the flip has happened, assume a missed interrupt */
|
||||
obj = work->pending_flip_obj;
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
int dspsurf = DSPSURF(intel_crtc->plane);
|
||||
stall_detected = I915_HI_DISPBASE(I915_READ(dspsurf)) ==
|
||||
i915_gem_obj_ggtt_offset(obj);
|
||||
} else {
|
||||
int dspaddr = DSPADDR(intel_crtc->plane);
|
||||
stall_detected = I915_READ(dspaddr) == (i915_gem_obj_ggtt_offset(obj) +
|
||||
crtc->y * crtc->primary->fb->pitches[0] +
|
||||
crtc->x * crtc->primary->fb->bits_per_pixel/8);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
|
||||
if (stall_detected) {
|
||||
DRM_DEBUG_DRIVER("Pageflip stall detected\n");
|
||||
intel_prepare_page_flip(dev, intel_crtc->plane);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called from drm generic code, passed 'crtc' which
|
||||
* we use as a pipe index
|
||||
*/
|
||||
@ -3459,7 +3438,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
|
||||
|
||||
I915_WRITE(PORT_HOTPLUG_EN, 0);
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
I915_WRITE(PIPESTAT(pipe), 0xffff);
|
||||
I915_WRITE(VLV_IIR, 0xffffffff);
|
||||
I915_WRITE(VLV_IMR, 0xffffffff);
|
||||
@ -3485,7 +3464,7 @@ static void gen8_irq_reset(struct drm_device *dev)
|
||||
|
||||
gen8_gt_irq_reset(dev_priv);
|
||||
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
if (intel_display_power_enabled(dev_priv,
|
||||
POWER_DOMAIN_PIPE(pipe)))
|
||||
GEN8_IRQ_RESET_NDX(DE_PIPE, pipe);
|
||||
@ -3528,7 +3507,7 @@ static void cherryview_irq_preinstall(struct drm_device *dev)
|
||||
I915_WRITE(PORT_HOTPLUG_EN, 0);
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
|
||||
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
I915_WRITE(PIPESTAT(pipe), 0xffff);
|
||||
|
||||
I915_WRITE(VLV_IMR, 0xffffffff);
|
||||
@ -3799,8 +3778,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
|
||||
|
||||
static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* These are interrupts we'll toggle with the ring mask register */
|
||||
uint32_t gt_interrupts[] = {
|
||||
GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
|
||||
@ -3817,15 +3794,15 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
|
||||
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++)
|
||||
GEN8_IRQ_INIT_NDX(GT, i, ~gt_interrupts[i], gt_interrupts[i]);
|
||||
|
||||
dev_priv->pm_irq_mask = 0xffffffff;
|
||||
GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]);
|
||||
GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
|
||||
GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_irq_mask, dev_priv->pm_rps_events);
|
||||
GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]);
|
||||
}
|
||||
|
||||
static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
uint32_t de_pipe_masked = GEN8_PIPE_PRIMARY_FLIP_DONE |
|
||||
GEN8_PIPE_CDCLK_CRC_DONE |
|
||||
GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
|
||||
@ -3836,7 +3813,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
|
||||
dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked;
|
||||
dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_masked;
|
||||
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
if (intel_display_power_enabled(dev_priv,
|
||||
POWER_DOMAIN_PIPE(pipe)))
|
||||
GEN8_IRQ_INIT_NDX(DE_PIPE, pipe,
|
||||
@ -3881,12 +3858,12 @@ static int cherryview_irq_postinstall(struct drm_device *dev)
|
||||
*/
|
||||
dev_priv->irq_mask = ~enable_mask;
|
||||
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
I915_WRITE(PIPESTAT(pipe), 0xffff);
|
||||
|
||||
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
|
||||
i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
i915_enable_pipestat(dev_priv, pipe, pipestat_enable);
|
||||
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
|
||||
|
||||
@ -3923,7 +3900,7 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
|
||||
|
||||
I915_WRITE(VLV_MASTER_IER, 0);
|
||||
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
I915_WRITE(PIPESTAT(pipe), 0xffff);
|
||||
|
||||
I915_WRITE(HWSTAM, 0xffffffff);
|
||||
@ -3985,7 +3962,7 @@ do { \
|
||||
I915_WRITE(PORT_HOTPLUG_EN, 0);
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
|
||||
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
I915_WRITE(PIPESTAT(pipe), 0xffff);
|
||||
|
||||
I915_WRITE(VLV_IMR, 0xffffffff);
|
||||
@ -4009,7 +3986,7 @@ static void i8xx_irq_preinstall(struct drm_device * dev)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int pipe;
|
||||
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
I915_WRITE(PIPESTAT(pipe), 0);
|
||||
I915_WRITE16(IMR, 0xffff);
|
||||
I915_WRITE16(IER, 0x0);
|
||||
@ -4063,7 +4040,7 @@ static bool i8xx_handle_vblank(struct drm_device *dev,
|
||||
return false;
|
||||
|
||||
if ((iir & flip_pending) == 0)
|
||||
return false;
|
||||
goto check_page_flip;
|
||||
|
||||
intel_prepare_page_flip(dev, plane);
|
||||
|
||||
@ -4074,11 +4051,14 @@ static bool i8xx_handle_vblank(struct drm_device *dev,
|
||||
* an interrupt per se, we watch for the change at vblank.
|
||||
*/
|
||||
if (I915_READ16(ISR) & flip_pending)
|
||||
return false;
|
||||
goto check_page_flip;
|
||||
|
||||
intel_finish_page_flip(dev, pipe);
|
||||
|
||||
return true;
|
||||
|
||||
check_page_flip:
|
||||
intel_check_page_flip(dev, pipe);
|
||||
return false;
|
||||
}
|
||||
|
||||
static irqreturn_t i8xx_irq_handler(int irq, void *arg)
|
||||
@ -4109,7 +4089,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
|
||||
"Command parser error, iir 0x%08x",
|
||||
iir);
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
int reg = PIPESTAT(pipe);
|
||||
pipe_stats[pipe] = I915_READ(reg);
|
||||
|
||||
@ -4129,7 +4109,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
|
||||
if (iir & I915_USER_INTERRUPT)
|
||||
notify_ring(dev, &dev_priv->ring[RCS]);
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
int plane = pipe;
|
||||
if (HAS_FBC(dev))
|
||||
plane = !plane;
|
||||
@ -4157,7 +4137,7 @@ static void i8xx_irq_uninstall(struct drm_device * dev)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int pipe;
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
/* Clear enable bits; then clear status bits */
|
||||
I915_WRITE(PIPESTAT(pipe), 0);
|
||||
I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe)));
|
||||
@ -4178,7 +4158,7 @@ static void i915_irq_preinstall(struct drm_device * dev)
|
||||
}
|
||||
|
||||
I915_WRITE16(HWSTAM, 0xeffe);
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
I915_WRITE(PIPESTAT(pipe), 0);
|
||||
I915_WRITE(IMR, 0xffffffff);
|
||||
I915_WRITE(IER, 0x0);
|
||||
@ -4248,7 +4228,7 @@ static bool i915_handle_vblank(struct drm_device *dev,
|
||||
return false;
|
||||
|
||||
if ((iir & flip_pending) == 0)
|
||||
return false;
|
||||
goto check_page_flip;
|
||||
|
||||
intel_prepare_page_flip(dev, plane);
|
||||
|
||||
@ -4259,11 +4239,14 @@ static bool i915_handle_vblank(struct drm_device *dev,
|
||||
* an interrupt per se, we watch for the change at vblank.
|
||||
*/
|
||||
if (I915_READ(ISR) & flip_pending)
|
||||
return false;
|
||||
goto check_page_flip;
|
||||
|
||||
intel_finish_page_flip(dev, pipe);
|
||||
|
||||
return true;
|
||||
|
||||
check_page_flip:
|
||||
intel_check_page_flip(dev, pipe);
|
||||
return false;
|
||||
}
|
||||
|
||||
static irqreturn_t i915_irq_handler(int irq, void *arg)
|
||||
@ -4293,7 +4276,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
|
||||
"Command parser error, iir 0x%08x",
|
||||
iir);
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
int reg = PIPESTAT(pipe);
|
||||
pipe_stats[pipe] = I915_READ(reg);
|
||||
|
||||
@ -4319,7 +4302,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
|
||||
if (iir & I915_USER_INTERRUPT)
|
||||
notify_ring(dev, &dev_priv->ring[RCS]);
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
int plane = pipe;
|
||||
if (HAS_FBC(dev))
|
||||
plane = !plane;
|
||||
@ -4377,7 +4360,7 @@ static void i915_irq_uninstall(struct drm_device * dev)
|
||||
}
|
||||
|
||||
I915_WRITE16(HWSTAM, 0xffff);
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
/* Clear enable bits; then clear status bits */
|
||||
I915_WRITE(PIPESTAT(pipe), 0);
|
||||
I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe)));
|
||||
@ -4397,7 +4380,7 @@ static void i965_irq_preinstall(struct drm_device * dev)
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
|
||||
|
||||
I915_WRITE(HWSTAM, 0xeffe);
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
I915_WRITE(PIPESTAT(pipe), 0);
|
||||
I915_WRITE(IMR, 0xffffffff);
|
||||
I915_WRITE(IER, 0x0);
|
||||
@ -4522,7 +4505,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
|
||||
"Command parser error, iir 0x%08x",
|
||||
iir);
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
int reg = PIPESTAT(pipe);
|
||||
pipe_stats[pipe] = I915_READ(reg);
|
||||
|
||||
@ -4553,7 +4536,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
|
||||
if (iir & I915_BSD_USER_INTERRUPT)
|
||||
notify_ring(dev, &dev_priv->ring[VCS]);
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
|
||||
i915_handle_vblank(dev, pipe, pipe, iir))
|
||||
flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe);
|
||||
@ -4610,12 +4593,12 @@ static void i965_irq_uninstall(struct drm_device * dev)
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
|
||||
|
||||
I915_WRITE(HWSTAM, 0xffffffff);
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
I915_WRITE(PIPESTAT(pipe), 0);
|
||||
I915_WRITE(IMR, 0xffffffff);
|
||||
I915_WRITE(IER, 0x0);
|
||||
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
I915_WRITE(PIPESTAT(pipe),
|
||||
I915_READ(PIPESTAT(pipe)) & 0x8000ffff);
|
||||
I915_WRITE(IIR, I915_READ(IIR));
|
||||
@ -4673,8 +4656,8 @@ void intel_irq_init(struct drm_device *dev)
|
||||
INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
|
||||
|
||||
/* Let's track the enabled rps events */
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
/* WaGsvRC0ResidenncyMethod:VLV */
|
||||
if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev))
|
||||
/* WaGsvRC0ResidencyMethod:vlv */
|
||||
dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
|
||||
else
|
||||
dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
|
||||
|
@ -1030,6 +1030,13 @@ enum punit_power_well {
|
||||
#define PGTBL_ADDRESS_LO_MASK 0xfffff000 /* bits [31:12] */
|
||||
#define PGTBL_ADDRESS_HI_MASK 0x000000f0 /* bits [35:32] (gen4) */
|
||||
#define PGTBL_ER 0x02024
|
||||
#define PRB0_BASE (0x2030-0x30)
|
||||
#define PRB1_BASE (0x2040-0x30) /* 830,gen3 */
|
||||
#define PRB2_BASE (0x2050-0x30) /* gen3 */
|
||||
#define SRB0_BASE (0x2100-0x30) /* gen2 */
|
||||
#define SRB1_BASE (0x2110-0x30) /* gen2 */
|
||||
#define SRB2_BASE (0x2120-0x30) /* 830 */
|
||||
#define SRB3_BASE (0x2130-0x30) /* 830 */
|
||||
#define RENDER_RING_BASE 0x02000
|
||||
#define BSD_RING_BASE 0x04000
|
||||
#define GEN6_BSD_RING_BASE 0x12000
|
||||
@ -1276,6 +1283,10 @@ enum punit_power_well {
|
||||
#define INSTPM_TLB_INVALIDATE (1<<9)
|
||||
#define INSTPM_SYNC_FLUSH (1<<5)
|
||||
#define ACTHD 0x020c8
|
||||
#define MEM_MODE 0x020cc
|
||||
#define MEM_DISPLAY_B_TRICKLE_FEED_DISABLE (1<<3) /* 830 only */
|
||||
#define MEM_DISPLAY_A_TRICKLE_FEED_DISABLE (1<<2) /* 830/845 only */
|
||||
#define MEM_DISPLAY_TRICKLE_FEED_DISABLE (1<<2) /* 85x only */
|
||||
#define FW_BLC 0x020d8
|
||||
#define FW_BLC2 0x020dc
|
||||
#define FW_BLC_SELF 0x020e0 /* 915+ only */
|
||||
@ -4218,6 +4229,7 @@ enum punit_power_well {
|
||||
#define DISPPLANE_NO_LINE_DOUBLE 0
|
||||
#define DISPPLANE_STEREO_POLARITY_FIRST 0
|
||||
#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18)
|
||||
#define DISPPLANE_ROTATE_180 (1<<15)
|
||||
#define DISPPLANE_TRICKLE_FEED_DISABLE (1<<14) /* Ironlake */
|
||||
#define DISPPLANE_TILED (1<<10)
|
||||
#define _DSPAADDR 0x70184
|
||||
@ -5356,8 +5368,7 @@ enum punit_power_well {
|
||||
#define PIPEA_PP_STATUS (VLV_DISPLAY_BASE + 0x61200)
|
||||
#define PIPEA_PP_CONTROL (VLV_DISPLAY_BASE + 0x61204)
|
||||
#define PIPEA_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61208)
|
||||
#define PANEL_PORT_SELECT_DPB_VLV (1 << 30)
|
||||
#define PANEL_PORT_SELECT_DPC_VLV (2 << 30)
|
||||
#define PANEL_PORT_SELECT_VLV(port) ((port) << 30)
|
||||
#define PIPEA_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6120c)
|
||||
#define PIPEA_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61210)
|
||||
|
||||
@ -5566,6 +5577,10 @@ enum punit_power_well {
|
||||
#define GEN8_UCGCTL6 0x9430
|
||||
#define GEN8_SDEUNIT_CLOCK_GATE_DISABLE (1<<14)
|
||||
|
||||
#define TIMESTAMP_CTR 0x44070
|
||||
#define FREQ_1_28_US(us) (((us) * 100) >> 7)
|
||||
#define MCHBAR_PCU_C0 (MCHBAR_MIRROR_BASE_SNB + 0x5960)
|
||||
|
||||
#define GEN6_GFXPAUSE 0xA000
|
||||
#define GEN6_RPNSWREQ 0xA008
|
||||
#define GEN6_TURBO_DISABLE (1<<31)
|
||||
@ -5654,12 +5669,6 @@ enum punit_power_well {
|
||||
GEN6_PM_RP_DOWN_THRESHOLD | \
|
||||
GEN6_PM_RP_DOWN_TIMEOUT)
|
||||
|
||||
#define CHV_CZ_CLOCK_FREQ_MODE_200 200
|
||||
#define CHV_CZ_CLOCK_FREQ_MODE_267 267
|
||||
#define CHV_CZ_CLOCK_FREQ_MODE_320 320
|
||||
#define CHV_CZ_CLOCK_FREQ_MODE_333 333
|
||||
#define CHV_CZ_CLOCK_FREQ_MODE_400 400
|
||||
|
||||
#define GEN7_GT_SCRATCH_BASE 0x4F100
|
||||
#define GEN7_GT_SCRATCH_REG_NUM 8
|
||||
|
||||
@ -5975,15 +5984,7 @@ enum punit_power_well {
|
||||
#define DDI_BUF_CTL_B 0x64100
|
||||
#define DDI_BUF_CTL(port) _PORT(port, DDI_BUF_CTL_A, DDI_BUF_CTL_B)
|
||||
#define DDI_BUF_CTL_ENABLE (1<<31)
|
||||
#define DDI_BUF_EMP_400MV_0DB_HSW (0<<24) /* Sel0 */
|
||||
#define DDI_BUF_EMP_400MV_3_5DB_HSW (1<<24) /* Sel1 */
|
||||
#define DDI_BUF_EMP_400MV_6DB_HSW (2<<24) /* Sel2 */
|
||||
#define DDI_BUF_EMP_400MV_9_5DB_HSW (3<<24) /* Sel3 */
|
||||
#define DDI_BUF_EMP_600MV_0DB_HSW (4<<24) /* Sel4 */
|
||||
#define DDI_BUF_EMP_600MV_3_5DB_HSW (5<<24) /* Sel5 */
|
||||
#define DDI_BUF_EMP_600MV_6DB_HSW (6<<24) /* Sel6 */
|
||||
#define DDI_BUF_EMP_800MV_0DB_HSW (7<<24) /* Sel7 */
|
||||
#define DDI_BUF_EMP_800MV_3_5DB_HSW (8<<24) /* Sel8 */
|
||||
#define DDI_BUF_TRANS_SELECT(n) ((n) << 24)
|
||||
#define DDI_BUF_EMP_MASK (0xf<<24)
|
||||
#define DDI_BUF_PORT_REVERSAL (1<<16)
|
||||
#define DDI_BUF_IS_IDLE (1<<7)
|
||||
|
@ -540,7 +540,7 @@ static ssize_t error_state_read(struct file *filp, struct kobject *kobj,
|
||||
|
||||
memset(&error_priv, 0, sizeof(error_priv));
|
||||
|
||||
ret = i915_error_state_buf_init(&error_str, count, off);
|
||||
ret = i915_error_state_buf_init(&error_str, to_i915(dev), count, off);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -627,16 +627,16 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
|
||||
|
||||
switch (edp_link_params->preemphasis) {
|
||||
case EDP_PREEMPHASIS_NONE:
|
||||
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
|
||||
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_0;
|
||||
break;
|
||||
case EDP_PREEMPHASIS_3_5dB:
|
||||
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
|
||||
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_1;
|
||||
break;
|
||||
case EDP_PREEMPHASIS_6dB:
|
||||
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
|
||||
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_2;
|
||||
break;
|
||||
case EDP_PREEMPHASIS_9_5dB:
|
||||
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
|
||||
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_3;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_KMS("VBT has unknown eDP pre-emphasis value %u\n",
|
||||
@ -646,16 +646,16 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
|
||||
|
||||
switch (edp_link_params->vswing) {
|
||||
case EDP_VSWING_0_4V:
|
||||
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_400;
|
||||
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
|
||||
break;
|
||||
case EDP_VSWING_0_6V:
|
||||
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_600;
|
||||
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_1;
|
||||
break;
|
||||
case EDP_VSWING_0_8V:
|
||||
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_800;
|
||||
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
|
||||
break;
|
||||
case EDP_VSWING_1_2V:
|
||||
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_1200;
|
||||
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_KMS("VBT has unknown eDP voltage swing value %u\n",
|
||||
|
@ -28,98 +28,103 @@
|
||||
#include "i915_drv.h"
|
||||
#include "intel_drv.h"
|
||||
|
||||
struct ddi_buf_trans {
|
||||
u32 trans1; /* balance leg enable, de-emph level */
|
||||
u32 trans2; /* vref sel, vswing */
|
||||
};
|
||||
|
||||
/* HDMI/DVI modes ignore everything but the last 2 items. So we share
|
||||
* them for both DP and FDI transports, allowing those ports to
|
||||
* automatically adapt to HDMI connections as well
|
||||
*/
|
||||
static const u32 hsw_ddi_translations_dp[] = {
|
||||
0x00FFFFFF, 0x0006000E,
|
||||
0x00D75FFF, 0x0005000A,
|
||||
0x00C30FFF, 0x00040006,
|
||||
0x80AAAFFF, 0x000B0000,
|
||||
0x00FFFFFF, 0x0005000A,
|
||||
0x00D75FFF, 0x000C0004,
|
||||
0x80C30FFF, 0x000B0000,
|
||||
0x00FFFFFF, 0x00040006,
|
||||
0x80D75FFF, 0x000B0000,
|
||||
static const struct ddi_buf_trans hsw_ddi_translations_dp[] = {
|
||||
{ 0x00FFFFFF, 0x0006000E },
|
||||
{ 0x00D75FFF, 0x0005000A },
|
||||
{ 0x00C30FFF, 0x00040006 },
|
||||
{ 0x80AAAFFF, 0x000B0000 },
|
||||
{ 0x00FFFFFF, 0x0005000A },
|
||||
{ 0x00D75FFF, 0x000C0004 },
|
||||
{ 0x80C30FFF, 0x000B0000 },
|
||||
{ 0x00FFFFFF, 0x00040006 },
|
||||
{ 0x80D75FFF, 0x000B0000 },
|
||||
};
|
||||
|
||||
static const u32 hsw_ddi_translations_fdi[] = {
|
||||
0x00FFFFFF, 0x0007000E,
|
||||
0x00D75FFF, 0x000F000A,
|
||||
0x00C30FFF, 0x00060006,
|
||||
0x00AAAFFF, 0x001E0000,
|
||||
0x00FFFFFF, 0x000F000A,
|
||||
0x00D75FFF, 0x00160004,
|
||||
0x00C30FFF, 0x001E0000,
|
||||
0x00FFFFFF, 0x00060006,
|
||||
0x00D75FFF, 0x001E0000,
|
||||
static const struct ddi_buf_trans hsw_ddi_translations_fdi[] = {
|
||||
{ 0x00FFFFFF, 0x0007000E },
|
||||
{ 0x00D75FFF, 0x000F000A },
|
||||
{ 0x00C30FFF, 0x00060006 },
|
||||
{ 0x00AAAFFF, 0x001E0000 },
|
||||
{ 0x00FFFFFF, 0x000F000A },
|
||||
{ 0x00D75FFF, 0x00160004 },
|
||||
{ 0x00C30FFF, 0x001E0000 },
|
||||
{ 0x00FFFFFF, 0x00060006 },
|
||||
{ 0x00D75FFF, 0x001E0000 },
|
||||
};
|
||||
|
||||
static const u32 hsw_ddi_translations_hdmi[] = {
|
||||
/* Idx NT mV diff T mV diff db */
|
||||
0x00FFFFFF, 0x0006000E, /* 0: 400 400 0 */
|
||||
0x00E79FFF, 0x000E000C, /* 1: 400 500 2 */
|
||||
0x00D75FFF, 0x0005000A, /* 2: 400 600 3.5 */
|
||||
0x00FFFFFF, 0x0005000A, /* 3: 600 600 0 */
|
||||
0x00E79FFF, 0x001D0007, /* 4: 600 750 2 */
|
||||
0x00D75FFF, 0x000C0004, /* 5: 600 900 3.5 */
|
||||
0x00FFFFFF, 0x00040006, /* 6: 800 800 0 */
|
||||
0x80E79FFF, 0x00030002, /* 7: 800 1000 2 */
|
||||
0x00FFFFFF, 0x00140005, /* 8: 850 850 0 */
|
||||
0x00FFFFFF, 0x000C0004, /* 9: 900 900 0 */
|
||||
0x00FFFFFF, 0x001C0003, /* 10: 950 950 0 */
|
||||
0x80FFFFFF, 0x00030002, /* 11: 1000 1000 0 */
|
||||
static const struct ddi_buf_trans hsw_ddi_translations_hdmi[] = {
|
||||
/* Idx NT mV d T mV d db */
|
||||
{ 0x00FFFFFF, 0x0006000E }, /* 0: 400 400 0 */
|
||||
{ 0x00E79FFF, 0x000E000C }, /* 1: 400 500 2 */
|
||||
{ 0x00D75FFF, 0x0005000A }, /* 2: 400 600 3.5 */
|
||||
{ 0x00FFFFFF, 0x0005000A }, /* 3: 600 600 0 */
|
||||
{ 0x00E79FFF, 0x001D0007 }, /* 4: 600 750 2 */
|
||||
{ 0x00D75FFF, 0x000C0004 }, /* 5: 600 900 3.5 */
|
||||
{ 0x00FFFFFF, 0x00040006 }, /* 6: 800 800 0 */
|
||||
{ 0x80E79FFF, 0x00030002 }, /* 7: 800 1000 2 */
|
||||
{ 0x00FFFFFF, 0x00140005 }, /* 8: 850 850 0 */
|
||||
{ 0x00FFFFFF, 0x000C0004 }, /* 9: 900 900 0 */
|
||||
{ 0x00FFFFFF, 0x001C0003 }, /* 10: 950 950 0 */
|
||||
{ 0x80FFFFFF, 0x00030002 }, /* 11: 1000 1000 0 */
|
||||
};
|
||||
|
||||
static const u32 bdw_ddi_translations_edp[] = {
|
||||
0x00FFFFFF, 0x00000012,
|
||||
0x00EBAFFF, 0x00020011,
|
||||
0x00C71FFF, 0x0006000F,
|
||||
0x00AAAFFF, 0x000E000A,
|
||||
0x00FFFFFF, 0x00020011,
|
||||
0x00DB6FFF, 0x0005000F,
|
||||
0x00BEEFFF, 0x000A000C,
|
||||
0x00FFFFFF, 0x0005000F,
|
||||
0x00DB6FFF, 0x000A000C,
|
||||
static const struct ddi_buf_trans bdw_ddi_translations_edp[] = {
|
||||
{ 0x00FFFFFF, 0x00000012 },
|
||||
{ 0x00EBAFFF, 0x00020011 },
|
||||
{ 0x00C71FFF, 0x0006000F },
|
||||
{ 0x00AAAFFF, 0x000E000A },
|
||||
{ 0x00FFFFFF, 0x00020011 },
|
||||
{ 0x00DB6FFF, 0x0005000F },
|
||||
{ 0x00BEEFFF, 0x000A000C },
|
||||
{ 0x00FFFFFF, 0x0005000F },
|
||||
{ 0x00DB6FFF, 0x000A000C },
|
||||
};
|
||||
|
||||
static const u32 bdw_ddi_translations_dp[] = {
|
||||
0x00FFFFFF, 0x0007000E,
|
||||
0x00D75FFF, 0x000E000A,
|
||||
0x00BEFFFF, 0x00140006,
|
||||
0x80B2CFFF, 0x001B0002,
|
||||
0x00FFFFFF, 0x000E000A,
|
||||
0x00D75FFF, 0x00180004,
|
||||
0x80CB2FFF, 0x001B0002,
|
||||
0x00F7DFFF, 0x00180004,
|
||||
0x80D75FFF, 0x001B0002,
|
||||
static const struct ddi_buf_trans bdw_ddi_translations_dp[] = {
|
||||
{ 0x00FFFFFF, 0x0007000E },
|
||||
{ 0x00D75FFF, 0x000E000A },
|
||||
{ 0x00BEFFFF, 0x00140006 },
|
||||
{ 0x80B2CFFF, 0x001B0002 },
|
||||
{ 0x00FFFFFF, 0x000E000A },
|
||||
{ 0x00D75FFF, 0x00180004 },
|
||||
{ 0x80CB2FFF, 0x001B0002 },
|
||||
{ 0x00F7DFFF, 0x00180004 },
|
||||
{ 0x80D75FFF, 0x001B0002 },
|
||||
};
|
||||
|
||||
static const u32 bdw_ddi_translations_fdi[] = {
|
||||
0x00FFFFFF, 0x0001000E,
|
||||
0x00D75FFF, 0x0004000A,
|
||||
0x00C30FFF, 0x00070006,
|
||||
0x00AAAFFF, 0x000C0000,
|
||||
0x00FFFFFF, 0x0004000A,
|
||||
0x00D75FFF, 0x00090004,
|
||||
0x00C30FFF, 0x000C0000,
|
||||
0x00FFFFFF, 0x00070006,
|
||||
0x00D75FFF, 0x000C0000,
|
||||
static const struct ddi_buf_trans bdw_ddi_translations_fdi[] = {
|
||||
{ 0x00FFFFFF, 0x0001000E },
|
||||
{ 0x00D75FFF, 0x0004000A },
|
||||
{ 0x00C30FFF, 0x00070006 },
|
||||
{ 0x00AAAFFF, 0x000C0000 },
|
||||
{ 0x00FFFFFF, 0x0004000A },
|
||||
{ 0x00D75FFF, 0x00090004 },
|
||||
{ 0x00C30FFF, 0x000C0000 },
|
||||
{ 0x00FFFFFF, 0x00070006 },
|
||||
{ 0x00D75FFF, 0x000C0000 },
|
||||
};
|
||||
|
||||
static const u32 bdw_ddi_translations_hdmi[] = {
|
||||
/* Idx NT mV diff T mV diff db */
|
||||
0x00FFFFFF, 0x0007000E, /* 0: 400 400 0 */
|
||||
0x00D75FFF, 0x000E000A, /* 1: 400 600 3.5 */
|
||||
0x00BEFFFF, 0x00140006, /* 2: 400 800 6 */
|
||||
0x00FFFFFF, 0x0009000D, /* 3: 450 450 0 */
|
||||
0x00FFFFFF, 0x000E000A, /* 4: 600 600 0 */
|
||||
0x00D7FFFF, 0x00140006, /* 5: 600 800 2.5 */
|
||||
0x80CB2FFF, 0x001B0002, /* 6: 600 1000 4.5 */
|
||||
0x00FFFFFF, 0x00140006, /* 7: 800 800 0 */
|
||||
0x80E79FFF, 0x001B0002, /* 8: 800 1000 2 */
|
||||
0x80FFFFFF, 0x001B0002, /* 9: 1000 1000 0 */
|
||||
static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = {
|
||||
/* Idx NT mV d T mV df db */
|
||||
{ 0x00FFFFFF, 0x0007000E }, /* 0: 400 400 0 */
|
||||
{ 0x00D75FFF, 0x000E000A }, /* 1: 400 600 3.5 */
|
||||
{ 0x00BEFFFF, 0x00140006 }, /* 2: 400 800 6 */
|
||||
{ 0x00FFFFFF, 0x0009000D }, /* 3: 450 450 0 */
|
||||
{ 0x00FFFFFF, 0x000E000A }, /* 4: 600 600 0 */
|
||||
{ 0x00D7FFFF, 0x00140006 }, /* 5: 600 800 2.5 */
|
||||
{ 0x80CB2FFF, 0x001B0002 }, /* 6: 600 1000 4.5 */
|
||||
{ 0x00FFFFFF, 0x00140006 }, /* 7: 800 800 0 */
|
||||
{ 0x80E79FFF, 0x001B0002 }, /* 8: 800 1000 2 */
|
||||
{ 0x80FFFFFF, 0x001B0002 }, /* 9: 1000 1000 0 */
|
||||
};
|
||||
|
||||
enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
|
||||
@ -158,25 +163,25 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
|
||||
u32 reg;
|
||||
int i, n_hdmi_entries, hdmi_800mV_0dB;
|
||||
int hdmi_level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift;
|
||||
const u32 *ddi_translations_fdi;
|
||||
const u32 *ddi_translations_dp;
|
||||
const u32 *ddi_translations_edp;
|
||||
const u32 *ddi_translations_hdmi;
|
||||
const u32 *ddi_translations;
|
||||
const struct ddi_buf_trans *ddi_translations_fdi;
|
||||
const struct ddi_buf_trans *ddi_translations_dp;
|
||||
const struct ddi_buf_trans *ddi_translations_edp;
|
||||
const struct ddi_buf_trans *ddi_translations_hdmi;
|
||||
const struct ddi_buf_trans *ddi_translations;
|
||||
|
||||
if (IS_BROADWELL(dev)) {
|
||||
ddi_translations_fdi = bdw_ddi_translations_fdi;
|
||||
ddi_translations_dp = bdw_ddi_translations_dp;
|
||||
ddi_translations_edp = bdw_ddi_translations_edp;
|
||||
ddi_translations_hdmi = bdw_ddi_translations_hdmi;
|
||||
n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi) / 2;
|
||||
n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
|
||||
hdmi_800mV_0dB = 7;
|
||||
} else if (IS_HASWELL(dev)) {
|
||||
ddi_translations_fdi = hsw_ddi_translations_fdi;
|
||||
ddi_translations_dp = hsw_ddi_translations_dp;
|
||||
ddi_translations_edp = hsw_ddi_translations_dp;
|
||||
ddi_translations_hdmi = hsw_ddi_translations_hdmi;
|
||||
n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi) / 2;
|
||||
n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi);
|
||||
hdmi_800mV_0dB = 6;
|
||||
} else {
|
||||
WARN(1, "ddi translation table missing\n");
|
||||
@ -184,7 +189,7 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
|
||||
ddi_translations_fdi = bdw_ddi_translations_fdi;
|
||||
ddi_translations_dp = bdw_ddi_translations_dp;
|
||||
ddi_translations_hdmi = bdw_ddi_translations_hdmi;
|
||||
n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi) / 2;
|
||||
n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
|
||||
hdmi_800mV_0dB = 7;
|
||||
}
|
||||
|
||||
@ -211,7 +216,9 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
|
||||
|
||||
for (i = 0, reg = DDI_BUF_TRANS(port);
|
||||
i < ARRAY_SIZE(hsw_ddi_translations_fdi); i++) {
|
||||
I915_WRITE(reg, ddi_translations[i]);
|
||||
I915_WRITE(reg, ddi_translations[i].trans1);
|
||||
reg += 4;
|
||||
I915_WRITE(reg, ddi_translations[i].trans2);
|
||||
reg += 4;
|
||||
}
|
||||
|
||||
@ -221,10 +228,10 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
|
||||
hdmi_level = hdmi_800mV_0dB;
|
||||
|
||||
/* Entry 9 is for HDMI: */
|
||||
for (i = 0; i < 2; i++) {
|
||||
I915_WRITE(reg, ddi_translations_hdmi[hdmi_level * 2 + i]);
|
||||
reg += 4;
|
||||
}
|
||||
I915_WRITE(reg, ddi_translations_hdmi[hdmi_level].trans1);
|
||||
reg += 4;
|
||||
I915_WRITE(reg, ddi_translations_hdmi[hdmi_level].trans2);
|
||||
reg += 4;
|
||||
}
|
||||
|
||||
/* Program DDI buffers translations for DP. By default, program ports A-D in DP
|
||||
@ -241,18 +248,6 @@ void intel_prepare_ddi(struct drm_device *dev)
|
||||
intel_prepare_ddi_buffers(dev, port);
|
||||
}
|
||||
|
||||
static const long hsw_ddi_buf_ctl_values[] = {
|
||||
DDI_BUF_EMP_400MV_0DB_HSW,
|
||||
DDI_BUF_EMP_400MV_3_5DB_HSW,
|
||||
DDI_BUF_EMP_400MV_6DB_HSW,
|
||||
DDI_BUF_EMP_400MV_9_5DB_HSW,
|
||||
DDI_BUF_EMP_600MV_0DB_HSW,
|
||||
DDI_BUF_EMP_600MV_3_5DB_HSW,
|
||||
DDI_BUF_EMP_600MV_6DB_HSW,
|
||||
DDI_BUF_EMP_800MV_0DB_HSW,
|
||||
DDI_BUF_EMP_800MV_3_5DB_HSW
|
||||
};
|
||||
|
||||
static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
|
||||
enum port port)
|
||||
{
|
||||
@ -312,7 +307,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
|
||||
|
||||
/* Start the training iterating through available voltages and emphasis,
|
||||
* testing each value twice. */
|
||||
for (i = 0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values) * 2; i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(hsw_ddi_translations_fdi) * 2; i++) {
|
||||
/* Configure DP_TP_CTL with auto-training */
|
||||
I915_WRITE(DP_TP_CTL(PORT_E),
|
||||
DP_TP_CTL_FDI_AUTOTRAIN |
|
||||
@ -327,7 +322,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
|
||||
I915_WRITE(DDI_BUF_CTL(PORT_E),
|
||||
DDI_BUF_CTL_ENABLE |
|
||||
((intel_crtc->config.fdi_lanes - 1) << 1) |
|
||||
hsw_ddi_buf_ctl_values[i / 2]);
|
||||
DDI_BUF_TRANS_SELECT(i / 2));
|
||||
POSTING_READ(DDI_BUF_CTL(PORT_E));
|
||||
|
||||
udelay(600);
|
||||
@ -402,7 +397,7 @@ void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder)
|
||||
enc_to_dig_port(&encoder->base);
|
||||
|
||||
intel_dp->DP = intel_dig_port->saved_port_bits |
|
||||
DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW;
|
||||
DDI_BUF_CTL_ENABLE | DDI_BUF_TRANS_SELECT(0);
|
||||
intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count);
|
||||
|
||||
}
|
||||
@ -429,7 +424,7 @@ intel_ddi_get_crtc_encoder(struct drm_crtc *crtc)
|
||||
}
|
||||
|
||||
#define LC_FREQ 2700
|
||||
#define LC_FREQ_2K (LC_FREQ * 2000)
|
||||
#define LC_FREQ_2K U64_C(LC_FREQ * 2000)
|
||||
|
||||
#define P_MIN 2
|
||||
#define P_MAX 64
|
||||
@ -441,7 +436,11 @@ intel_ddi_get_crtc_encoder(struct drm_crtc *crtc)
|
||||
#define VCO_MIN 2400
|
||||
#define VCO_MAX 4800
|
||||
|
||||
#define ABS_DIFF(a, b) ((a > b) ? (a - b) : (b - a))
|
||||
#define abs_diff(a, b) ({ \
|
||||
typeof(a) __a = (a); \
|
||||
typeof(b) __b = (b); \
|
||||
(void) (&__a == &__b); \
|
||||
__a > __b ? (__a - __b) : (__b - __a); })
|
||||
|
||||
struct wrpll_rnp {
|
||||
unsigned p, n2, r2;
|
||||
@ -551,9 +550,9 @@ static void wrpll_update_rnp(uint64_t freq2k, unsigned budget,
|
||||
*/
|
||||
a = freq2k * budget * p * r2;
|
||||
b = freq2k * budget * best->p * best->r2;
|
||||
diff = ABS_DIFF((freq2k * p * r2), (LC_FREQ_2K * n2));
|
||||
diff_best = ABS_DIFF((freq2k * best->p * best->r2),
|
||||
(LC_FREQ_2K * best->n2));
|
||||
diff = abs_diff(freq2k * p * r2, LC_FREQ_2K * n2);
|
||||
diff_best = abs_diff(freq2k * best->p * best->r2,
|
||||
LC_FREQ_2K * best->n2);
|
||||
c = 1000000 * diff;
|
||||
d = 1000000 * diff_best;
|
||||
|
||||
|
@ -900,7 +900,8 @@ static void g4x_wait_for_vblank(struct drm_device *dev, int pipe)
|
||||
frame = I915_READ(frame_reg);
|
||||
|
||||
if (wait_for(I915_READ_NOTRACE(frame_reg) != frame, 50))
|
||||
WARN(1, "vblank wait timed out\n");
|
||||
WARN(1, "vblank wait on pipe %c timed out\n",
|
||||
pipe_name(pipe));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -941,7 +942,8 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
|
||||
if (wait_for(I915_READ(pipestat_reg) &
|
||||
PIPE_VBLANK_INTERRUPT_STATUS,
|
||||
50))
|
||||
DRM_DEBUG_KMS("vblank wait timed out\n");
|
||||
DRM_DEBUG_KMS("vblank wait on pipe %c timed out\n",
|
||||
pipe_name(pipe));
|
||||
}
|
||||
|
||||
static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe)
|
||||
@ -965,8 +967,7 @@ static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe)
|
||||
|
||||
/*
|
||||
* intel_wait_for_pipe_off - wait for pipe to turn off
|
||||
* @dev: drm device
|
||||
* @pipe: pipe to wait for
|
||||
* @crtc: crtc whose pipe to wait for
|
||||
*
|
||||
* After disabling a pipe, we can't wait for vblank in the usual way,
|
||||
* spinning on the vblank interrupt status bit, since we won't actually
|
||||
@ -980,11 +981,12 @@ static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe)
|
||||
* ends up stopping at the start of the next frame).
|
||||
*
|
||||
*/
|
||||
void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
|
||||
static void intel_wait_for_pipe_off(struct intel_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
|
||||
pipe);
|
||||
enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
|
||||
enum pipe pipe = crtc->pipe;
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
int reg = PIPECONF(cpu_transcoder);
|
||||
@ -1193,27 +1195,40 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
|
||||
static void assert_panel_unlocked(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe)
|
||||
{
|
||||
int pp_reg, lvds_reg;
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
int pp_reg;
|
||||
u32 val;
|
||||
enum pipe panel_pipe = PIPE_A;
|
||||
bool locked = true;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev_priv->dev)) {
|
||||
if (WARN_ON(HAS_DDI(dev)))
|
||||
return;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
u32 port_sel;
|
||||
|
||||
pp_reg = PCH_PP_CONTROL;
|
||||
lvds_reg = PCH_LVDS;
|
||||
port_sel = I915_READ(PCH_PP_ON_DELAYS) & PANEL_PORT_SELECT_MASK;
|
||||
|
||||
if (port_sel == PANEL_PORT_SELECT_LVDS &&
|
||||
I915_READ(PCH_LVDS) & LVDS_PIPEB_SELECT)
|
||||
panel_pipe = PIPE_B;
|
||||
/* XXX: else fix for eDP */
|
||||
} else if (IS_VALLEYVIEW(dev)) {
|
||||
/* presumably write lock depends on pipe, not port select */
|
||||
pp_reg = VLV_PIPE_PP_CONTROL(pipe);
|
||||
panel_pipe = pipe;
|
||||
} else {
|
||||
pp_reg = PP_CONTROL;
|
||||
lvds_reg = LVDS;
|
||||
if (I915_READ(LVDS) & LVDS_PIPEB_SELECT)
|
||||
panel_pipe = PIPE_B;
|
||||
}
|
||||
|
||||
val = I915_READ(pp_reg);
|
||||
if (!(val & PANEL_POWER_ON) ||
|
||||
((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS))
|
||||
((val & PANEL_UNLOCK_MASK) == PANEL_UNLOCK_REGS))
|
||||
locked = false;
|
||||
|
||||
if (I915_READ(lvds_reg) & LVDS_PIPEB_SELECT)
|
||||
panel_pipe = PIPE_B;
|
||||
|
||||
WARN(panel_pipe == pipe && locked,
|
||||
"panel assertion failure, pipe %c regs locked\n",
|
||||
pipe_name(pipe));
|
||||
@ -1246,8 +1261,9 @@ void assert_pipe(struct drm_i915_private *dev_priv,
|
||||
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
|
||||
pipe);
|
||||
|
||||
/* if we need the pipe A quirk it must be always on */
|
||||
if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
|
||||
/* if we need the pipe quirk it must be always on */
|
||||
if ((pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) ||
|
||||
(pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
|
||||
state = true;
|
||||
|
||||
if (!intel_display_power_enabled(dev_priv,
|
||||
@ -1301,7 +1317,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
|
||||
}
|
||||
|
||||
/* Need to check both planes against the pipe */
|
||||
for_each_pipe(i) {
|
||||
for_each_pipe(dev_priv, i) {
|
||||
reg = DSPCNTR(i);
|
||||
val = I915_READ(reg);
|
||||
cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
|
||||
@ -1533,7 +1549,7 @@ static void vlv_enable_pll(struct intel_crtc *crtc)
|
||||
BUG_ON(!IS_VALLEYVIEW(dev_priv->dev));
|
||||
|
||||
/* PLL is protected by panel, make sure we can write it */
|
||||
if (IS_MOBILE(dev_priv->dev) && !IS_I830(dev_priv->dev))
|
||||
if (IS_MOBILE(dev_priv->dev))
|
||||
assert_panel_unlocked(dev_priv, crtc->pipe);
|
||||
|
||||
I915_WRITE(reg, dpll);
|
||||
@ -1653,8 +1669,9 @@ static void i9xx_enable_pll(struct intel_crtc *crtc)
|
||||
*/
|
||||
static void i9xx_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
|
||||
{
|
||||
/* Don't disable pipe A or pipe A PLLs if needed */
|
||||
if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
|
||||
/* Don't disable pipe or pipe PLLs if needed */
|
||||
if ((pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) ||
|
||||
(pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
|
||||
return;
|
||||
|
||||
/* Make sure the pipe isn't still relying on us */
|
||||
@ -1847,7 +1864,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
|
||||
uint32_t reg, val, pipeconf_val;
|
||||
|
||||
/* PCH only available on ILK+ */
|
||||
BUG_ON(INTEL_INFO(dev)->gen < 5);
|
||||
BUG_ON(!HAS_PCH_SPLIT(dev));
|
||||
|
||||
/* Make sure PCH DPLL is enabled */
|
||||
assert_shared_dpll_enabled(dev_priv,
|
||||
@ -1900,7 +1917,7 @@ static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv,
|
||||
u32 val, pipeconf_val;
|
||||
|
||||
/* PCH only available on ILK+ */
|
||||
BUG_ON(INTEL_INFO(dev_priv->dev)->gen < 5);
|
||||
BUG_ON(!HAS_PCH_SPLIT(dev_priv->dev));
|
||||
|
||||
/* FDI must be feeding us bits for PCH ports */
|
||||
assert_fdi_tx_enabled(dev_priv, (enum pipe) cpu_transcoder);
|
||||
@ -2022,8 +2039,8 @@ static void intel_enable_pipe(struct intel_crtc *crtc)
|
||||
reg = PIPECONF(cpu_transcoder);
|
||||
val = I915_READ(reg);
|
||||
if (val & PIPECONF_ENABLE) {
|
||||
WARN_ON(!(pipe == PIPE_A &&
|
||||
dev_priv->quirks & QUIRK_PIPEA_FORCE));
|
||||
WARN_ON(!((pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) ||
|
||||
(pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE)));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2033,21 +2050,19 @@ static void intel_enable_pipe(struct intel_crtc *crtc)
|
||||
|
||||
/**
|
||||
* intel_disable_pipe - disable a pipe, asserting requirements
|
||||
* @dev_priv: i915 private structure
|
||||
* @pipe: pipe to disable
|
||||
* @crtc: crtc whose pipes is to be disabled
|
||||
*
|
||||
* Disable @pipe, making sure that various hardware specific requirements
|
||||
* are met, if applicable, e.g. plane disabled, panel fitter off, etc.
|
||||
*
|
||||
* @pipe should be %PIPE_A or %PIPE_B.
|
||||
* Disable the pipe of @crtc, making sure that various hardware
|
||||
* specific requirements are met, if applicable, e.g. plane
|
||||
* disabled, panel fitter off, etc.
|
||||
*
|
||||
* Will wait until the pipe has shut down before returning.
|
||||
*/
|
||||
static void intel_disable_pipe(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe)
|
||||
static void intel_disable_pipe(struct intel_crtc *crtc)
|
||||
{
|
||||
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
|
||||
pipe);
|
||||
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
|
||||
enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
|
||||
enum pipe pipe = crtc->pipe;
|
||||
int reg;
|
||||
u32 val;
|
||||
|
||||
@ -2059,17 +2074,26 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv,
|
||||
assert_cursor_disabled(dev_priv, pipe);
|
||||
assert_sprites_disabled(dev_priv, pipe);
|
||||
|
||||
/* Don't disable pipe A or pipe A PLLs if needed */
|
||||
if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
|
||||
return;
|
||||
|
||||
reg = PIPECONF(cpu_transcoder);
|
||||
val = I915_READ(reg);
|
||||
if ((val & PIPECONF_ENABLE) == 0)
|
||||
return;
|
||||
|
||||
I915_WRITE(reg, val & ~PIPECONF_ENABLE);
|
||||
intel_wait_for_pipe_off(dev_priv->dev, pipe);
|
||||
/*
|
||||
* Double wide has implications for planes
|
||||
* so best keep it disabled when not needed.
|
||||
*/
|
||||
if (crtc->config.double_wide)
|
||||
val &= ~PIPECONF_DOUBLE_WIDE;
|
||||
|
||||
/* Don't disable pipe or pipe PLLs if needed */
|
||||
if (!(pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) &&
|
||||
!(pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
|
||||
val &= ~PIPECONF_ENABLE;
|
||||
|
||||
I915_WRITE(reg, val);
|
||||
if ((val & PIPECONF_ENABLE) == 0)
|
||||
intel_wait_for_pipe_off(crtc);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2390,11 +2414,12 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
|
||||
struct drm_i915_gem_object *obj;
|
||||
int plane = intel_crtc->plane;
|
||||
unsigned long linear_offset;
|
||||
u32 dspcntr;
|
||||
u32 reg = DSPCNTR(plane);
|
||||
int pixel_size;
|
||||
|
||||
if (!intel_crtc->primary_enabled) {
|
||||
I915_WRITE(reg, 0);
|
||||
@ -2406,6 +2431,12 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
|
||||
return;
|
||||
}
|
||||
|
||||
obj = intel_fb_obj(fb);
|
||||
if (WARN_ON(obj == NULL))
|
||||
return;
|
||||
|
||||
pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
|
||||
|
||||
dspcntr = DISPPLANE_GAMMA_ENABLE;
|
||||
|
||||
dspcntr |= DISPLAY_PLANE_ENABLE;
|
||||
@ -2461,20 +2492,33 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
|
||||
if (IS_G4X(dev))
|
||||
dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
|
||||
|
||||
I915_WRITE(reg, dspcntr);
|
||||
|
||||
linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
|
||||
linear_offset = y * fb->pitches[0] + x * pixel_size;
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
intel_crtc->dspaddr_offset =
|
||||
intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
|
||||
fb->bits_per_pixel / 8,
|
||||
pixel_size,
|
||||
fb->pitches[0]);
|
||||
linear_offset -= intel_crtc->dspaddr_offset;
|
||||
} else {
|
||||
intel_crtc->dspaddr_offset = linear_offset;
|
||||
}
|
||||
|
||||
if (to_intel_plane(crtc->primary)->rotation == BIT(DRM_ROTATE_180)) {
|
||||
dspcntr |= DISPPLANE_ROTATE_180;
|
||||
|
||||
x += (intel_crtc->config.pipe_src_w - 1);
|
||||
y += (intel_crtc->config.pipe_src_h - 1);
|
||||
|
||||
/* Finding the last pixel of the last line of the display
|
||||
data and adding to linear_offset*/
|
||||
linear_offset +=
|
||||
(intel_crtc->config.pipe_src_h - 1) * fb->pitches[0] +
|
||||
(intel_crtc->config.pipe_src_w - 1) * pixel_size;
|
||||
}
|
||||
|
||||
I915_WRITE(reg, dspcntr);
|
||||
|
||||
DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
|
||||
i915_gem_obj_ggtt_offset(obj), linear_offset, x, y,
|
||||
fb->pitches[0]);
|
||||
@ -2496,11 +2540,12 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
|
||||
struct drm_i915_gem_object *obj;
|
||||
int plane = intel_crtc->plane;
|
||||
unsigned long linear_offset;
|
||||
u32 dspcntr;
|
||||
u32 reg = DSPCNTR(plane);
|
||||
int pixel_size;
|
||||
|
||||
if (!intel_crtc->primary_enabled) {
|
||||
I915_WRITE(reg, 0);
|
||||
@ -2509,6 +2554,12 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
|
||||
return;
|
||||
}
|
||||
|
||||
obj = intel_fb_obj(fb);
|
||||
if (WARN_ON(obj == NULL))
|
||||
return;
|
||||
|
||||
pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
|
||||
|
||||
dspcntr = DISPPLANE_GAMMA_ENABLE;
|
||||
|
||||
dspcntr |= DISPLAY_PLANE_ENABLE;
|
||||
@ -2549,14 +2600,28 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
|
||||
if (!IS_HASWELL(dev) && !IS_BROADWELL(dev))
|
||||
dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
|
||||
|
||||
I915_WRITE(reg, dspcntr);
|
||||
|
||||
linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
|
||||
linear_offset = y * fb->pitches[0] + x * pixel_size;
|
||||
intel_crtc->dspaddr_offset =
|
||||
intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
|
||||
fb->bits_per_pixel / 8,
|
||||
pixel_size,
|
||||
fb->pitches[0]);
|
||||
linear_offset -= intel_crtc->dspaddr_offset;
|
||||
if (to_intel_plane(crtc->primary)->rotation == BIT(DRM_ROTATE_180)) {
|
||||
dspcntr |= DISPPLANE_ROTATE_180;
|
||||
|
||||
if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
|
||||
x += (intel_crtc->config.pipe_src_w - 1);
|
||||
y += (intel_crtc->config.pipe_src_h - 1);
|
||||
|
||||
/* Finding the last pixel of the last line of the display
|
||||
data and adding to linear_offset*/
|
||||
linear_offset +=
|
||||
(intel_crtc->config.pipe_src_h - 1) * fb->pitches[0] +
|
||||
(intel_crtc->config.pipe_src_w - 1) * pixel_size;
|
||||
}
|
||||
}
|
||||
|
||||
I915_WRITE(reg, dspcntr);
|
||||
|
||||
DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
|
||||
i915_gem_obj_ggtt_offset(obj), linear_offset, x, y,
|
||||
@ -3340,23 +3405,54 @@ bool intel_has_pending_fb_unpin(struct drm_device *dev)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void page_flip_completed(struct intel_crtc *intel_crtc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
|
||||
struct intel_unpin_work *work = intel_crtc->unpin_work;
|
||||
|
||||
/* ensure that the unpin work is consistent wrt ->pending. */
|
||||
smp_rmb();
|
||||
intel_crtc->unpin_work = NULL;
|
||||
|
||||
if (work->event)
|
||||
drm_send_vblank_event(intel_crtc->base.dev,
|
||||
intel_crtc->pipe,
|
||||
work->event);
|
||||
|
||||
drm_crtc_vblank_put(&intel_crtc->base);
|
||||
|
||||
wake_up_all(&dev_priv->pending_flip_queue);
|
||||
queue_work(dev_priv->wq, &work->work);
|
||||
|
||||
trace_i915_flip_complete(intel_crtc->plane,
|
||||
work->pending_flip_obj);
|
||||
}
|
||||
|
||||
void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (crtc->primary->fb == NULL)
|
||||
return;
|
||||
|
||||
WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue));
|
||||
if (WARN_ON(wait_event_timeout(dev_priv->pending_flip_queue,
|
||||
!intel_crtc_has_pending_flip(crtc),
|
||||
60*HZ) == 0)) {
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ON(wait_event_timeout(dev_priv->pending_flip_queue,
|
||||
!intel_crtc_has_pending_flip(crtc),
|
||||
60*HZ) == 0);
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
if (intel_crtc->unpin_work) {
|
||||
WARN_ONCE(1, "Removing stuck page flip\n");
|
||||
page_flip_completed(intel_crtc);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
}
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
intel_finish_fb(crtc->primary->fb);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
if (crtc->primary->fb) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
intel_finish_fb(crtc->primary->fb);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/* Program iCLKIP clock to the desired frequency */
|
||||
@ -4178,7 +4274,8 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
|
||||
if (intel_crtc->config.has_pch_encoder)
|
||||
intel_set_pch_fifo_underrun_reporting(dev, pipe, false);
|
||||
|
||||
intel_disable_pipe(dev_priv, pipe);
|
||||
intel_disable_pipe(intel_crtc);
|
||||
|
||||
ironlake_pfit_disable(intel_crtc);
|
||||
|
||||
for_each_encoder_on_crtc(dev, crtc, encoder)
|
||||
@ -4226,7 +4323,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct intel_encoder *encoder;
|
||||
int pipe = intel_crtc->pipe;
|
||||
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
|
||||
|
||||
if (!intel_crtc->active)
|
||||
@ -4241,7 +4337,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
|
||||
|
||||
if (intel_crtc->config.has_pch_encoder)
|
||||
intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, false);
|
||||
intel_disable_pipe(dev_priv, pipe);
|
||||
intel_disable_pipe(intel_crtc);
|
||||
|
||||
if (intel_crtc->config.dp_encoder_is_mst)
|
||||
intel_ddi_set_vc_payload_alloc(crtc, false);
|
||||
@ -4831,7 +4927,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
|
||||
*/
|
||||
intel_wait_for_vblank(dev, pipe);
|
||||
|
||||
intel_disable_pipe(dev_priv, pipe);
|
||||
intel_disable_pipe(intel_crtc);
|
||||
|
||||
i9xx_pfit_disable(intel_crtc);
|
||||
|
||||
@ -6000,9 +6096,9 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
|
||||
|
||||
pipeconf = 0;
|
||||
|
||||
if (dev_priv->quirks & QUIRK_PIPEA_FORCE &&
|
||||
I915_READ(PIPECONF(intel_crtc->pipe)) & PIPECONF_ENABLE)
|
||||
pipeconf |= PIPECONF_ENABLE;
|
||||
if ((intel_crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) ||
|
||||
(intel_crtc->pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
|
||||
pipeconf |= I915_READ(PIPECONF(intel_crtc->pipe)) & PIPECONF_ENABLE;
|
||||
|
||||
if (intel_crtc->config.double_wide)
|
||||
pipeconf |= PIPECONF_DOUBLE_WIDE;
|
||||
@ -8274,7 +8370,6 @@ static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc,
|
||||
if (!obj) {
|
||||
DRM_DEBUG_KMS("cursor off\n");
|
||||
addr = 0;
|
||||
obj = NULL;
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
goto finish;
|
||||
}
|
||||
@ -8994,12 +9089,13 @@ static void intel_mark_fb_busy(struct drm_device *dev,
|
||||
unsigned frontbuffer_bits,
|
||||
struct intel_engine_cs *ring)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
enum pipe pipe;
|
||||
|
||||
if (!i915.powersave)
|
||||
return;
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
if (!(frontbuffer_bits & INTEL_FRONTBUFFER_ALL_MASK(pipe)))
|
||||
continue;
|
||||
|
||||
@ -9069,6 +9165,14 @@ void intel_frontbuffer_flush(struct drm_device *dev,
|
||||
intel_mark_fb_busy(dev, frontbuffer_bits, NULL);
|
||||
|
||||
intel_edp_psr_flush(dev, frontbuffer_bits);
|
||||
|
||||
/*
|
||||
* FIXME: Unconditional fbc flushing here is a rather gross hack and
|
||||
* needs to be reworked into a proper frontbuffer tracking scheme like
|
||||
* psr employs.
|
||||
*/
|
||||
if (IS_BROADWELL(dev))
|
||||
gen8_fbc_sw_flush(dev, FBC_REND_CACHE_CLEAN);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -9201,7 +9305,6 @@ static void intel_unpin_work_fn(struct work_struct *__work)
|
||||
static void do_intel_finish_page_flip(struct drm_device *dev,
|
||||
struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct intel_unpin_work *work;
|
||||
unsigned long flags;
|
||||
@ -9221,23 +9324,9 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
|
||||
return;
|
||||
}
|
||||
|
||||
/* and that the unpin work is consistent wrt ->pending. */
|
||||
smp_rmb();
|
||||
|
||||
intel_crtc->unpin_work = NULL;
|
||||
|
||||
if (work->event)
|
||||
drm_send_vblank_event(dev, intel_crtc->pipe, work->event);
|
||||
|
||||
drm_crtc_vblank_put(crtc);
|
||||
page_flip_completed(intel_crtc);
|
||||
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
|
||||
wake_up_all(&dev_priv->pending_flip_queue);
|
||||
|
||||
queue_work(dev_priv->wq, &work->work);
|
||||
|
||||
trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
|
||||
}
|
||||
|
||||
void intel_finish_page_flip(struct drm_device *dev, int pipe)
|
||||
@ -9717,6 +9806,65 @@ static int intel_default_queue_flip(struct drm_device *dev,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static bool __intel_pageflip_stall_check(struct drm_device *dev,
|
||||
struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct intel_unpin_work *work = intel_crtc->unpin_work;
|
||||
u32 addr;
|
||||
|
||||
if (atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE)
|
||||
return true;
|
||||
|
||||
if (!work->enable_stall_check)
|
||||
return false;
|
||||
|
||||
if (work->flip_ready_vblank == 0) {
|
||||
if (work->flip_queued_ring &&
|
||||
!i915_seqno_passed(work->flip_queued_ring->get_seqno(work->flip_queued_ring, true),
|
||||
work->flip_queued_seqno))
|
||||
return false;
|
||||
|
||||
work->flip_ready_vblank = drm_vblank_count(dev, intel_crtc->pipe);
|
||||
}
|
||||
|
||||
if (drm_vblank_count(dev, intel_crtc->pipe) - work->flip_ready_vblank < 3)
|
||||
return false;
|
||||
|
||||
/* Potential stall - if we see that the flip has happened,
|
||||
* assume a missed interrupt. */
|
||||
if (INTEL_INFO(dev)->gen >= 4)
|
||||
addr = I915_HI_DISPBASE(I915_READ(DSPSURF(intel_crtc->plane)));
|
||||
else
|
||||
addr = I915_READ(DSPADDR(intel_crtc->plane));
|
||||
|
||||
/* There is a potential issue here with a false positive after a flip
|
||||
* to the same address. We could address this by checking for a
|
||||
* non-incrementing frame counter.
|
||||
*/
|
||||
return addr == work->gtt_offset;
|
||||
}
|
||||
|
||||
void intel_check_page_flip(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
unsigned long flags;
|
||||
|
||||
if (crtc == NULL)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
if (intel_crtc->unpin_work && __intel_pageflip_stall_check(dev, crtc)) {
|
||||
WARN_ONCE(1, "Kicking stuck page flip: queued at %d, now %d\n",
|
||||
intel_crtc->unpin_work->flip_queued_vblank, drm_vblank_count(dev, pipe));
|
||||
page_flip_completed(intel_crtc);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
}
|
||||
|
||||
static int intel_crtc_page_flip(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event,
|
||||
@ -9733,6 +9881,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
//trigger software GT busyness calculation
|
||||
gen8_flip_interrupt(dev);
|
||||
|
||||
/*
|
||||
* drm_mode_page_flip_ioctl() should already catch this, but double
|
||||
* check to be safe. In the future we may enable pageflipping from
|
||||
@ -9773,12 +9924,20 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
|
||||
/* We borrow the event spin lock for protecting unpin_work */
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
if (intel_crtc->unpin_work) {
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
kfree(work);
|
||||
drm_crtc_vblank_put(crtc);
|
||||
/* Before declaring the flip queue wedged, check if
|
||||
* the hardware completed the operation behind our backs.
|
||||
*/
|
||||
if (__intel_pageflip_stall_check(dev, crtc)) {
|
||||
DRM_DEBUG_DRIVER("flip queue: previous flip completed, continuing\n");
|
||||
page_flip_completed(intel_crtc);
|
||||
} else {
|
||||
DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
|
||||
DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
|
||||
return -EBUSY;
|
||||
drm_crtc_vblank_put(crtc);
|
||||
kfree(work);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
intel_crtc->unpin_work = work;
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
@ -9798,8 +9957,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
|
||||
|
||||
work->pending_flip_obj = obj;
|
||||
|
||||
work->enable_stall_check = true;
|
||||
|
||||
atomic_inc(&intel_crtc->unpin_work_count);
|
||||
intel_crtc->reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
|
||||
|
||||
@ -9828,14 +9985,26 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
|
||||
work->gtt_offset =
|
||||
i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
|
||||
|
||||
if (use_mmio_flip(ring, obj))
|
||||
if (use_mmio_flip(ring, obj)) {
|
||||
ret = intel_queue_mmio_flip(dev, crtc, fb, obj, ring,
|
||||
page_flip_flags);
|
||||
else
|
||||
if (ret)
|
||||
goto cleanup_unpin;
|
||||
|
||||
work->flip_queued_seqno = obj->last_write_seqno;
|
||||
work->flip_queued_ring = obj->ring;
|
||||
} else {
|
||||
ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring,
|
||||
page_flip_flags);
|
||||
if (ret)
|
||||
goto cleanup_unpin;
|
||||
page_flip_flags);
|
||||
if (ret)
|
||||
goto cleanup_unpin;
|
||||
|
||||
work->flip_queued_seqno = intel_ring_get_seqno(ring);
|
||||
work->flip_queued_ring = ring;
|
||||
}
|
||||
|
||||
work->flip_queued_vblank = drm_vblank_count(dev, intel_crtc->pipe);
|
||||
work->enable_stall_check = true;
|
||||
|
||||
i915_gem_track_fb(work->old_fb_obj, obj,
|
||||
INTEL_FRONTBUFFER_PRIMARY(pipe));
|
||||
@ -10723,8 +10892,9 @@ check_crtc_state(struct drm_device *dev)
|
||||
active = dev_priv->display.get_pipe_config(crtc,
|
||||
&pipe_config);
|
||||
|
||||
/* hw state is inconsistent with the pipe A quirk */
|
||||
if (crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
|
||||
/* hw state is inconsistent with the pipe quirk */
|
||||
if ((crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) ||
|
||||
(crtc->pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
|
||||
active = crtc->active;
|
||||
|
||||
for_each_intel_encoder(dev, encoder) {
|
||||
@ -11596,6 +11766,7 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||
uint32_t src_w, uint32_t src_h)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
|
||||
struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
|
||||
@ -11618,6 +11789,21 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||
.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0,
|
||||
.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0,
|
||||
};
|
||||
const struct {
|
||||
int crtc_x, crtc_y;
|
||||
unsigned int crtc_w, crtc_h;
|
||||
uint32_t src_x, src_y, src_w, src_h;
|
||||
} orig = {
|
||||
.crtc_x = crtc_x,
|
||||
.crtc_y = crtc_y,
|
||||
.crtc_w = crtc_w,
|
||||
.crtc_h = crtc_h,
|
||||
.src_x = src_x,
|
||||
.src_y = src_y,
|
||||
.src_w = src_w,
|
||||
.src_h = src_h,
|
||||
};
|
||||
struct intel_plane *intel_plane = to_intel_plane(plane);
|
||||
bool visible;
|
||||
int ret;
|
||||
|
||||
@ -11692,15 +11878,42 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
if (intel_crtc && intel_crtc->active &&
|
||||
intel_crtc->primary_enabled) {
|
||||
/*
|
||||
* FBC does not work on some platforms for rotated
|
||||
* planes, so disable it when rotation is not 0 and
|
||||
* update it when rotation is set back to 0.
|
||||
*
|
||||
* FIXME: This is redundant with the fbc update done in
|
||||
* the primary plane enable function except that that
|
||||
* one is done too late. We eventually need to unify
|
||||
* this.
|
||||
*/
|
||||
if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
|
||||
dev_priv->fbc.plane == intel_crtc->plane &&
|
||||
intel_plane->rotation != BIT(DRM_ROTATE_0)) {
|
||||
intel_disable_fbc(dev);
|
||||
}
|
||||
}
|
||||
ret = intel_pipe_set_base(crtc, src.x1, src.y1, fb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!intel_crtc->primary_enabled)
|
||||
intel_enable_primary_hw_plane(plane, crtc);
|
||||
}
|
||||
|
||||
ret = intel_pipe_set_base(crtc, src.x1, src.y1, fb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!intel_crtc->primary_enabled)
|
||||
intel_enable_primary_hw_plane(plane, crtc);
|
||||
intel_plane->crtc_x = orig.crtc_x;
|
||||
intel_plane->crtc_y = orig.crtc_y;
|
||||
intel_plane->crtc_w = orig.crtc_w;
|
||||
intel_plane->crtc_h = orig.crtc_h;
|
||||
intel_plane->src_x = orig.src_x;
|
||||
intel_plane->src_y = orig.src_y;
|
||||
intel_plane->src_w = orig.src_w;
|
||||
intel_plane->src_h = orig.src_h;
|
||||
intel_plane->obj = obj;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -11717,6 +11930,7 @@ static const struct drm_plane_funcs intel_primary_plane_funcs = {
|
||||
.update_plane = intel_primary_plane_setplane,
|
||||
.disable_plane = intel_primary_plane_disable,
|
||||
.destroy = intel_plane_destroy,
|
||||
.set_property = intel_plane_set_property
|
||||
};
|
||||
|
||||
static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
|
||||
@ -11734,6 +11948,7 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
|
||||
primary->max_downscale = 1;
|
||||
primary->pipe = pipe;
|
||||
primary->plane = pipe;
|
||||
primary->rotation = BIT(DRM_ROTATE_0);
|
||||
if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4)
|
||||
primary->plane = !pipe;
|
||||
|
||||
@ -11749,6 +11964,19 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
|
||||
&intel_primary_plane_funcs,
|
||||
intel_primary_formats, num_formats,
|
||||
DRM_PLANE_TYPE_PRIMARY);
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
if (!dev->mode_config.rotation_property)
|
||||
dev->mode_config.rotation_property =
|
||||
drm_mode_create_rotation_property(dev,
|
||||
BIT(DRM_ROTATE_0) |
|
||||
BIT(DRM_ROTATE_180));
|
||||
if (dev->mode_config.rotation_property)
|
||||
drm_object_attach_property(&primary->base.base,
|
||||
dev->mode_config.rotation_property,
|
||||
primary->rotation);
|
||||
}
|
||||
|
||||
return &primary->base;
|
||||
}
|
||||
|
||||
@ -12423,7 +12651,7 @@ static void intel_init_display(struct drm_device *dev)
|
||||
dev_priv->display.write_eld = ironlake_write_eld;
|
||||
dev_priv->display.modeset_global_resources =
|
||||
ivb_modeset_global_resources;
|
||||
} else if (IS_HASWELL(dev) || IS_GEN8(dev)) {
|
||||
} else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
|
||||
dev_priv->display.fdi_link_train = hsw_fdi_link_train;
|
||||
dev_priv->display.write_eld = haswell_write_eld;
|
||||
dev_priv->display.modeset_global_resources =
|
||||
@ -12461,6 +12689,8 @@ static void intel_init_display(struct drm_device *dev)
|
||||
}
|
||||
|
||||
intel_panel_init_backlight_funcs(dev);
|
||||
|
||||
mutex_init(&dev_priv->pps_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -12476,6 +12706,14 @@ static void quirk_pipea_force(struct drm_device *dev)
|
||||
DRM_INFO("applying pipe a force quirk\n");
|
||||
}
|
||||
|
||||
static void quirk_pipeb_force(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
dev_priv->quirks |= QUIRK_PIPEB_FORCE;
|
||||
DRM_INFO("applying pipe b force quirk\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Some machines (Lenovo U160) do not work with SSC on LVDS for some reason
|
||||
*/
|
||||
@ -12550,6 +12788,12 @@ static struct intel_quirk intel_quirks[] = {
|
||||
/* ThinkPad T60 needs pipe A force quirk (bug #16494) */
|
||||
{ 0x2782, 0x17aa, 0x201a, quirk_pipea_force },
|
||||
|
||||
/* 830 needs to leave pipe A & dpll A up */
|
||||
{ 0x3577, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
|
||||
|
||||
/* 830 needs to leave pipe B & dpll B up */
|
||||
{ 0x3577, PCI_ANY_ID, PCI_ANY_ID, quirk_pipeb_force },
|
||||
|
||||
/* Lenovo U160 cannot use SSC on LVDS */
|
||||
{ 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable },
|
||||
|
||||
@ -12623,7 +12867,11 @@ static void i915_disable_vga(struct drm_device *dev)
|
||||
vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
|
||||
udelay(300);
|
||||
|
||||
I915_WRITE(vga_reg, VGA_DISP_DISABLE);
|
||||
/*
|
||||
* Fujitsu-Siemens Lifebook S6010 (830) has problems resuming
|
||||
* from S3 without preserving (some of?) the other bits.
|
||||
*/
|
||||
I915_WRITE(vga_reg, dev_priv->bios_vgacntr | VGA_DISP_DISABLE);
|
||||
POSTING_READ(vga_reg);
|
||||
}
|
||||
|
||||
@ -12698,7 +12946,7 @@ void intel_modeset_init(struct drm_device *dev)
|
||||
INTEL_INFO(dev)->num_pipes,
|
||||
INTEL_INFO(dev)->num_pipes > 1 ? "s" : "");
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
intel_crtc_init(dev, pipe);
|
||||
for_each_sprite(pipe, sprite) {
|
||||
ret = intel_plane_init(dev, pipe, sprite);
|
||||
@ -12712,6 +12960,8 @@ void intel_modeset_init(struct drm_device *dev)
|
||||
|
||||
intel_shared_dpll_init(dev);
|
||||
|
||||
/* save the BIOS value before clobbering it */
|
||||
dev_priv->bios_vgacntr = I915_READ(i915_vgacntrl_reg(dev));
|
||||
/* Just disable it once at startup */
|
||||
i915_disable_vga(dev);
|
||||
intel_setup_outputs(dev);
|
||||
@ -12889,7 +13139,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
|
||||
}
|
||||
}
|
||||
|
||||
if (crtc->active || IS_VALLEYVIEW(dev) || INTEL_INFO(dev)->gen < 5) {
|
||||
if (crtc->active || HAS_GMCH_DISPLAY(dev)) {
|
||||
/*
|
||||
* We start out with underrun reporting disabled to avoid races.
|
||||
* For correct bookkeeping mark this on active crtcs.
|
||||
@ -13104,7 +13354,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
|
||||
intel_sanitize_encoder(encoder);
|
||||
}
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
|
||||
intel_sanitize_crtc(crtc);
|
||||
intel_dump_pipe_config(crtc, &crtc->config, "[setup_hw_state]");
|
||||
@ -13132,7 +13382,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
|
||||
* We need to use raw interfaces for restoring state to avoid
|
||||
* checking (bogus) intermediate states.
|
||||
*/
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
struct drm_crtc *crtc =
|
||||
dev_priv->pipe_to_crtc_mapping[pipe];
|
||||
|
||||
@ -13353,7 +13603,7 @@ intel_display_capture_error_state(struct drm_device *dev)
|
||||
if (IS_HASWELL(dev) || IS_BROADWELL(dev))
|
||||
error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER);
|
||||
|
||||
for_each_pipe(i) {
|
||||
for_each_pipe(dev_priv, i) {
|
||||
error->pipe[i].power_domain_on =
|
||||
intel_display_power_enabled_unlocked(dev_priv,
|
||||
POWER_DOMAIN_PIPE(i));
|
||||
@ -13417,6 +13667,7 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
|
||||
struct drm_device *dev,
|
||||
struct intel_display_error_state *error)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int i;
|
||||
|
||||
if (!error)
|
||||
@ -13426,7 +13677,7 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
|
||||
if (IS_HASWELL(dev) || IS_BROADWELL(dev))
|
||||
err_printf(m, "PWR_WELL_CTL2: %08x\n",
|
||||
error->power_well_driver);
|
||||
for_each_pipe(i) {
|
||||
for_each_pipe(dev_priv, i) {
|
||||
err_printf(m, "Pipe [%d]:\n", i);
|
||||
err_printf(m, " Power: %s\n",
|
||||
error->pipe[i].power_domain_on ? "on" : "off");
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,6 +25,7 @@
|
||||
#ifndef __INTEL_DRV_H__
|
||||
#define __INTEL_DRV_H__
|
||||
|
||||
#include <linux/async.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hdmi.h>
|
||||
#include <drm/i915_drm.h>
|
||||
@ -179,6 +180,8 @@ struct intel_panel {
|
||||
bool active_low_pwm;
|
||||
struct backlight_device *device;
|
||||
} backlight;
|
||||
|
||||
void (*backlight_power)(struct intel_connector *, bool enable);
|
||||
};
|
||||
|
||||
struct intel_connector {
|
||||
@ -211,6 +214,7 @@ struct intel_connector {
|
||||
|
||||
/* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */
|
||||
struct edid *edid;
|
||||
struct edid *detect_edid;
|
||||
|
||||
/* since POLL and HPD connectors may use the same HPD line keep the native
|
||||
state of connector->polled in case hotplug storm detection changes it */
|
||||
@ -566,6 +570,12 @@ struct intel_dp {
|
||||
|
||||
struct notifier_block edp_notifier;
|
||||
|
||||
/*
|
||||
* Pipe whose power sequencer is currently locked into
|
||||
* this port. Only relevant on VLV/CHV.
|
||||
*/
|
||||
enum pipe pps_pipe;
|
||||
|
||||
bool use_tps3;
|
||||
bool can_mst; /* this port supports mst */
|
||||
bool is_mst;
|
||||
@ -664,6 +674,10 @@ struct intel_unpin_work {
|
||||
#define INTEL_FLIP_COMPLETE 2
|
||||
u32 flip_count;
|
||||
u32 gtt_offset;
|
||||
struct intel_engine_cs *flip_queued_ring;
|
||||
u32 flip_queued_seqno;
|
||||
int flip_queued_vblank;
|
||||
int flip_ready_vblank;
|
||||
bool enable_stall_check;
|
||||
};
|
||||
|
||||
@ -828,7 +842,6 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
|
||||
enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
|
||||
enum pipe pipe);
|
||||
void intel_wait_for_vblank(struct drm_device *dev, int pipe);
|
||||
void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
|
||||
int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp);
|
||||
void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
|
||||
struct intel_digital_port *dport);
|
||||
@ -849,6 +862,7 @@ __intel_framebuffer_create(struct drm_device *dev,
|
||||
void intel_prepare_page_flip(struct drm_device *dev, int plane);
|
||||
void intel_finish_page_flip(struct drm_device *dev, int pipe);
|
||||
void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
|
||||
void intel_check_page_flip(struct drm_device *dev, int pipe);
|
||||
|
||||
/* shared dpll functions */
|
||||
struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
|
||||
@ -937,6 +951,7 @@ void intel_dp_mst_suspend(struct drm_device *dev);
|
||||
void intel_dp_mst_resume(struct drm_device *dev);
|
||||
int intel_dp_max_link_bw(struct intel_dp *intel_dp);
|
||||
void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
|
||||
void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv);
|
||||
/* intel_dp_mst.c */
|
||||
int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
|
||||
void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port);
|
||||
@ -951,7 +966,7 @@ void intel_dvo_init(struct drm_device *dev);
|
||||
/* legacy fbdev emulation in intel_fbdev.c */
|
||||
#ifdef CONFIG_DRM_I915_FBDEV
|
||||
extern int intel_fbdev_init(struct drm_device *dev);
|
||||
extern void intel_fbdev_initial_config(struct drm_device *dev);
|
||||
extern void intel_fbdev_initial_config(void *data, async_cookie_t cookie);
|
||||
extern void intel_fbdev_fini(struct drm_device *dev);
|
||||
extern void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous);
|
||||
extern void intel_fbdev_output_poll_changed(struct drm_device *dev);
|
||||
@ -962,7 +977,7 @@ static inline int intel_fbdev_init(struct drm_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void intel_fbdev_initial_config(struct drm_device *dev)
|
||||
static inline void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1093,6 +1108,9 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob);
|
||||
int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane);
|
||||
void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
|
||||
enum plane plane);
|
||||
int intel_plane_set_property(struct drm_plane *plane,
|
||||
struct drm_property *prop,
|
||||
uint64_t val);
|
||||
int intel_plane_restore(struct drm_plane *plane);
|
||||
void intel_plane_disable(struct drm_plane *plane);
|
||||
int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
|
||||
|
@ -85,7 +85,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
|
||||
{
|
||||
.type = INTEL_DVO_CHIP_TMDS,
|
||||
.name = "ns2501",
|
||||
.dvo_reg = DVOC,
|
||||
.dvo_reg = DVOB,
|
||||
.slave_addr = NS2501_ADDR,
|
||||
.dev_ops = &ns2501_ops,
|
||||
}
|
||||
@ -185,12 +185,13 @@ static void intel_enable_dvo(struct intel_encoder *encoder)
|
||||
u32 dvo_reg = intel_dvo->dev.dvo_reg;
|
||||
u32 temp = I915_READ(dvo_reg);
|
||||
|
||||
I915_WRITE(dvo_reg, temp | DVO_ENABLE);
|
||||
I915_READ(dvo_reg);
|
||||
intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
|
||||
&crtc->config.requested_mode,
|
||||
&crtc->config.adjusted_mode);
|
||||
|
||||
I915_WRITE(dvo_reg, temp | DVO_ENABLE);
|
||||
I915_READ(dvo_reg);
|
||||
|
||||
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
|
||||
}
|
||||
|
||||
@ -226,10 +227,6 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode)
|
||||
|
||||
intel_crtc_update_dpms(crtc);
|
||||
|
||||
intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
|
||||
&config->requested_mode,
|
||||
&config->adjusted_mode);
|
||||
|
||||
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
|
||||
} else {
|
||||
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
|
||||
|
@ -24,6 +24,7 @@
|
||||
* David Airlie
|
||||
*/
|
||||
|
||||
#include <linux/async.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/console.h>
|
||||
@ -332,24 +333,6 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
|
||||
int num_connectors_enabled = 0;
|
||||
int num_connectors_detected = 0;
|
||||
|
||||
/*
|
||||
* If the user specified any force options, just bail here
|
||||
* and use that config.
|
||||
*/
|
||||
for (i = 0; i < fb_helper->connector_count; i++) {
|
||||
struct drm_fb_helper_connector *fb_conn;
|
||||
struct drm_connector *connector;
|
||||
|
||||
fb_conn = fb_helper->connector_info[i];
|
||||
connector = fb_conn->connector;
|
||||
|
||||
if (!enabled[i])
|
||||
continue;
|
||||
|
||||
if (connector->force != DRM_FORCE_UNSPECIFIED)
|
||||
return false;
|
||||
}
|
||||
|
||||
save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool),
|
||||
GFP_KERNEL);
|
||||
if (!save_enabled)
|
||||
@ -375,8 +358,18 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (connector->force == DRM_FORCE_OFF) {
|
||||
DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
|
||||
connector->name);
|
||||
enabled[i] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
encoder = connector->encoder;
|
||||
if (!encoder || WARN_ON(!encoder->crtc)) {
|
||||
if (connector->force > DRM_FORCE_OFF)
|
||||
goto bail;
|
||||
|
||||
DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
|
||||
connector->name);
|
||||
enabled[i] = false;
|
||||
@ -395,8 +388,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
|
||||
for (j = 0; j < fb_helper->connector_count; j++) {
|
||||
if (crtcs[j] == new_crtc) {
|
||||
DRM_DEBUG_KMS("fallback: cloned configuration\n");
|
||||
fallback = true;
|
||||
goto out;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
@ -467,8 +459,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
|
||||
fallback = true;
|
||||
}
|
||||
|
||||
out:
|
||||
if (fallback) {
|
||||
bail:
|
||||
DRM_DEBUG_KMS("Not using firmware configuration\n");
|
||||
memcpy(enabled, save_enabled, dev->mode_config.num_connector);
|
||||
kfree(save_enabled);
|
||||
@ -679,9 +671,9 @@ int intel_fbdev_init(struct drm_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_fbdev_initial_config(struct drm_device *dev)
|
||||
void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_private *dev_priv = data;
|
||||
struct intel_fbdev *ifbdev = dev_priv->fbdev;
|
||||
|
||||
/* Due to peculiar init order wrt to hpd handling this is separate. */
|
||||
@ -696,6 +688,7 @@ void intel_fbdev_fini(struct drm_device *dev)
|
||||
|
||||
flush_work(&dev_priv->fbdev_suspend_work);
|
||||
|
||||
async_synchronize_full();
|
||||
intel_fbdev_destroy(dev, dev_priv->fbdev);
|
||||
kfree(dev_priv->fbdev);
|
||||
dev_priv->fbdev = NULL;
|
||||
|
@ -971,104 +971,117 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
|
||||
return true;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
intel_hdmi_detect(struct drm_connector *connector, bool force)
|
||||
static void
|
||||
intel_hdmi_unset_edid(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
struct intel_digital_port *intel_dig_port =
|
||||
hdmi_to_dig_port(intel_hdmi);
|
||||
struct intel_encoder *intel_encoder = &intel_dig_port->base;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct edid *edid;
|
||||
enum intel_display_power_domain power_domain;
|
||||
enum drm_connector_status status = connector_status_disconnected;
|
||||
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
|
||||
connector->base.id, connector->name);
|
||||
|
||||
power_domain = intel_display_port_power_domain(intel_encoder);
|
||||
intel_display_power_get(dev_priv, power_domain);
|
||||
|
||||
intel_hdmi->has_hdmi_sink = false;
|
||||
intel_hdmi->has_audio = false;
|
||||
intel_hdmi->rgb_quant_range_selectable = false;
|
||||
edid = drm_get_edid(connector,
|
||||
intel_gmbus_get_adapter(dev_priv,
|
||||
intel_hdmi->ddc_bus));
|
||||
|
||||
if (edid) {
|
||||
if (edid->input & DRM_EDID_INPUT_DIGITAL) {
|
||||
status = connector_status_connected;
|
||||
if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
|
||||
intel_hdmi->has_hdmi_sink =
|
||||
drm_detect_hdmi_monitor(edid);
|
||||
intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
|
||||
intel_hdmi->rgb_quant_range_selectable =
|
||||
drm_rgb_quant_range_selectable(edid);
|
||||
}
|
||||
kfree(edid);
|
||||
}
|
||||
|
||||
if (status == connector_status_connected) {
|
||||
if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
|
||||
intel_hdmi->has_audio =
|
||||
(intel_hdmi->force_audio == HDMI_AUDIO_ON);
|
||||
intel_encoder->type = INTEL_OUTPUT_HDMI;
|
||||
}
|
||||
|
||||
intel_display_power_put(dev_priv, power_domain);
|
||||
|
||||
return status;
|
||||
kfree(to_intel_connector(connector)->detect_edid);
|
||||
to_intel_connector(connector)->detect_edid = NULL;
|
||||
}
|
||||
|
||||
static int intel_hdmi_get_modes(struct drm_connector *connector)
|
||||
static bool
|
||||
intel_hdmi_set_edid(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_encoder *intel_encoder = intel_attached_encoder(connector);
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
|
||||
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||
struct drm_i915_private *dev_priv = to_i915(connector->dev);
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
struct intel_encoder *intel_encoder =
|
||||
&hdmi_to_dig_port(intel_hdmi)->base;
|
||||
enum intel_display_power_domain power_domain;
|
||||
int ret;
|
||||
|
||||
/* We should parse the EDID data and find out if it's an HDMI sink so
|
||||
* we can send audio to it.
|
||||
*/
|
||||
struct edid *edid;
|
||||
bool connected = false;
|
||||
|
||||
power_domain = intel_display_port_power_domain(intel_encoder);
|
||||
intel_display_power_get(dev_priv, power_domain);
|
||||
|
||||
ret = intel_ddc_get_modes(connector,
|
||||
intel_gmbus_get_adapter(dev_priv,
|
||||
intel_hdmi->ddc_bus));
|
||||
edid = drm_get_edid(connector,
|
||||
intel_gmbus_get_adapter(dev_priv,
|
||||
intel_hdmi->ddc_bus));
|
||||
|
||||
intel_display_power_put(dev_priv, power_domain);
|
||||
|
||||
return ret;
|
||||
to_intel_connector(connector)->detect_edid = edid;
|
||||
if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
|
||||
intel_hdmi->rgb_quant_range_selectable =
|
||||
drm_rgb_quant_range_selectable(edid);
|
||||
|
||||
intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
|
||||
if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
|
||||
intel_hdmi->has_audio =
|
||||
intel_hdmi->force_audio == HDMI_AUDIO_ON;
|
||||
|
||||
if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
|
||||
intel_hdmi->has_hdmi_sink =
|
||||
drm_detect_hdmi_monitor(edid);
|
||||
|
||||
connected = true;
|
||||
}
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
intel_hdmi_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
enum drm_connector_status status;
|
||||
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
|
||||
connector->base.id, connector->name);
|
||||
|
||||
intel_hdmi_unset_edid(connector);
|
||||
|
||||
if (intel_hdmi_set_edid(connector)) {
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
|
||||
hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
|
||||
status = connector_status_connected;
|
||||
} else
|
||||
status = connector_status_disconnected;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
intel_hdmi_force(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
|
||||
connector->base.id, connector->name);
|
||||
|
||||
intel_hdmi_unset_edid(connector);
|
||||
|
||||
if (connector->status != connector_status_connected)
|
||||
return;
|
||||
|
||||
intel_hdmi_set_edid(connector);
|
||||
hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
|
||||
}
|
||||
|
||||
static int intel_hdmi_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct edid *edid;
|
||||
|
||||
edid = to_intel_connector(connector)->detect_edid;
|
||||
if (edid == NULL)
|
||||
return 0;
|
||||
|
||||
return intel_connector_update_modes(connector, edid);
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_hdmi_detect_audio(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_encoder *intel_encoder = intel_attached_encoder(connector);
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
|
||||
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||
enum intel_display_power_domain power_domain;
|
||||
struct edid *edid;
|
||||
bool has_audio = false;
|
||||
struct edid *edid;
|
||||
|
||||
power_domain = intel_display_port_power_domain(intel_encoder);
|
||||
intel_display_power_get(dev_priv, power_domain);
|
||||
|
||||
edid = drm_get_edid(connector,
|
||||
intel_gmbus_get_adapter(dev_priv,
|
||||
intel_hdmi->ddc_bus));
|
||||
if (edid) {
|
||||
if (edid->input & DRM_EDID_INPUT_DIGITAL)
|
||||
has_audio = drm_detect_monitor_audio(edid);
|
||||
kfree(edid);
|
||||
}
|
||||
|
||||
intel_display_power_put(dev_priv, power_domain);
|
||||
edid = to_intel_connector(connector)->detect_edid;
|
||||
if (edid && edid->input & DRM_EDID_INPUT_DIGITAL)
|
||||
has_audio = drm_detect_monitor_audio(edid);
|
||||
|
||||
return has_audio;
|
||||
}
|
||||
@ -1488,6 +1501,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
|
||||
|
||||
static void intel_hdmi_destroy(struct drm_connector *connector)
|
||||
{
|
||||
intel_hdmi_unset_edid(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
kfree(connector);
|
||||
}
|
||||
@ -1495,6 +1509,7 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
|
||||
static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
|
||||
.dpms = intel_connector_dpms,
|
||||
.detect = intel_hdmi_detect,
|
||||
.force = intel_hdmi_force,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.set_property = intel_hdmi_set_property,
|
||||
.destroy = intel_hdmi_destroy,
|
||||
|
@ -1217,8 +1217,6 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
|
||||
static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *ring)
|
||||
{
|
||||
int ret;
|
||||
struct intel_context *dctx = ring->default_context;
|
||||
struct drm_i915_gem_object *dctx_obj;
|
||||
|
||||
/* Intentionally left blank. */
|
||||
ring->buffer = NULL;
|
||||
@ -1232,18 +1230,6 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
|
||||
spin_lock_init(&ring->execlist_lock);
|
||||
ring->next_context_status_buffer = 0;
|
||||
|
||||
ret = intel_lr_context_deferred_create(dctx, ring);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* The status page is offset 0 from the context object in LRCs. */
|
||||
dctx_obj = dctx->engine[ring->id].state;
|
||||
ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(dctx_obj);
|
||||
ring->status_page.page_addr = kmap(sg_page(dctx_obj->pages->sgl));
|
||||
if (ring->status_page.page_addr == NULL)
|
||||
return -ENOMEM;
|
||||
ring->status_page.obj = dctx_obj;
|
||||
|
||||
ret = i915_cmd_parser_init_ring(ring);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -1254,7 +1240,9 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = intel_lr_context_deferred_create(ring->default_context, ring);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int logical_render_ring_init(struct drm_device *dev)
|
||||
@ -1448,16 +1436,53 @@ cleanup_render_ring:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
|
||||
struct intel_context *ctx)
|
||||
{
|
||||
struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
|
||||
struct render_state so;
|
||||
struct drm_i915_file_private *file_priv = ctx->file_priv;
|
||||
struct drm_file *file = file_priv ? file_priv->file : NULL;
|
||||
int ret;
|
||||
|
||||
ret = i915_gem_render_state_prepare(ring, &so);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (so.rodata == NULL)
|
||||
return 0;
|
||||
|
||||
ret = ring->emit_bb_start(ringbuf,
|
||||
so.ggtt_offset,
|
||||
I915_DISPATCH_SECURE);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring);
|
||||
|
||||
ret = __i915_add_request(ring, file, so.obj, NULL);
|
||||
/* intel_logical_ring_add_request moves object to inactive if it
|
||||
* fails */
|
||||
out:
|
||||
i915_gem_render_state_fini(&so);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_obj,
|
||||
struct intel_engine_cs *ring, struct intel_ringbuffer *ringbuf)
|
||||
{
|
||||
struct drm_device *dev = ring->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *ring_obj = ringbuf->obj;
|
||||
struct i915_hw_ppgtt *ppgtt = ctx->ppgtt;
|
||||
struct page *page;
|
||||
uint32_t *reg_state;
|
||||
int ret;
|
||||
|
||||
if (!ppgtt)
|
||||
ppgtt = dev_priv->mm.aliasing_ppgtt;
|
||||
|
||||
ret = i915_gem_object_set_to_cpu_domain(ctx_obj, true);
|
||||
if (ret) {
|
||||
DRM_DEBUG_DRIVER("Could not set to CPU domain\n");
|
||||
@ -1687,6 +1712,29 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
|
||||
ctx->engine[ring->id].ringbuf = ringbuf;
|
||||
ctx->engine[ring->id].state = ctx_obj;
|
||||
|
||||
if (ctx == ring->default_context) {
|
||||
/* The status page is offset 0 from the default context object
|
||||
* in LRC mode. */
|
||||
ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(ctx_obj);
|
||||
ring->status_page.page_addr =
|
||||
kmap(sg_page(ctx_obj->pages->sgl));
|
||||
if (ring->status_page.page_addr == NULL)
|
||||
return -ENOMEM;
|
||||
ring->status_page.obj = ctx_obj;
|
||||
}
|
||||
|
||||
if (ring->id == RCS && !ctx->rcs_initialized) {
|
||||
ret = intel_lr_context_render_state_init(ring, ctx);
|
||||
if (ret) {
|
||||
DRM_ERROR("Init render state failed: %d\n", ret);
|
||||
ctx->engine[ring->id].ringbuf = NULL;
|
||||
ctx->engine[ring->id].state = NULL;
|
||||
intel_destroy_ringbuffer_obj(ringbuf);
|
||||
goto error;
|
||||
}
|
||||
ctx->rcs_initialized = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
@ -62,6 +62,8 @@ static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf,
|
||||
int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords);
|
||||
|
||||
/* Logical Ring Contexts */
|
||||
int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
|
||||
struct intel_context *ctx);
|
||||
void intel_lr_context_free(struct intel_context *ctx);
|
||||
int intel_lr_context_deferred_create(struct intel_context *ctx,
|
||||
struct intel_engine_cs *ring);
|
||||
|
@ -751,6 +751,8 @@ void intel_panel_disable_backlight(struct intel_connector *connector)
|
||||
|
||||
spin_lock_irqsave(&dev_priv->backlight_lock, flags);
|
||||
|
||||
if (panel->backlight.device)
|
||||
panel->backlight.device->props.power = FB_BLANK_POWERDOWN;
|
||||
panel->backlight.enabled = false;
|
||||
dev_priv->display.disable_backlight(connector);
|
||||
|
||||
@ -957,6 +959,8 @@ void intel_panel_enable_backlight(struct intel_connector *connector)
|
||||
|
||||
dev_priv->display.enable_backlight(connector);
|
||||
panel->backlight.enabled = true;
|
||||
if (panel->backlight.device)
|
||||
panel->backlight.device->props.power = FB_BLANK_UNBLANK;
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
|
||||
}
|
||||
@ -965,6 +969,7 @@ void intel_panel_enable_backlight(struct intel_connector *connector)
|
||||
static int intel_backlight_device_update_status(struct backlight_device *bd)
|
||||
{
|
||||
struct intel_connector *connector = bl_get_data(bd);
|
||||
struct intel_panel *panel = &connector->panel;
|
||||
struct drm_device *dev = connector->base.dev;
|
||||
|
||||
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
|
||||
@ -972,6 +977,23 @@ static int intel_backlight_device_update_status(struct backlight_device *bd)
|
||||
bd->props.brightness, bd->props.max_brightness);
|
||||
intel_panel_set_backlight(connector, bd->props.brightness,
|
||||
bd->props.max_brightness);
|
||||
|
||||
/*
|
||||
* Allow flipping bl_power as a sub-state of enabled. Sadly the
|
||||
* backlight class device does not make it easy to to differentiate
|
||||
* between callbacks for brightness and bl_power, so our backlight_power
|
||||
* callback needs to take this into account.
|
||||
*/
|
||||
if (panel->backlight.enabled) {
|
||||
if (panel->backlight_power) {
|
||||
bool enable = bd->props.power == FB_BLANK_UNBLANK &&
|
||||
bd->props.brightness != 0;
|
||||
panel->backlight_power(connector, enable);
|
||||
}
|
||||
} else {
|
||||
bd->props.power = FB_BLANK_POWERDOWN;
|
||||
}
|
||||
|
||||
drm_modeset_unlock(&dev->mode_config.connection_mutex);
|
||||
return 0;
|
||||
}
|
||||
@ -1023,6 +1045,11 @@ static int intel_backlight_device_register(struct intel_connector *connector)
|
||||
panel->backlight.level,
|
||||
props.max_brightness);
|
||||
|
||||
if (panel->backlight.enabled)
|
||||
props.power = FB_BLANK_UNBLANK;
|
||||
else
|
||||
props.power = FB_BLANK_POWERDOWN;
|
||||
|
||||
/*
|
||||
* Note: using the same name independent of the connector prevents
|
||||
* registration of multiple backlight devices in the driver.
|
||||
@ -1203,7 +1230,7 @@ static int vlv_setup_backlight(struct intel_connector *connector)
|
||||
enum pipe pipe;
|
||||
u32 ctl, ctl2, val;
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe));
|
||||
|
||||
/* Skip if the modulation freq is already set */
|
||||
|
@ -345,6 +345,16 @@ bool intel_fbc_enabled(struct drm_device *dev)
|
||||
return dev_priv->display.fbc_enabled(dev);
|
||||
}
|
||||
|
||||
void gen8_fbc_sw_flush(struct drm_device *dev, u32 value)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (!IS_GEN8(dev))
|
||||
return;
|
||||
|
||||
I915_WRITE(MSG_FBC_REND_STATE, value);
|
||||
}
|
||||
|
||||
static void intel_fbc_work_fn(struct work_struct *__work)
|
||||
{
|
||||
struct intel_fbc_work *work =
|
||||
@ -581,6 +591,12 @@ void intel_update_fbc(struct drm_device *dev)
|
||||
DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
|
||||
goto out_disable;
|
||||
}
|
||||
if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
|
||||
to_intel_plane(crtc->primary)->rotation != BIT(DRM_ROTATE_0)) {
|
||||
if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
|
||||
DRM_DEBUG_KMS("Rotation unsupported, disabling\n");
|
||||
goto out_disable;
|
||||
}
|
||||
|
||||
/* If the kernel debugger is active, always disable compression */
|
||||
if (in_dbg_master())
|
||||
@ -856,7 +872,7 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
|
||||
* A value of 5us seems to be a good balance; safe for very low end
|
||||
* platforms but not overly aggressive on lower latency configs.
|
||||
*/
|
||||
static const int latency_ns = 5000;
|
||||
static const int pessimal_latency_ns = 5000;
|
||||
|
||||
static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
|
||||
{
|
||||
@ -985,13 +1001,20 @@ static const struct intel_watermark_params i915_wm_info = {
|
||||
.guard_size = 2,
|
||||
.cacheline_size = I915_FIFO_LINE_SIZE,
|
||||
};
|
||||
static const struct intel_watermark_params i830_wm_info = {
|
||||
static const struct intel_watermark_params i830_a_wm_info = {
|
||||
.fifo_size = I855GM_FIFO_SIZE,
|
||||
.max_wm = I915_MAX_WM,
|
||||
.default_wm = 1,
|
||||
.guard_size = 2,
|
||||
.cacheline_size = I830_FIFO_LINE_SIZE,
|
||||
};
|
||||
static const struct intel_watermark_params i830_bc_wm_info = {
|
||||
.fifo_size = I855GM_FIFO_SIZE,
|
||||
.max_wm = I915_MAX_WM/2,
|
||||
.default_wm = 1,
|
||||
.guard_size = 2,
|
||||
.cacheline_size = I830_FIFO_LINE_SIZE,
|
||||
};
|
||||
static const struct intel_watermark_params i845_wm_info = {
|
||||
.fifo_size = I830_FIFO_SIZE,
|
||||
.max_wm = I915_MAX_WM,
|
||||
@ -1364,14 +1387,14 @@ static void valleyview_update_wm(struct drm_crtc *crtc)
|
||||
vlv_update_drain_latency(crtc);
|
||||
|
||||
if (g4x_compute_wm0(dev, PIPE_A,
|
||||
&valleyview_wm_info, latency_ns,
|
||||
&valleyview_cursor_wm_info, latency_ns,
|
||||
&valleyview_wm_info, pessimal_latency_ns,
|
||||
&valleyview_cursor_wm_info, pessimal_latency_ns,
|
||||
&planea_wm, &cursora_wm))
|
||||
enabled |= 1 << PIPE_A;
|
||||
|
||||
if (g4x_compute_wm0(dev, PIPE_B,
|
||||
&valleyview_wm_info, latency_ns,
|
||||
&valleyview_cursor_wm_info, latency_ns,
|
||||
&valleyview_wm_info, pessimal_latency_ns,
|
||||
&valleyview_cursor_wm_info, pessimal_latency_ns,
|
||||
&planeb_wm, &cursorb_wm))
|
||||
enabled |= 1 << PIPE_B;
|
||||
|
||||
@ -1430,20 +1453,20 @@ static void cherryview_update_wm(struct drm_crtc *crtc)
|
||||
vlv_update_drain_latency(crtc);
|
||||
|
||||
if (g4x_compute_wm0(dev, PIPE_A,
|
||||
&valleyview_wm_info, latency_ns,
|
||||
&valleyview_cursor_wm_info, latency_ns,
|
||||
&valleyview_wm_info, pessimal_latency_ns,
|
||||
&valleyview_cursor_wm_info, pessimal_latency_ns,
|
||||
&planea_wm, &cursora_wm))
|
||||
enabled |= 1 << PIPE_A;
|
||||
|
||||
if (g4x_compute_wm0(dev, PIPE_B,
|
||||
&valleyview_wm_info, latency_ns,
|
||||
&valleyview_cursor_wm_info, latency_ns,
|
||||
&valleyview_wm_info, pessimal_latency_ns,
|
||||
&valleyview_cursor_wm_info, pessimal_latency_ns,
|
||||
&planeb_wm, &cursorb_wm))
|
||||
enabled |= 1 << PIPE_B;
|
||||
|
||||
if (g4x_compute_wm0(dev, PIPE_C,
|
||||
&valleyview_wm_info, latency_ns,
|
||||
&valleyview_cursor_wm_info, latency_ns,
|
||||
&valleyview_wm_info, pessimal_latency_ns,
|
||||
&valleyview_cursor_wm_info, pessimal_latency_ns,
|
||||
&planec_wm, &cursorc_wm))
|
||||
enabled |= 1 << PIPE_C;
|
||||
|
||||
@ -1536,14 +1559,14 @@ static void g4x_update_wm(struct drm_crtc *crtc)
|
||||
bool cxsr_enabled;
|
||||
|
||||
if (g4x_compute_wm0(dev, PIPE_A,
|
||||
&g4x_wm_info, latency_ns,
|
||||
&g4x_cursor_wm_info, latency_ns,
|
||||
&g4x_wm_info, pessimal_latency_ns,
|
||||
&g4x_cursor_wm_info, pessimal_latency_ns,
|
||||
&planea_wm, &cursora_wm))
|
||||
enabled |= 1 << PIPE_A;
|
||||
|
||||
if (g4x_compute_wm0(dev, PIPE_B,
|
||||
&g4x_wm_info, latency_ns,
|
||||
&g4x_cursor_wm_info, latency_ns,
|
||||
&g4x_wm_info, pessimal_latency_ns,
|
||||
&g4x_cursor_wm_info, pessimal_latency_ns,
|
||||
&planeb_wm, &cursorb_wm))
|
||||
enabled |= 1 << PIPE_B;
|
||||
|
||||
@ -1673,7 +1696,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
|
||||
else if (!IS_GEN2(dev))
|
||||
wm_info = &i915_wm_info;
|
||||
else
|
||||
wm_info = &i830_wm_info;
|
||||
wm_info = &i830_a_wm_info;
|
||||
|
||||
fifo_size = dev_priv->display.get_fifo_size(dev, 0);
|
||||
crtc = intel_get_crtc_for_plane(dev, 0);
|
||||
@ -1686,10 +1709,16 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
|
||||
adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
|
||||
planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
|
||||
wm_info, fifo_size, cpp,
|
||||
latency_ns);
|
||||
pessimal_latency_ns);
|
||||
enabled = crtc;
|
||||
} else
|
||||
} else {
|
||||
planea_wm = fifo_size - wm_info->guard_size;
|
||||
if (planea_wm > (long)wm_info->max_wm)
|
||||
planea_wm = wm_info->max_wm;
|
||||
}
|
||||
|
||||
if (IS_GEN2(dev))
|
||||
wm_info = &i830_bc_wm_info;
|
||||
|
||||
fifo_size = dev_priv->display.get_fifo_size(dev, 1);
|
||||
crtc = intel_get_crtc_for_plane(dev, 1);
|
||||
@ -1702,13 +1731,16 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
|
||||
adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
|
||||
planeb_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
|
||||
wm_info, fifo_size, cpp,
|
||||
latency_ns);
|
||||
pessimal_latency_ns);
|
||||
if (enabled == NULL)
|
||||
enabled = crtc;
|
||||
else
|
||||
enabled = NULL;
|
||||
} else
|
||||
} else {
|
||||
planeb_wm = fifo_size - wm_info->guard_size;
|
||||
if (planeb_wm > (long)wm_info->max_wm)
|
||||
planeb_wm = wm_info->max_wm;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
|
||||
|
||||
@ -1795,7 +1827,7 @@ static void i845_update_wm(struct drm_crtc *unused_crtc)
|
||||
planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
|
||||
&i845_wm_info,
|
||||
dev_priv->display.get_fifo_size(dev, 0),
|
||||
4, latency_ns);
|
||||
4, pessimal_latency_ns);
|
||||
fwater_lo = I915_READ(FW_BLC) & ~0xfff;
|
||||
fwater_lo |= (3<<8) | planea_wm;
|
||||
|
||||
@ -2242,7 +2274,6 @@ int ilk_wm_max_level(const struct drm_device *dev)
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
static void intel_print_wm_latency(struct drm_device *dev,
|
||||
const char *name,
|
||||
const uint16_t wm[5])
|
||||
@ -2648,7 +2679,7 @@ static struct intel_pipe_wm *ilk_find_best_result(struct drm_device *dev,
|
||||
#define WM_DIRTY_FBC (1 << 24)
|
||||
#define WM_DIRTY_DDB (1 << 25)
|
||||
|
||||
static unsigned int ilk_compute_wm_dirty(struct drm_device *dev,
|
||||
static unsigned int ilk_compute_wm_dirty(struct drm_i915_private *dev_priv,
|
||||
const struct ilk_wm_values *old,
|
||||
const struct ilk_wm_values *new)
|
||||
{
|
||||
@ -2656,7 +2687,7 @@ static unsigned int ilk_compute_wm_dirty(struct drm_device *dev,
|
||||
enum pipe pipe;
|
||||
int wm_lp;
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
if (old->wm_linetime[pipe] != new->wm_linetime[pipe]) {
|
||||
dirty |= WM_DIRTY_LINETIME(pipe);
|
||||
/* Must disable LP1+ watermarks too */
|
||||
@ -2742,7 +2773,7 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
|
||||
unsigned int dirty;
|
||||
uint32_t val;
|
||||
|
||||
dirty = ilk_compute_wm_dirty(dev, previous, results);
|
||||
dirty = ilk_compute_wm_dirty(dev_priv, previous, results);
|
||||
if (!dirty)
|
||||
return;
|
||||
|
||||
@ -3211,6 +3242,9 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
|
||||
{
|
||||
int new_power;
|
||||
|
||||
if (dev_priv->rps.is_bdw_sw_turbo)
|
||||
return;
|
||||
|
||||
new_power = dev_priv->rps.power;
|
||||
switch (dev_priv->rps.power) {
|
||||
case LOW_POWER:
|
||||
@ -3418,8 +3452,11 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
|
||||
valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
|
||||
else if (IS_VALLEYVIEW(dev))
|
||||
vlv_set_rps_idle(dev_priv);
|
||||
else
|
||||
else if (!dev_priv->rps.is_bdw_sw_turbo
|
||||
|| atomic_read(&dev_priv->rps.sw_turbo.flip_received)){
|
||||
gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
|
||||
}
|
||||
|
||||
dev_priv->rps.last_adj = 0;
|
||||
}
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
@ -3433,8 +3470,11 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv)
|
||||
if (dev_priv->rps.enabled) {
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
valleyview_set_rps(dev_priv->dev, dev_priv->rps.max_freq_softlimit);
|
||||
else
|
||||
else if (!dev_priv->rps.is_bdw_sw_turbo
|
||||
|| atomic_read(&dev_priv->rps.sw_turbo.flip_received)){
|
||||
gen6_set_rps(dev_priv->dev, dev_priv->rps.max_freq_softlimit);
|
||||
}
|
||||
|
||||
dev_priv->rps.last_adj = 0;
|
||||
}
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
@ -3453,6 +3493,10 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
|
||||
dev_priv->rps.cur_freq,
|
||||
vlv_gpu_freq(dev_priv, val), val);
|
||||
|
||||
if (WARN_ONCE(IS_CHERRYVIEW(dev) && (val & 1),
|
||||
"Odd GPU freq value\n"))
|
||||
val &= ~1;
|
||||
|
||||
if (val != dev_priv->rps.cur_freq)
|
||||
vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
|
||||
|
||||
@ -3465,21 +3509,26 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
|
||||
static void gen8_disable_rps_interrupts(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
if (IS_BROADWELL(dev) && dev_priv->rps.is_bdw_sw_turbo){
|
||||
if (atomic_read(&dev_priv->rps.sw_turbo.flip_received))
|
||||
del_timer(&dev_priv->rps.sw_turbo.flip_timer);
|
||||
dev_priv-> rps.is_bdw_sw_turbo = false;
|
||||
} else {
|
||||
I915_WRITE(GEN6_PMINTRMSK, ~GEN8_PMINTR_REDIRECT_TO_NON_DISP);
|
||||
I915_WRITE(GEN8_GT_IER(2), I915_READ(GEN8_GT_IER(2)) &
|
||||
~dev_priv->pm_rps_events);
|
||||
/* Complete PM interrupt masking here doesn't race with the rps work
|
||||
* item again unmasking PM interrupts because that is using a different
|
||||
* register (GEN8_GT_IMR(2)) to mask PM interrupts. The only risk is in
|
||||
* leaving stale bits in GEN8_GT_IIR(2) and GEN8_GT_IMR(2) which
|
||||
* gen8_enable_rps will clean up. */
|
||||
|
||||
I915_WRITE(GEN6_PMINTRMSK, ~GEN8_PMINTR_REDIRECT_TO_NON_DISP);
|
||||
I915_WRITE(GEN8_GT_IER(2), I915_READ(GEN8_GT_IER(2)) &
|
||||
~dev_priv->pm_rps_events);
|
||||
/* Complete PM interrupt masking here doesn't race with the rps work
|
||||
* item again unmasking PM interrupts because that is using a different
|
||||
* register (GEN8_GT_IMR(2)) to mask PM interrupts. The only risk is in
|
||||
* leaving stale bits in GEN8_GT_IIR(2) and GEN8_GT_IMR(2) which
|
||||
* gen8_enable_rps will clean up. */
|
||||
spin_lock_irq(&dev_priv->irq_lock);
|
||||
dev_priv->rps.pm_iir = 0;
|
||||
spin_unlock_irq(&dev_priv->irq_lock);
|
||||
|
||||
spin_lock_irq(&dev_priv->irq_lock);
|
||||
dev_priv->rps.pm_iir = 0;
|
||||
spin_unlock_irq(&dev_priv->irq_lock);
|
||||
|
||||
I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
|
||||
I915_WRITE(GEN8_GT_IIR(2), dev_priv->pm_rps_events);
|
||||
}
|
||||
}
|
||||
|
||||
static void gen6_disable_rps_interrupts(struct drm_device *dev)
|
||||
@ -3527,8 +3576,14 @@ static void valleyview_disable_rps(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
/* we're doing forcewake before Disabling RC6,
|
||||
* This what the BIOS expects when going into suspend */
|
||||
gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
|
||||
|
||||
I915_WRITE(GEN6_RC_CONTROL, 0);
|
||||
|
||||
gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
|
||||
|
||||
gen6_disable_rps_interrupts(dev);
|
||||
}
|
||||
|
||||
@ -3631,13 +3686,111 @@ static void parse_rp_state_cap(struct drm_i915_private *dev_priv, u32 rp_state_c
|
||||
dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;
|
||||
}
|
||||
|
||||
static void bdw_sw_calculate_freq(struct drm_device *dev,
|
||||
struct intel_rps_bdw_cal *c, u32 *cur_time, u32 *c0)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u64 busy = 0;
|
||||
u32 busyness_pct = 0;
|
||||
u32 elapsed_time = 0;
|
||||
u16 new_freq = 0;
|
||||
|
||||
if (!c || !cur_time || !c0)
|
||||
return;
|
||||
|
||||
if (0 == c->last_c0)
|
||||
goto out;
|
||||
|
||||
/* Check Evaluation interval */
|
||||
elapsed_time = *cur_time - c->last_ts;
|
||||
if (elapsed_time < c->eval_interval)
|
||||
return;
|
||||
|
||||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
|
||||
/*
|
||||
* c0 unit in 32*1.28 usec, elapsed_time unit in 1 usec.
|
||||
* Whole busyness_pct calculation should be
|
||||
* busy = ((u64)(*c0 - c->last_c0) << 5 << 7) / 100;
|
||||
* busyness_pct = (u32)(busy * 100 / elapsed_time);
|
||||
* The final formula is to simplify CPU calculation
|
||||
*/
|
||||
busy = (u64)(*c0 - c->last_c0) << 12;
|
||||
do_div(busy, elapsed_time);
|
||||
busyness_pct = (u32)busy;
|
||||
|
||||
if (c->is_up && busyness_pct >= c->it_threshold_pct)
|
||||
new_freq = (u16)dev_priv->rps.cur_freq + 3;
|
||||
if (!c->is_up && busyness_pct <= c->it_threshold_pct)
|
||||
new_freq = (u16)dev_priv->rps.cur_freq - 1;
|
||||
|
||||
/* Adjust to new frequency busyness and compare with threshold */
|
||||
if (0 != new_freq) {
|
||||
if (new_freq > dev_priv->rps.max_freq_softlimit)
|
||||
new_freq = dev_priv->rps.max_freq_softlimit;
|
||||
else if (new_freq < dev_priv->rps.min_freq_softlimit)
|
||||
new_freq = dev_priv->rps.min_freq_softlimit;
|
||||
|
||||
gen6_set_rps(dev, new_freq);
|
||||
}
|
||||
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
out:
|
||||
c->last_c0 = *c0;
|
||||
c->last_ts = *cur_time;
|
||||
}
|
||||
|
||||
static void gen8_set_frequency_RP0(struct work_struct *work)
|
||||
{
|
||||
struct intel_rps_bdw_turbo *p_bdw_turbo =
|
||||
container_of(work, struct intel_rps_bdw_turbo, work_max_freq);
|
||||
struct intel_gen6_power_mgmt *p_power_mgmt =
|
||||
container_of(p_bdw_turbo, struct intel_gen6_power_mgmt, sw_turbo);
|
||||
struct drm_i915_private *dev_priv =
|
||||
container_of(p_power_mgmt, struct drm_i915_private, rps);
|
||||
|
||||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
gen6_set_rps(dev_priv->dev, dev_priv->rps.rp0_freq);
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
}
|
||||
|
||||
static void flip_active_timeout_handler(unsigned long var)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = (struct drm_i915_private *) var;
|
||||
|
||||
del_timer(&dev_priv->rps.sw_turbo.flip_timer);
|
||||
atomic_set(&dev_priv->rps.sw_turbo.flip_received, false);
|
||||
|
||||
queue_work(dev_priv->wq, &dev_priv->rps.sw_turbo.work_max_freq);
|
||||
}
|
||||
|
||||
void bdw_software_turbo(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
u32 current_time = I915_READ(TIMESTAMP_CTR); /* unit in usec */
|
||||
u32 current_c0 = I915_READ(MCHBAR_PCU_C0); /* unit in 32*1.28 usec */
|
||||
|
||||
bdw_sw_calculate_freq(dev, &dev_priv->rps.sw_turbo.up,
|
||||
¤t_time, ¤t_c0);
|
||||
bdw_sw_calculate_freq(dev, &dev_priv->rps.sw_turbo.down,
|
||||
¤t_time, ¤t_c0);
|
||||
}
|
||||
|
||||
static void gen8_enable_rps(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_engine_cs *ring;
|
||||
uint32_t rc6_mask = 0, rp_state_cap;
|
||||
uint32_t threshold_up_pct, threshold_down_pct;
|
||||
uint32_t ei_up, ei_down; /* up and down evaluation interval */
|
||||
u32 rp_ctl_flag;
|
||||
int unused;
|
||||
|
||||
/* Use software Turbo for BDW */
|
||||
dev_priv->rps.is_bdw_sw_turbo = IS_BROADWELL(dev);
|
||||
|
||||
/* 1a: Software RC state - RC0 */
|
||||
I915_WRITE(GEN6_RC_STATE, 0);
|
||||
|
||||
@ -3681,35 +3834,74 @@ static void gen8_enable_rps(struct drm_device *dev)
|
||||
HSW_FREQUENCY(dev_priv->rps.rp1_freq));
|
||||
I915_WRITE(GEN6_RC_VIDEO_FREQ,
|
||||
HSW_FREQUENCY(dev_priv->rps.rp1_freq));
|
||||
/* NB: Docs say 1s, and 1000000 - which aren't equivalent */
|
||||
I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 100000000 / 128); /* 1 second timeout */
|
||||
ei_up = 84480; /* 84.48ms */
|
||||
ei_down = 448000;
|
||||
threshold_up_pct = 90; /* x percent busy */
|
||||
threshold_down_pct = 70;
|
||||
|
||||
/* Docs recommend 900MHz, and 300 MHz respectively */
|
||||
I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
|
||||
dev_priv->rps.max_freq_softlimit << 24 |
|
||||
dev_priv->rps.min_freq_softlimit << 16);
|
||||
if (dev_priv->rps.is_bdw_sw_turbo) {
|
||||
dev_priv->rps.sw_turbo.up.it_threshold_pct = threshold_up_pct;
|
||||
dev_priv->rps.sw_turbo.up.eval_interval = ei_up;
|
||||
dev_priv->rps.sw_turbo.up.is_up = true;
|
||||
dev_priv->rps.sw_turbo.up.last_ts = 0;
|
||||
dev_priv->rps.sw_turbo.up.last_c0 = 0;
|
||||
|
||||
I915_WRITE(GEN6_RP_UP_THRESHOLD, 7600000 / 128); /* 76ms busyness per EI, 90% */
|
||||
I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 31300000 / 128); /* 313ms busyness per EI, 70%*/
|
||||
I915_WRITE(GEN6_RP_UP_EI, 66000); /* 84.48ms, XXX: random? */
|
||||
I915_WRITE(GEN6_RP_DOWN_EI, 350000); /* 448ms, XXX: random? */
|
||||
dev_priv->rps.sw_turbo.down.it_threshold_pct = threshold_down_pct;
|
||||
dev_priv->rps.sw_turbo.down.eval_interval = ei_down;
|
||||
dev_priv->rps.sw_turbo.down.is_up = false;
|
||||
dev_priv->rps.sw_turbo.down.last_ts = 0;
|
||||
dev_priv->rps.sw_turbo.down.last_c0 = 0;
|
||||
|
||||
I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
|
||||
/* Start the timer to track if flip comes*/
|
||||
dev_priv->rps.sw_turbo.timeout = 200*1000; /* in us */
|
||||
|
||||
init_timer(&dev_priv->rps.sw_turbo.flip_timer);
|
||||
dev_priv->rps.sw_turbo.flip_timer.function = flip_active_timeout_handler;
|
||||
dev_priv->rps.sw_turbo.flip_timer.data = (unsigned long) dev_priv;
|
||||
dev_priv->rps.sw_turbo.flip_timer.expires =
|
||||
usecs_to_jiffies(dev_priv->rps.sw_turbo.timeout) + jiffies;
|
||||
add_timer(&dev_priv->rps.sw_turbo.flip_timer);
|
||||
INIT_WORK(&dev_priv->rps.sw_turbo.work_max_freq, gen8_set_frequency_RP0);
|
||||
|
||||
atomic_set(&dev_priv->rps.sw_turbo.flip_received, true);
|
||||
} else {
|
||||
/* NB: Docs say 1s, and 1000000 - which aren't equivalent
|
||||
* 1 second timeout*/
|
||||
I915_WRITE(GEN6_RP_DOWN_TIMEOUT, FREQ_1_28_US(1000000));
|
||||
|
||||
/* Docs recommend 900MHz, and 300 MHz respectively */
|
||||
I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
|
||||
dev_priv->rps.max_freq_softlimit << 24 |
|
||||
dev_priv->rps.min_freq_softlimit << 16);
|
||||
|
||||
I915_WRITE(GEN6_RP_UP_THRESHOLD,
|
||||
FREQ_1_28_US(ei_up * threshold_up_pct / 100));
|
||||
I915_WRITE(GEN6_RP_DOWN_THRESHOLD,
|
||||
FREQ_1_28_US(ei_down * threshold_down_pct / 100));
|
||||
I915_WRITE(GEN6_RP_UP_EI,
|
||||
FREQ_1_28_US(ei_up));
|
||||
I915_WRITE(GEN6_RP_DOWN_EI,
|
||||
FREQ_1_28_US(ei_down));
|
||||
|
||||
I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
|
||||
}
|
||||
|
||||
/* 5: Enable RPS */
|
||||
I915_WRITE(GEN6_RP_CONTROL,
|
||||
GEN6_RP_MEDIA_TURBO |
|
||||
GEN6_RP_MEDIA_HW_NORMAL_MODE |
|
||||
GEN6_RP_MEDIA_IS_GFX |
|
||||
GEN6_RP_ENABLE |
|
||||
GEN6_RP_UP_BUSY_AVG |
|
||||
GEN6_RP_DOWN_IDLE_AVG);
|
||||
rp_ctl_flag = GEN6_RP_MEDIA_TURBO |
|
||||
GEN6_RP_MEDIA_HW_NORMAL_MODE |
|
||||
GEN6_RP_MEDIA_IS_GFX |
|
||||
GEN6_RP_UP_BUSY_AVG |
|
||||
GEN6_RP_DOWN_IDLE_AVG;
|
||||
if (!dev_priv->rps.is_bdw_sw_turbo)
|
||||
rp_ctl_flag |= GEN6_RP_ENABLE;
|
||||
|
||||
/* 6: Ring frequency + overclocking (our driver does this later */
|
||||
I915_WRITE(GEN6_RP_CONTROL, rp_ctl_flag);
|
||||
|
||||
/* 6: Ring frequency + overclocking
|
||||
* (our driver does this later */
|
||||
gen6_set_rps(dev, (I915_READ(GEN6_GT_PERF_STATUS) & 0xff00) >> 8);
|
||||
|
||||
gen8_enable_rps_interrupts(dev);
|
||||
if (!dev_priv->rps.is_bdw_sw_turbo)
|
||||
gen8_enable_rps_interrupts(dev);
|
||||
|
||||
gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
|
||||
}
|
||||
@ -4084,11 +4276,27 @@ static void valleyview_cleanup_pctx(struct drm_device *dev)
|
||||
static void valleyview_init_gt_powersave(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 val;
|
||||
|
||||
valleyview_setup_pctx(dev);
|
||||
|
||||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
|
||||
val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
|
||||
switch ((val >> 6) & 3) {
|
||||
case 0:
|
||||
case 1:
|
||||
dev_priv->mem_freq = 800;
|
||||
break;
|
||||
case 2:
|
||||
dev_priv->mem_freq = 1066;
|
||||
break;
|
||||
case 3:
|
||||
dev_priv->mem_freq = 1333;
|
||||
break;
|
||||
}
|
||||
DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq);
|
||||
|
||||
dev_priv->rps.max_freq = valleyview_rps_max_freq(dev_priv);
|
||||
dev_priv->rps.rp0_freq = dev_priv->rps.max_freq;
|
||||
DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
|
||||
@ -4123,11 +4331,38 @@ static void valleyview_init_gt_powersave(struct drm_device *dev)
|
||||
static void cherryview_init_gt_powersave(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 val;
|
||||
|
||||
cherryview_setup_pctx(dev);
|
||||
|
||||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
|
||||
val = vlv_punit_read(dev_priv, CCK_FUSE_REG);
|
||||
switch ((val >> 2) & 0x7) {
|
||||
case 0:
|
||||
case 1:
|
||||
dev_priv->rps.cz_freq = 200;
|
||||
dev_priv->mem_freq = 1600;
|
||||
break;
|
||||
case 2:
|
||||
dev_priv->rps.cz_freq = 267;
|
||||
dev_priv->mem_freq = 1600;
|
||||
break;
|
||||
case 3:
|
||||
dev_priv->rps.cz_freq = 333;
|
||||
dev_priv->mem_freq = 2000;
|
||||
break;
|
||||
case 4:
|
||||
dev_priv->rps.cz_freq = 320;
|
||||
dev_priv->mem_freq = 1600;
|
||||
break;
|
||||
case 5:
|
||||
dev_priv->rps.cz_freq = 400;
|
||||
dev_priv->mem_freq = 1600;
|
||||
break;
|
||||
}
|
||||
DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq);
|
||||
|
||||
dev_priv->rps.max_freq = cherryview_rps_max_freq(dev_priv);
|
||||
dev_priv->rps.rp0_freq = dev_priv->rps.max_freq;
|
||||
DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
|
||||
@ -4149,6 +4384,12 @@ static void cherryview_init_gt_powersave(struct drm_device *dev)
|
||||
vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq),
|
||||
dev_priv->rps.min_freq);
|
||||
|
||||
WARN_ONCE((dev_priv->rps.max_freq |
|
||||
dev_priv->rps.efficient_freq |
|
||||
dev_priv->rps.rp1_freq |
|
||||
dev_priv->rps.min_freq) & 1,
|
||||
"Odd GPU freq values\n");
|
||||
|
||||
/* Preserve min/max settings in case of re-init */
|
||||
if (dev_priv->rps.max_freq_softlimit == 0)
|
||||
dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
|
||||
@ -5134,6 +5375,8 @@ static void intel_gen6_powersave_work(struct work_struct *work)
|
||||
rps.delayed_resume_work.work);
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
|
||||
dev_priv->rps.is_bdw_sw_turbo = false;
|
||||
|
||||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
|
||||
if (IS_CHERRYVIEW(dev)) {
|
||||
@ -5207,7 +5450,7 @@ static void g4x_disable_trickle_feed(struct drm_device *dev)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int pipe;
|
||||
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
I915_WRITE(DSPCNTR(pipe),
|
||||
I915_READ(DSPCNTR(pipe)) |
|
||||
DISPPLANE_TRICKLE_FEED_DISABLE);
|
||||
@ -5322,7 +5565,7 @@ static void cpt_init_clock_gating(struct drm_device *dev)
|
||||
/* The below fixes the weird display corruption, a few pixels shifted
|
||||
* downward, on (only) LVDS of some HP laptops with IVY.
|
||||
*/
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
val = I915_READ(TRANS_CHICKEN2(pipe));
|
||||
val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
|
||||
val &= ~TRANS_CHICKEN2_FDI_POLARITY_REVERSED;
|
||||
@ -5334,7 +5577,7 @@ static void cpt_init_clock_gating(struct drm_device *dev)
|
||||
I915_WRITE(TRANS_CHICKEN2(pipe), val);
|
||||
}
|
||||
/* WADP0ClockGatingDisable */
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
I915_WRITE(TRANS_CHICKEN1(pipe),
|
||||
TRANS_CHICKEN1_DP0UNIT_GC_DISABLE);
|
||||
}
|
||||
@ -5502,7 +5745,7 @@ static void lpt_suspend_hw(struct drm_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void gen8_init_clock_gating(struct drm_device *dev)
|
||||
static void broadwell_init_clock_gating(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
enum pipe pipe;
|
||||
@ -5514,37 +5757,12 @@ static void gen8_init_clock_gating(struct drm_device *dev)
|
||||
/* FIXME(BDW): Check all the w/a, some might only apply to
|
||||
* pre-production hw. */
|
||||
|
||||
/* WaDisablePartialInstShootdown:bdw */
|
||||
I915_WRITE(GEN8_ROW_CHICKEN,
|
||||
_MASKED_BIT_ENABLE(PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE));
|
||||
|
||||
/* WaDisableThreadStallDopClockGating:bdw */
|
||||
/* FIXME: Unclear whether we really need this on production bdw. */
|
||||
I915_WRITE(GEN8_ROW_CHICKEN,
|
||||
_MASKED_BIT_ENABLE(STALL_DOP_GATING_DISABLE));
|
||||
|
||||
/*
|
||||
* This GEN8_CENTROID_PIXEL_OPT_DIS W/A is only needed for
|
||||
* pre-production hardware
|
||||
*/
|
||||
I915_WRITE(HALF_SLICE_CHICKEN3,
|
||||
_MASKED_BIT_ENABLE(GEN8_CENTROID_PIXEL_OPT_DIS));
|
||||
I915_WRITE(HALF_SLICE_CHICKEN3,
|
||||
_MASKED_BIT_ENABLE(GEN8_SAMPLER_POWER_BYPASS_DIS));
|
||||
I915_WRITE(GAMTARBMODE, _MASKED_BIT_ENABLE(ARB_MODE_BWGTLB_DISABLE));
|
||||
|
||||
I915_WRITE(_3D_CHICKEN3,
|
||||
_MASKED_BIT_ENABLE(_3D_CHICKEN_SDE_LIMIT_FIFO_POLY_DEPTH(2)));
|
||||
|
||||
I915_WRITE(COMMON_SLICE_CHICKEN2,
|
||||
_MASKED_BIT_ENABLE(GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE));
|
||||
|
||||
I915_WRITE(GEN7_HALF_SLICE_CHICKEN1,
|
||||
_MASKED_BIT_ENABLE(GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE));
|
||||
|
||||
/* WaDisableDopClockGating:bdw May not be needed for production */
|
||||
I915_WRITE(GEN7_ROW_CHICKEN2,
|
||||
_MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
|
||||
|
||||
/* WaSwitchSolVfFArbitrationPriority:bdw */
|
||||
I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
|
||||
@ -5554,37 +5772,18 @@ static void gen8_init_clock_gating(struct drm_device *dev)
|
||||
I915_READ(CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD);
|
||||
|
||||
/* WaPsrDPRSUnmaskVBlankInSRD:bdw */
|
||||
for_each_pipe(pipe) {
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
I915_WRITE(CHICKEN_PIPESL_1(pipe),
|
||||
I915_READ(CHICKEN_PIPESL_1(pipe)) |
|
||||
BDW_DPRS_MASK_VBLANK_SRD);
|
||||
}
|
||||
|
||||
/* Use Force Non-Coherent whenever executing a 3D context. This is a
|
||||
* workaround for for a possible hang in the unlikely event a TLB
|
||||
* invalidation occurs during a PSD flush.
|
||||
*/
|
||||
I915_WRITE(HDC_CHICKEN0,
|
||||
I915_READ(HDC_CHICKEN0) |
|
||||
_MASKED_BIT_ENABLE(HDC_FORCE_NON_COHERENT));
|
||||
|
||||
/* WaVSRefCountFullforceMissDisable:bdw */
|
||||
/* WaDSRefCountFullforceMissDisable:bdw */
|
||||
I915_WRITE(GEN7_FF_THREAD_MODE,
|
||||
I915_READ(GEN7_FF_THREAD_MODE) &
|
||||
~(GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME));
|
||||
|
||||
/*
|
||||
* BSpec recommends 8x4 when MSAA is used,
|
||||
* however in practice 16x4 seems fastest.
|
||||
*
|
||||
* Note that PS/WM thread counts depend on the WIZ hashing
|
||||
* disable bit, which we don't touch here, but it's good
|
||||
* to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
|
||||
*/
|
||||
I915_WRITE(GEN7_GT_MODE,
|
||||
GEN6_WIZ_HASHING_MASK | GEN6_WIZ_HASHING_16x4);
|
||||
|
||||
I915_WRITE(GEN6_RC_SLEEP_PSMI_CONTROL,
|
||||
_MASKED_BIT_ENABLE(GEN8_RC_SEMA_IDLE_MSG_DISABLE));
|
||||
|
||||
@ -5592,9 +5791,7 @@ static void gen8_init_clock_gating(struct drm_device *dev)
|
||||
I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
|
||||
GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
|
||||
|
||||
/* Wa4x4STCOptimizationDisable:bdw */
|
||||
I915_WRITE(CACHE_MODE_1,
|
||||
_MASKED_BIT_ENABLE(GEN8_4x4_STC_OPTIMIZATION_DISABLE));
|
||||
lpt_init_clock_gating(dev);
|
||||
}
|
||||
|
||||
static void haswell_init_clock_gating(struct drm_device *dev)
|
||||
@ -5750,24 +5947,6 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
|
||||
static void valleyview_init_clock_gating(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 val;
|
||||
|
||||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
switch ((val >> 6) & 3) {
|
||||
case 0:
|
||||
case 1:
|
||||
dev_priv->mem_freq = 800;
|
||||
break;
|
||||
case 2:
|
||||
dev_priv->mem_freq = 1066;
|
||||
break;
|
||||
case 3:
|
||||
dev_priv->mem_freq = 1333;
|
||||
break;
|
||||
}
|
||||
DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq);
|
||||
|
||||
I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE);
|
||||
|
||||
@ -5843,48 +6022,11 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
|
||||
static void cherryview_init_clock_gating(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 val;
|
||||
|
||||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
val = vlv_punit_read(dev_priv, CCK_FUSE_REG);
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
switch ((val >> 2) & 0x7) {
|
||||
case 0:
|
||||
case 1:
|
||||
dev_priv->rps.cz_freq = CHV_CZ_CLOCK_FREQ_MODE_200;
|
||||
dev_priv->mem_freq = 1600;
|
||||
break;
|
||||
case 2:
|
||||
dev_priv->rps.cz_freq = CHV_CZ_CLOCK_FREQ_MODE_267;
|
||||
dev_priv->mem_freq = 1600;
|
||||
break;
|
||||
case 3:
|
||||
dev_priv->rps.cz_freq = CHV_CZ_CLOCK_FREQ_MODE_333;
|
||||
dev_priv->mem_freq = 2000;
|
||||
break;
|
||||
case 4:
|
||||
dev_priv->rps.cz_freq = CHV_CZ_CLOCK_FREQ_MODE_320;
|
||||
dev_priv->mem_freq = 1600;
|
||||
break;
|
||||
case 5:
|
||||
dev_priv->rps.cz_freq = CHV_CZ_CLOCK_FREQ_MODE_400;
|
||||
dev_priv->mem_freq = 1600;
|
||||
break;
|
||||
}
|
||||
DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq);
|
||||
|
||||
I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE);
|
||||
|
||||
I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE);
|
||||
|
||||
/* WaDisablePartialInstShootdown:chv */
|
||||
I915_WRITE(GEN8_ROW_CHICKEN,
|
||||
_MASKED_BIT_ENABLE(PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE));
|
||||
|
||||
/* WaDisableThreadStallDopClockGating:chv */
|
||||
I915_WRITE(GEN8_ROW_CHICKEN,
|
||||
_MASKED_BIT_ENABLE(STALL_DOP_GATING_DISABLE));
|
||||
|
||||
/* WaVSRefCountFullforceMissDisable:chv */
|
||||
/* WaDSRefCountFullforceMissDisable:chv */
|
||||
I915_WRITE(GEN7_FF_THREAD_MODE,
|
||||
@ -5903,10 +6045,6 @@ static void cherryview_init_clock_gating(struct drm_device *dev)
|
||||
I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
|
||||
GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
|
||||
|
||||
/* WaDisableSamplerPowerBypass:chv (pre-production hw) */
|
||||
I915_WRITE(HALF_SLICE_CHICKEN3,
|
||||
_MASKED_BIT_ENABLE(GEN8_SAMPLER_POWER_BYPASS_DIS));
|
||||
|
||||
/* WaDisableGunitClockGating:chv (pre-production hw) */
|
||||
I915_WRITE(VLV_GUNIT_CLOCK_GATE, I915_READ(VLV_GUNIT_CLOCK_GATE) |
|
||||
GINT_DIS);
|
||||
@ -5916,8 +6054,6 @@ static void cherryview_init_clock_gating(struct drm_device *dev)
|
||||
_MASKED_BIT_ENABLE(GEN8_FF_DOP_CLOCK_GATE_DISABLE));
|
||||
|
||||
/* WaDisableDopClockGating:chv (pre-production hw) */
|
||||
I915_WRITE(GEN7_ROW_CHICKEN2,
|
||||
_MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
|
||||
I915_WRITE(GEN6_UCGCTL1, I915_READ(GEN6_UCGCTL1) |
|
||||
GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE);
|
||||
}
|
||||
@ -6002,6 +6138,9 @@ static void gen3_init_clock_gating(struct drm_device *dev)
|
||||
|
||||
/* On GEN3 we really need to make sure the ARB C3 LP bit is set */
|
||||
I915_WRITE(MI_ARB_STATE, _MASKED_BIT_ENABLE(MI_ARB_C3_LP_WRITE_ENABLE));
|
||||
|
||||
I915_WRITE(MI_ARB_STATE,
|
||||
_MASKED_BIT_ENABLE(MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE));
|
||||
}
|
||||
|
||||
static void i85x_init_clock_gating(struct drm_device *dev)
|
||||
@ -6013,6 +6152,9 @@ static void i85x_init_clock_gating(struct drm_device *dev)
|
||||
/* interrupts should cause a wake up from C3 */
|
||||
I915_WRITE(MI_STATE, _MASKED_BIT_ENABLE(MI_AGPBUSY_INT_EN) |
|
||||
_MASKED_BIT_DISABLE(MI_AGPBUSY_830_MODE));
|
||||
|
||||
I915_WRITE(MEM_MODE,
|
||||
_MASKED_BIT_ENABLE(MEM_DISPLAY_TRICKLE_FEED_DISABLE));
|
||||
}
|
||||
|
||||
static void i830_init_clock_gating(struct drm_device *dev)
|
||||
@ -6020,6 +6162,10 @@ static void i830_init_clock_gating(struct drm_device *dev)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
|
||||
|
||||
I915_WRITE(MEM_MODE,
|
||||
_MASKED_BIT_ENABLE(MEM_DISPLAY_A_TRICKLE_FEED_DISABLE) |
|
||||
_MASKED_BIT_ENABLE(MEM_DISPLAY_B_TRICKLE_FEED_DISABLE));
|
||||
}
|
||||
|
||||
void intel_init_clock_gating(struct drm_device *dev)
|
||||
@ -6322,6 +6468,8 @@ static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv,
|
||||
spin_unlock_irq(&dev_priv->irq_lock);
|
||||
|
||||
vlv_set_power_well(dev_priv, power_well, false);
|
||||
|
||||
vlv_power_sequencer_reset(dev_priv);
|
||||
}
|
||||
|
||||
static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
|
||||
@ -6357,12 +6505,11 @@ static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
|
||||
static void vlv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
|
||||
struct i915_power_well *power_well)
|
||||
{
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
enum pipe pipe;
|
||||
|
||||
WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC);
|
||||
|
||||
for_each_pipe(pipe)
|
||||
for_each_pipe(dev_priv, pipe)
|
||||
assert_pll_disabled(dev_priv, pipe);
|
||||
|
||||
/* Assert common reset */
|
||||
@ -7249,7 +7396,7 @@ void intel_init_pm(struct drm_device *dev)
|
||||
else if (IS_HASWELL(dev))
|
||||
dev_priv->display.init_clock_gating = haswell_init_clock_gating;
|
||||
else if (INTEL_INFO(dev)->gen == 8)
|
||||
dev_priv->display.init_clock_gating = gen8_init_clock_gating;
|
||||
dev_priv->display.init_clock_gating = broadwell_init_clock_gating;
|
||||
} else if (IS_CHERRYVIEW(dev)) {
|
||||
dev_priv->display.update_wm = cherryview_update_wm;
|
||||
dev_priv->display.update_sprite_wm = valleyview_update_sprite_wm;
|
||||
@ -7443,6 +7590,7 @@ static int chv_freq_opcode(struct drm_i915_private *dev_priv, int val)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* CHV needs even values */
|
||||
opcode = (DIV_ROUND_CLOSEST((val * 2 * mul), dev_priv->rps.cz_freq) * 2);
|
||||
|
||||
return opcode;
|
||||
|
@ -24,13 +24,7 @@
|
||||
#ifndef _INTEL_RENDERSTATE_H
|
||||
#define _INTEL_RENDERSTATE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct intel_renderstate_rodata {
|
||||
const u32 *reloc;
|
||||
const u32 *batch;
|
||||
const u32 batch_items;
|
||||
};
|
||||
#include "i915_drv.h"
|
||||
|
||||
extern const struct intel_renderstate_rodata gen6_null_state;
|
||||
extern const struct intel_renderstate_rodata gen7_null_state;
|
||||
|
@ -444,7 +444,14 @@ gen8_render_ring_flush(struct intel_engine_cs *ring,
|
||||
return ret;
|
||||
}
|
||||
|
||||
return gen8_emit_pipe_control(ring, flags, scratch_addr);
|
||||
ret = gen8_emit_pipe_control(ring, flags, scratch_addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!invalidate_domains && flush_domains)
|
||||
return gen7_ring_fbc_flush(ring, FBC_REND_NUKE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ring_write_tail(struct intel_engine_cs *ring,
|
||||
@ -556,6 +563,14 @@ static int init_ring_common(struct intel_engine_cs *ring)
|
||||
* also enforces ordering), otherwise the hw might lose the new ring
|
||||
* register values. */
|
||||
I915_WRITE_START(ring, i915_gem_obj_ggtt_offset(obj));
|
||||
|
||||
/* WaClearRingBufHeadRegAtInit:ctg,elk */
|
||||
if (I915_READ_HEAD(ring))
|
||||
DRM_DEBUG("%s initialization failed [head=%08x], fudging\n",
|
||||
ring->name, I915_READ_HEAD(ring));
|
||||
I915_WRITE_HEAD(ring, 0);
|
||||
(void)I915_READ_HEAD(ring);
|
||||
|
||||
I915_WRITE_CTL(ring,
|
||||
((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES)
|
||||
| RING_VALID);
|
||||
@ -650,6 +665,146 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void intel_ring_emit_wa(struct intel_engine_cs *ring,
|
||||
u32 addr, u32 value)
|
||||
{
|
||||
struct drm_device *dev = ring->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (WARN_ON(dev_priv->num_wa_regs >= I915_MAX_WA_REGS))
|
||||
return;
|
||||
|
||||
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
|
||||
intel_ring_emit(ring, addr);
|
||||
intel_ring_emit(ring, value);
|
||||
|
||||
dev_priv->intel_wa_regs[dev_priv->num_wa_regs].addr = addr;
|
||||
dev_priv->intel_wa_regs[dev_priv->num_wa_regs].mask = value & 0xFFFF;
|
||||
/* value is updated with the status of remaining bits of this
|
||||
* register when it is read from debugfs file
|
||||
*/
|
||||
dev_priv->intel_wa_regs[dev_priv->num_wa_regs].value = value;
|
||||
dev_priv->num_wa_regs++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int bdw_init_workarounds(struct intel_engine_cs *ring)
|
||||
{
|
||||
int ret;
|
||||
struct drm_device *dev = ring->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
/*
|
||||
* workarounds applied in this fn are part of register state context,
|
||||
* they need to be re-initialized followed by gpu reset, suspend/resume,
|
||||
* module reload.
|
||||
*/
|
||||
dev_priv->num_wa_regs = 0;
|
||||
memset(dev_priv->intel_wa_regs, 0, sizeof(dev_priv->intel_wa_regs));
|
||||
|
||||
/*
|
||||
* update the number of dwords required based on the
|
||||
* actual number of workarounds applied
|
||||
*/
|
||||
ret = intel_ring_begin(ring, 24);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* WaDisablePartialInstShootdown:bdw */
|
||||
/* WaDisableThreadStallDopClockGating:bdw */
|
||||
/* FIXME: Unclear whether we really need this on production bdw. */
|
||||
intel_ring_emit_wa(ring, GEN8_ROW_CHICKEN,
|
||||
_MASKED_BIT_ENABLE(PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE
|
||||
| STALL_DOP_GATING_DISABLE));
|
||||
|
||||
/* WaDisableDopClockGating:bdw May not be needed for production */
|
||||
intel_ring_emit_wa(ring, GEN7_ROW_CHICKEN2,
|
||||
_MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
|
||||
|
||||
/*
|
||||
* This GEN8_CENTROID_PIXEL_OPT_DIS W/A is only needed for
|
||||
* pre-production hardware
|
||||
*/
|
||||
intel_ring_emit_wa(ring, HALF_SLICE_CHICKEN3,
|
||||
_MASKED_BIT_ENABLE(GEN8_CENTROID_PIXEL_OPT_DIS
|
||||
| GEN8_SAMPLER_POWER_BYPASS_DIS));
|
||||
|
||||
intel_ring_emit_wa(ring, GEN7_HALF_SLICE_CHICKEN1,
|
||||
_MASKED_BIT_ENABLE(GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE));
|
||||
|
||||
intel_ring_emit_wa(ring, COMMON_SLICE_CHICKEN2,
|
||||
_MASKED_BIT_ENABLE(GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE));
|
||||
|
||||
/* Use Force Non-Coherent whenever executing a 3D context. This is a
|
||||
* workaround for for a possible hang in the unlikely event a TLB
|
||||
* invalidation occurs during a PSD flush.
|
||||
*/
|
||||
intel_ring_emit_wa(ring, HDC_CHICKEN0,
|
||||
_MASKED_BIT_ENABLE(HDC_FORCE_NON_COHERENT));
|
||||
|
||||
/* Wa4x4STCOptimizationDisable:bdw */
|
||||
intel_ring_emit_wa(ring, CACHE_MODE_1,
|
||||
_MASKED_BIT_ENABLE(GEN8_4x4_STC_OPTIMIZATION_DISABLE));
|
||||
|
||||
/*
|
||||
* BSpec recommends 8x4 when MSAA is used,
|
||||
* however in practice 16x4 seems fastest.
|
||||
*
|
||||
* Note that PS/WM thread counts depend on the WIZ hashing
|
||||
* disable bit, which we don't touch here, but it's good
|
||||
* to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
|
||||
*/
|
||||
intel_ring_emit_wa(ring, GEN7_GT_MODE,
|
||||
GEN6_WIZ_HASHING_MASK | GEN6_WIZ_HASHING_16x4);
|
||||
|
||||
intel_ring_advance(ring);
|
||||
|
||||
DRM_DEBUG_DRIVER("Number of Workarounds applied: %d\n",
|
||||
dev_priv->num_wa_regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int chv_init_workarounds(struct intel_engine_cs *ring)
|
||||
{
|
||||
int ret;
|
||||
struct drm_device *dev = ring->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
/*
|
||||
* workarounds applied in this fn are part of register state context,
|
||||
* they need to be re-initialized followed by gpu reset, suspend/resume,
|
||||
* module reload.
|
||||
*/
|
||||
dev_priv->num_wa_regs = 0;
|
||||
memset(dev_priv->intel_wa_regs, 0, sizeof(dev_priv->intel_wa_regs));
|
||||
|
||||
ret = intel_ring_begin(ring, 12);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* WaDisablePartialInstShootdown:chv */
|
||||
intel_ring_emit_wa(ring, GEN8_ROW_CHICKEN,
|
||||
_MASKED_BIT_ENABLE(PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE));
|
||||
|
||||
/* WaDisableThreadStallDopClockGating:chv */
|
||||
intel_ring_emit_wa(ring, GEN8_ROW_CHICKEN,
|
||||
_MASKED_BIT_ENABLE(STALL_DOP_GATING_DISABLE));
|
||||
|
||||
/* WaDisableDopClockGating:chv (pre-production hw) */
|
||||
intel_ring_emit_wa(ring, GEN7_ROW_CHICKEN2,
|
||||
_MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
|
||||
|
||||
/* WaDisableSamplerPowerBypass:chv (pre-production hw) */
|
||||
intel_ring_emit_wa(ring, HALF_SLICE_CHICKEN3,
|
||||
_MASKED_BIT_ENABLE(GEN8_SAMPLER_POWER_BYPASS_DIS));
|
||||
|
||||
intel_ring_advance(ring);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_render_ring(struct intel_engine_cs *ring)
|
||||
{
|
||||
struct drm_device *dev = ring->dev;
|
||||
@ -2148,6 +2303,10 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
|
||||
dev_priv->semaphore_obj = obj;
|
||||
}
|
||||
}
|
||||
if (IS_CHERRYVIEW(dev))
|
||||
ring->init_context = chv_init_workarounds;
|
||||
else
|
||||
ring->init_context = bdw_init_workarounds;
|
||||
ring->add_request = gen6_add_request;
|
||||
ring->flush = gen8_render_ring_flush;
|
||||
ring->irq_get = gen8_ring_get_irq;
|
||||
|
@ -148,6 +148,8 @@ struct intel_engine_cs {
|
||||
|
||||
int (*init)(struct intel_engine_cs *ring);
|
||||
|
||||
int (*init_context)(struct intel_engine_cs *ring);
|
||||
|
||||
void (*write_tail)(struct intel_engine_cs *ring,
|
||||
u32 value);
|
||||
int __must_check (*flush)(struct intel_engine_cs *ring,
|
||||
|
@ -1218,9 +1218,9 @@ out_unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int intel_plane_set_property(struct drm_plane *plane,
|
||||
struct drm_property *prop,
|
||||
uint64_t val)
|
||||
int intel_plane_set_property(struct drm_plane *plane,
|
||||
struct drm_property *prop,
|
||||
uint64_t val)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct intel_plane *intel_plane = to_intel_plane(plane);
|
||||
@ -1232,6 +1232,9 @@ static int intel_plane_set_property(struct drm_plane *plane,
|
||||
if (hweight32(val & 0xf) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (intel_plane->rotation == val)
|
||||
return 0;
|
||||
|
||||
old_val = intel_plane->rotation;
|
||||
intel_plane->rotation = val;
|
||||
ret = intel_plane_restore(plane);
|
||||
@ -1249,7 +1252,7 @@ int intel_plane_restore(struct drm_plane *plane)
|
||||
if (!plane->crtc || !plane->fb)
|
||||
return 0;
|
||||
|
||||
return intel_update_plane(plane, plane->crtc, plane->fb,
|
||||
return plane->funcs->update_plane(plane, plane->crtc, plane->fb,
|
||||
intel_plane->crtc_x, intel_plane->crtc_y,
|
||||
intel_plane->crtc_w, intel_plane->crtc_h,
|
||||
intel_plane->src_x, intel_plane->src_y,
|
||||
@ -1375,10 +1378,10 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
|
||||
intel_plane->plane = plane;
|
||||
intel_plane->rotation = BIT(DRM_ROTATE_0);
|
||||
possible_crtcs = (1 << pipe);
|
||||
ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs,
|
||||
&intel_plane_funcs,
|
||||
plane_formats, num_plane_formats,
|
||||
false);
|
||||
ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs,
|
||||
&intel_plane_funcs,
|
||||
plane_formats, num_plane_formats,
|
||||
DRM_PLANE_TYPE_OVERLAY);
|
||||
if (ret) {
|
||||
kfree(intel_plane);
|
||||
goto out;
|
||||
|
@ -101,7 +101,7 @@ static void __gen7_gt_force_wake_mt_get(struct drm_i915_private *dev_priv,
|
||||
{
|
||||
u32 forcewake_ack;
|
||||
|
||||
if (IS_HASWELL(dev_priv->dev) || IS_GEN8(dev_priv->dev))
|
||||
if (IS_HASWELL(dev_priv->dev) || IS_BROADWELL(dev_priv->dev))
|
||||
forcewake_ack = FORCEWAKE_ACK_HSW;
|
||||
else
|
||||
forcewake_ack = FORCEWAKE_MT_ACK;
|
||||
@ -334,7 +334,7 @@ void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore)
|
||||
else if (IS_GEN6(dev) || IS_GEN7(dev))
|
||||
__gen6_gt_force_wake_reset(dev_priv);
|
||||
|
||||
if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_GEN8(dev))
|
||||
if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev))
|
||||
__gen7_gt_force_wake_mt_reset(dev_priv);
|
||||
|
||||
if (restore) { /* If reset with a user forcewake, try to restore */
|
||||
@ -838,7 +838,7 @@ void intel_uncore_init(struct drm_device *dev)
|
||||
if (IS_VALLEYVIEW(dev)) {
|
||||
dev_priv->uncore.funcs.force_wake_get = __vlv_force_wake_get;
|
||||
dev_priv->uncore.funcs.force_wake_put = __vlv_force_wake_put;
|
||||
} else if (IS_HASWELL(dev) || IS_GEN8(dev)) {
|
||||
} else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
|
||||
dev_priv->uncore.funcs.force_wake_get = __gen7_gt_force_wake_mt_get;
|
||||
dev_priv->uncore.funcs.force_wake_put = __gen7_gt_force_wake_mt_put;
|
||||
} else if (IS_IVYBRIDGE(dev)) {
|
||||
|
@ -232,8 +232,8 @@ void radeon_dp_aux_init(struct radeon_connector *radeon_connector)
|
||||
|
||||
/***** general DP utility functions *****/
|
||||
|
||||
#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200
|
||||
#define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPHASIS_9_5
|
||||
#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_LEVEL_3
|
||||
#define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPH_LEVEL_3
|
||||
|
||||
static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
|
||||
int lane_count,
|
||||
|
@ -533,9 +533,9 @@ int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link,
|
||||
|
||||
for (i = 0; i < link->num_lanes; i++)
|
||||
values[i] = DP_TRAIN_MAX_PRE_EMPHASIS_REACHED |
|
||||
DP_TRAIN_PRE_EMPHASIS_0 |
|
||||
DP_TRAIN_PRE_EMPH_LEVEL_0 |
|
||||
DP_TRAIN_MAX_SWING_REACHED |
|
||||
DP_TRAIN_VOLTAGE_SWING_400;
|
||||
DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
|
||||
|
||||
err = drm_dp_dpcd_write(&dpaux->aux, DP_TRAINING_LANE0_SET, values,
|
||||
link->num_lanes);
|
||||
|
@ -190,16 +190,16 @@
|
||||
# define DP_TRAIN_VOLTAGE_SWING_MASK 0x3
|
||||
# define DP_TRAIN_VOLTAGE_SWING_SHIFT 0
|
||||
# define DP_TRAIN_MAX_SWING_REACHED (1 << 2)
|
||||
# define DP_TRAIN_VOLTAGE_SWING_400 (0 << 0)
|
||||
# define DP_TRAIN_VOLTAGE_SWING_600 (1 << 0)
|
||||
# define DP_TRAIN_VOLTAGE_SWING_800 (2 << 0)
|
||||
# define DP_TRAIN_VOLTAGE_SWING_1200 (3 << 0)
|
||||
# define DP_TRAIN_VOLTAGE_SWING_LEVEL_0 (0 << 0)
|
||||
# define DP_TRAIN_VOLTAGE_SWING_LEVEL_1 (1 << 0)
|
||||
# define DP_TRAIN_VOLTAGE_SWING_LEVEL_2 (2 << 0)
|
||||
# define DP_TRAIN_VOLTAGE_SWING_LEVEL_3 (3 << 0)
|
||||
|
||||
# define DP_TRAIN_PRE_EMPHASIS_MASK (3 << 3)
|
||||
# define DP_TRAIN_PRE_EMPHASIS_0 (0 << 3)
|
||||
# define DP_TRAIN_PRE_EMPHASIS_3_5 (1 << 3)
|
||||
# define DP_TRAIN_PRE_EMPHASIS_6 (2 << 3)
|
||||
# define DP_TRAIN_PRE_EMPHASIS_9_5 (3 << 3)
|
||||
# define DP_TRAIN_PRE_EMPH_LEVEL_0 (0 << 3)
|
||||
# define DP_TRAIN_PRE_EMPH_LEVEL_1 (1 << 3)
|
||||
# define DP_TRAIN_PRE_EMPH_LEVEL_2 (2 << 3)
|
||||
# define DP_TRAIN_PRE_EMPH_LEVEL_3 (3 << 3)
|
||||
|
||||
# define DP_TRAIN_PRE_EMPHASIS_SHIFT 3
|
||||
# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED (1 << 5)
|
||||
|
Loading…
Reference in New Issue
Block a user