提交 5762a179 编写于 作者: D Dave Airlie

Merge branch 'drm-intel-next' of...

Merge branch 'drm-intel-next' of ssh://master.kernel.org/pub/scm/linux/kernel/git/keithp/linux-2.6 into drm-core-next

* 'drm-intel-next' of ssh://master.kernel.org/pub/scm/linux/kernel/git/keithp/linux-2.6: (52 commits)
  drm/i915: provide module parameter description
  drm/i915: add module parameter compiler hints
  drm/i915/bios: Avoid temporary allocation whilst searching for downclock
  drm/i915: Cache GT fifo count for SandyBridge
  i915: Fix opregion notifications
  drm/i915: TVDAC_STATE_CHG does not indicate successful load-detect
  drm/i915: Select correct pipe during TV detect
  drm/i915/ringbuffer: Idling requires waiting for the ring to be empty
  Revert "drm/i915: enable rc6 by default"
  drm/i915: Clean up i915_driver_load failure path
  drm/i915: Enable i915 frame buffer compression by default
  drm/i915: Share the common work of disabling active FBC before updating
  drm/i915: Perform intel_enable_fbc() from a delayed task
  drm/i915: Disable FBC across page-flipping
  drm/i915: Set persistent-mode for ILK/SNB framebuffer compression
  drm/i915: Use of a CPU fence is mandatory to update FBC regions upon CPU writes
  drm/i915: Remove vestigial pitch from post-gen2 FBC control routines
  drm/i915: Replace direct calls to vfunc.disable_fbc with intel_disable_fbc()
  drm/i915: Only export the generic intel_disable_fbc() interface
  drm/i915: Enable GPU reset on Ivybridge.
  ...
...@@ -46,7 +46,6 @@ ...@@ -46,7 +46,6 @@
#define PREFIX "ACPI: " #define PREFIX "ACPI: "
#define ACPI_VIDEO_CLASS "video"
#define ACPI_VIDEO_BUS_NAME "Video Bus" #define ACPI_VIDEO_BUS_NAME "Video Bus"
#define ACPI_VIDEO_DEVICE_NAME "Video Device" #define ACPI_VIDEO_DEVICE_NAME "Video Device"
#define ACPI_VIDEO_NOTIFY_SWITCH 0x80 #define ACPI_VIDEO_NOTIFY_SWITCH 0x80
...@@ -1445,7 +1444,8 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) ...@@ -1445,7 +1444,8 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch, case ACPI_VIDEO_NOTIFY_SWITCH: /* User requested a switch,
* most likely via hotkey. */ * most likely via hotkey. */
acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_SWITCHVIDEOMODE; if (!acpi_notifier_call_chain(device, event, 0))
keycode = KEY_SWITCHVIDEOMODE;
break; break;
case ACPI_VIDEO_NOTIFY_PROBE: /* User plugged in or removed a video case ACPI_VIDEO_NOTIFY_PROBE: /* User plugged in or removed a video
...@@ -1475,7 +1475,8 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event) ...@@ -1475,7 +1475,8 @@ static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
break; break;
} }
acpi_notifier_call_chain(device, event, 0); if (event != ACPI_VIDEO_NOTIFY_SWITCH)
acpi_notifier_call_chain(device, event, 0);
if (keycode) { if (keycode) {
input_report_key(input, keycode, 1); input_report_key(input, keycode, 1);
......
...@@ -1199,6 +1199,26 @@ unsigned int cpufreq_quick_get(unsigned int cpu) ...@@ -1199,6 +1199,26 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
} }
EXPORT_SYMBOL(cpufreq_quick_get); EXPORT_SYMBOL(cpufreq_quick_get);
/**
* cpufreq_quick_get_max - get the max reported CPU frequency for this CPU
* @cpu: CPU number
*
* Just return the max possible frequency for a given CPU.
*/
unsigned int cpufreq_quick_get_max(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
unsigned int ret_freq = 0;
if (policy) {
ret_freq = policy->max;
cpufreq_cpu_put(policy);
}
return ret_freq;
}
EXPORT_SYMBOL(cpufreq_quick_get_max);
static unsigned int __cpufreq_get(unsigned int cpu) static unsigned int __cpufreq_get(unsigned int cpu)
{ {
......
...@@ -560,6 +560,11 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -560,6 +560,11 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
mode_changed = true; mode_changed = true;
} else if (set->fb == NULL) { } else if (set->fb == NULL) {
mode_changed = true; mode_changed = true;
} else if (set->fb->depth != set->crtc->fb->depth) {
mode_changed = true;
} else if (set->fb->bits_per_pixel !=
set->crtc->fb->bits_per_pixel) {
mode_changed = true;
} else } else
fb_changed = true; fb_changed = true;
} }
......
...@@ -865,7 +865,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) ...@@ -865,7 +865,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
MEMSTAT_VID_SHIFT); MEMSTAT_VID_SHIFT);
seq_printf(m, "Current P-state: %d\n", seq_printf(m, "Current P-state: %d\n",
(rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
} else if (IS_GEN6(dev)) { } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS); u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS);
u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
...@@ -1123,6 +1123,44 @@ static int i915_emon_status(struct seq_file *m, void *unused) ...@@ -1123,6 +1123,44 @@ static int i915_emon_status(struct seq_file *m, void *unused)
return 0; return 0;
} }
static int i915_ring_freq_table(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
int gpu_freq, ia_freq;
if (!(IS_GEN6(dev) || IS_GEN7(dev))) {
seq_printf(m, "unsupported on this chipset\n");
return 0;
}
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\n");
for (gpu_freq = dev_priv->min_delay; gpu_freq <= dev_priv->max_delay;
gpu_freq++) {
I915_WRITE(GEN6_PCODE_DATA, gpu_freq);
I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
GEN6_PCODE_READ_MIN_FREQ_TABLE);
if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) &
GEN6_PCODE_READY) == 0, 10)) {
DRM_ERROR("pcode read of freq table timed out\n");
continue;
}
ia_freq = I915_READ(GEN6_PCODE_DATA);
seq_printf(m, "%d\t\t%d\n", gpu_freq * 50, ia_freq * 100);
}
mutex_unlock(&dev->struct_mutex);
return 0;
}
static int i915_gfxec(struct seq_file *m, void *unused) static int i915_gfxec(struct seq_file *m, void *unused)
{ {
struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_info_node *node = (struct drm_info_node *) m->private;
...@@ -1430,6 +1468,7 @@ static struct drm_info_list i915_debugfs_list[] = { ...@@ -1430,6 +1468,7 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_inttoext_table", i915_inttoext_table, 0}, {"i915_inttoext_table", i915_inttoext_table, 0},
{"i915_drpc_info", i915_drpc_info, 0}, {"i915_drpc_info", i915_drpc_info, 0},
{"i915_emon_status", i915_emon_status, 0}, {"i915_emon_status", i915_emon_status, 0},
{"i915_ring_freq_table", i915_ring_freq_table, 0},
{"i915_gfxec", i915_gfxec, 0}, {"i915_gfxec", i915_gfxec, 0},
{"i915_fbc_status", i915_fbc_status, 0}, {"i915_fbc_status", i915_fbc_status, 0},
{"i915_sr_status", i915_sr_status, 0}, {"i915_sr_status", i915_sr_status, 0},
......
...@@ -1073,6 +1073,9 @@ static void i915_setup_compression(struct drm_device *dev, int size) ...@@ -1073,6 +1073,9 @@ static void i915_setup_compression(struct drm_device *dev, int size)
unsigned long cfb_base; unsigned long cfb_base;
unsigned long ll_base = 0; unsigned long ll_base = 0;
/* Just in case the BIOS is doing something questionable. */
intel_disable_fbc(dev);
compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0); compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0);
if (compressed_fb) if (compressed_fb)
compressed_fb = drm_mm_get_block(compressed_fb, size, 4096); compressed_fb = drm_mm_get_block(compressed_fb, size, 4096);
...@@ -1099,7 +1102,6 @@ static void i915_setup_compression(struct drm_device *dev, int size) ...@@ -1099,7 +1102,6 @@ static void i915_setup_compression(struct drm_device *dev, int size)
dev_priv->cfb_size = size; dev_priv->cfb_size = size;
intel_disable_fbc(dev);
dev_priv->compressed_fb = compressed_fb; dev_priv->compressed_fb = compressed_fb;
if (HAS_PCH_SPLIT(dev)) if (HAS_PCH_SPLIT(dev))
I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start); I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start);
...@@ -1943,7 +1945,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -1943,7 +1945,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (!dev_priv->mm.gtt) { if (!dev_priv->mm.gtt) {
DRM_ERROR("Failed to initialize GTT\n"); DRM_ERROR("Failed to initialize GTT\n");
ret = -ENODEV; ret = -ENODEV;
goto out_iomapfree; goto out_rmmap;
} }
agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
...@@ -1987,7 +1989,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -1987,7 +1989,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
if (dev_priv->wq == NULL) { if (dev_priv->wq == NULL) {
DRM_ERROR("Failed to create our workqueue.\n"); DRM_ERROR("Failed to create our workqueue.\n");
ret = -ENOMEM; ret = -ENOMEM;
goto out_iomapfree; goto out_mtrrfree;
} }
/* enable GEM by default */ /* enable GEM by default */
...@@ -2074,13 +2076,21 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -2074,13 +2076,21 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
return 0; return 0;
out_gem_unload: out_gem_unload:
if (dev_priv->mm.inactive_shrinker.shrink)
unregister_shrinker(&dev_priv->mm.inactive_shrinker);
if (dev->pdev->msi_enabled) if (dev->pdev->msi_enabled)
pci_disable_msi(dev->pdev); pci_disable_msi(dev->pdev);
intel_teardown_gmbus(dev); intel_teardown_gmbus(dev);
intel_teardown_mchbar(dev); intel_teardown_mchbar(dev);
destroy_workqueue(dev_priv->wq); destroy_workqueue(dev_priv->wq);
out_iomapfree: out_mtrrfree:
if (dev_priv->mm.gtt_mtrr >= 0) {
mtrr_del(dev_priv->mm.gtt_mtrr, dev->agp->base,
dev->agp->agp_info.aper_size * 1024 * 1024);
dev_priv->mm.gtt_mtrr = -1;
}
io_mapping_free(dev_priv->mm.gtt_mapping); io_mapping_free(dev_priv->mm.gtt_mapping);
out_rmmap: out_rmmap:
pci_iounmap(dev->pdev, dev_priv->regs); pci_iounmap(dev->pdev, dev_priv->regs);
......
...@@ -37,38 +37,70 @@ ...@@ -37,38 +37,70 @@
#include <linux/console.h> #include <linux/console.h>
#include "drm_crtc_helper.h" #include "drm_crtc_helper.h"
static int i915_modeset = -1; static int i915_modeset __read_mostly = -1;
module_param_named(modeset, i915_modeset, int, 0400); module_param_named(modeset, i915_modeset, int, 0400);
MODULE_PARM_DESC(modeset,
"Use kernel modesetting [KMS] (0=DRM_I915_KMS from .config, "
"1=on, -1=force vga console preference [default])");
unsigned int i915_fbpercrtc = 0; unsigned int i915_fbpercrtc __always_unused = 0;
module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
int i915_panel_ignore_lid = 0; int i915_panel_ignore_lid __read_mostly = 0;
module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600); module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600);
MODULE_PARM_DESC(panel_ignore_lid,
"Override lid status (0=autodetect [default], 1=lid open, "
"-1=lid closed)");
unsigned int i915_powersave = 1; unsigned int i915_powersave __read_mostly = 1;
module_param_named(powersave, i915_powersave, int, 0600); module_param_named(powersave, i915_powersave, int, 0600);
MODULE_PARM_DESC(powersave,
"Enable powersavings, fbc, downclocking, etc. (default: true)");
unsigned int i915_semaphores = 0; unsigned int i915_semaphores __read_mostly = 0;
module_param_named(semaphores, i915_semaphores, int, 0600); module_param_named(semaphores, i915_semaphores, int, 0600);
MODULE_PARM_DESC(semaphores,
"Use semaphores for inter-ring sync (default: false)");
unsigned int i915_enable_rc6 = 1; unsigned int i915_enable_rc6 __read_mostly = 0;
module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600); module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600);
MODULE_PARM_DESC(i915_enable_rc6,
"Enable power-saving render C-state 6 (default: true)");
unsigned int i915_enable_fbc = 0; unsigned int i915_enable_fbc __read_mostly = 1;
module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600); module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600);
MODULE_PARM_DESC(i915_enable_fbc,
"Enable frame buffer compression for power savings "
"(default: false)");
unsigned int i915_lvds_downclock = 0; unsigned int i915_lvds_downclock __read_mostly = 0;
module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
MODULE_PARM_DESC(lvds_downclock,
"Use panel (LVDS/eDP) downclocking for power savings "
"(default: false)");
unsigned int i915_panel_use_ssc = 1; unsigned int i915_panel_use_ssc __read_mostly = 1;
module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600); module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600);
MODULE_PARM_DESC(lvds_use_ssc,
"Use Spread Spectrum Clock with panels [LVDS/eDP] "
"(default: true)");
int i915_vbt_sdvo_panel_type = -1; int i915_vbt_sdvo_panel_type __read_mostly = -1;
module_param_named(vbt_sdvo_panel_type, i915_vbt_sdvo_panel_type, int, 0600); module_param_named(vbt_sdvo_panel_type, i915_vbt_sdvo_panel_type, int, 0600);
MODULE_PARM_DESC(vbt_sdvo_panel_type,
"Override selection of SDVO panel mode in the VBT "
"(default: auto)");
static bool i915_try_reset = true; static bool i915_try_reset __read_mostly = true;
module_param_named(reset, i915_try_reset, bool, 0600); module_param_named(reset, i915_try_reset, bool, 0600);
MODULE_PARM_DESC(reset, "Attempt GPU resets (default: true)");
bool i915_enable_hangcheck __read_mostly = true;
module_param_named(enable_hangcheck, i915_enable_hangcheck, bool, 0644);
MODULE_PARM_DESC(enable_hangcheck,
"Periodically check GPU activity for detecting hangs. "
"WARNING: Disabling this can cause system wide hangs. "
"(default: true)");
static struct drm_driver driver; static struct drm_driver driver;
extern int intel_agp_enabled; extern int intel_agp_enabled;
...@@ -345,12 +377,17 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) ...@@ -345,12 +377,17 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
{ {
int loop = 500; if (dev_priv->gt_fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES ) {
u32 fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); int loop = 500;
while (fifo < 20 && loop--) { u32 fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
udelay(10); while (fifo <= GT_FIFO_NUM_RESERVED_ENTRIES && loop--) {
fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); udelay(10);
fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
}
WARN_ON(loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES);
dev_priv->gt_fifo_count = fifo;
} }
dev_priv->gt_fifo_count--;
} }
static int i915_drm_freeze(struct drm_device *dev) static int i915_drm_freeze(struct drm_device *dev)
...@@ -577,6 +614,7 @@ int i915_reset(struct drm_device *dev, u8 flags) ...@@ -577,6 +614,7 @@ int i915_reset(struct drm_device *dev, u8 flags)
if (get_seconds() - dev_priv->last_gpu_reset < 5) { if (get_seconds() - dev_priv->last_gpu_reset < 5) {
DRM_ERROR("GPU hanging too fast, declaring wedged!\n"); DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
} else switch (INTEL_INFO(dev)->gen) { } else switch (INTEL_INFO(dev)->gen) {
case 7:
case 6: case 6:
ret = gen6_do_reset(dev, flags); ret = gen6_do_reset(dev, flags);
/* If reset with a user forcewake, try to restore */ /* If reset with a user forcewake, try to restore */
......
...@@ -214,6 +214,8 @@ struct drm_i915_display_funcs { ...@@ -214,6 +214,8 @@ struct drm_i915_display_funcs {
int (*queue_flip)(struct drm_device *dev, struct drm_crtc *crtc, int (*queue_flip)(struct drm_device *dev, struct drm_crtc *crtc,
struct drm_framebuffer *fb, struct drm_framebuffer *fb,
struct drm_i915_gem_object *obj); struct drm_i915_gem_object *obj);
int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
int x, int y);
/* clock updates for mode set */ /* clock updates for mode set */
/* cursor updates */ /* cursor updates */
/* render clock increase/decrease */ /* render clock increase/decrease */
...@@ -264,6 +266,7 @@ enum intel_pch { ...@@ -264,6 +266,7 @@ enum intel_pch {
#define QUIRK_PIPEA_FORCE (1<<0) #define QUIRK_PIPEA_FORCE (1<<0)
struct intel_fbdev; struct intel_fbdev;
struct intel_fbc_work;
typedef struct drm_i915_private { typedef struct drm_i915_private {
struct drm_device *dev; struct drm_device *dev;
...@@ -274,6 +277,7 @@ typedef struct drm_i915_private { ...@@ -274,6 +277,7 @@ typedef struct drm_i915_private {
int relative_constants_mode; int relative_constants_mode;
void __iomem *regs; void __iomem *regs;
u32 gt_fifo_count;
struct intel_gmbus { struct intel_gmbus {
struct i2c_adapter adapter; struct i2c_adapter adapter;
...@@ -328,11 +332,10 @@ typedef struct drm_i915_private { ...@@ -328,11 +332,10 @@ typedef struct drm_i915_private {
uint32_t last_instdone1; uint32_t last_instdone1;
unsigned long cfb_size; unsigned long cfb_size;
unsigned long cfb_pitch; unsigned int cfb_fb;
unsigned long cfb_offset; enum plane cfb_plane;
int cfb_fence;
int cfb_plane;
int cfb_y; int cfb_y;
struct intel_fbc_work *fbc_work;
struct intel_opregion opregion; struct intel_opregion opregion;
...@@ -985,15 +988,16 @@ struct drm_i915_file_private { ...@@ -985,15 +988,16 @@ struct drm_i915_file_private {
extern struct drm_ioctl_desc i915_ioctls[]; extern struct drm_ioctl_desc i915_ioctls[];
extern int i915_max_ioctl; extern int i915_max_ioctl;
extern unsigned int i915_fbpercrtc; extern unsigned int i915_fbpercrtc __always_unused;
extern int i915_panel_ignore_lid; extern int i915_panel_ignore_lid __read_mostly;
extern unsigned int i915_powersave; extern unsigned int i915_powersave __read_mostly;
extern unsigned int i915_semaphores; extern unsigned int i915_semaphores __read_mostly;
extern unsigned int i915_lvds_downclock; extern unsigned int i915_lvds_downclock __read_mostly;
extern unsigned int i915_panel_use_ssc; extern unsigned int i915_panel_use_ssc __read_mostly;
extern int i915_vbt_sdvo_panel_type; extern int i915_vbt_sdvo_panel_type __read_mostly;
extern unsigned int i915_enable_rc6; extern unsigned int i915_enable_rc6 __read_mostly;
extern unsigned int i915_enable_fbc; extern unsigned int i915_enable_fbc __read_mostly;
extern bool i915_enable_hangcheck __read_mostly;
extern int i915_suspend(struct drm_device *dev, pm_message_t state); extern int i915_suspend(struct drm_device *dev, pm_message_t state);
extern int i915_resume(struct drm_device *dev); extern int i915_resume(struct drm_device *dev);
...@@ -1163,7 +1167,7 @@ void i915_gem_clflush_object(struct drm_i915_gem_object *obj); ...@@ -1163,7 +1167,7 @@ void i915_gem_clflush_object(struct drm_i915_gem_object *obj);
int __must_check i915_gem_object_set_domain(struct drm_i915_gem_object *obj, int __must_check i915_gem_object_set_domain(struct drm_i915_gem_object *obj,
uint32_t read_domains, uint32_t read_domains,
uint32_t write_domain); uint32_t write_domain);
int __must_check i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj); int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
int __must_check i915_gem_init_ringbuffer(struct drm_device *dev); int __must_check i915_gem_init_ringbuffer(struct drm_device *dev);
void i915_gem_cleanup_ringbuffer(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
void i915_gem_do_init(struct drm_device *dev, void i915_gem_do_init(struct drm_device *dev,
...@@ -1182,7 +1186,8 @@ int __must_check ...@@ -1182,7 +1186,8 @@ int __must_check
i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj,
bool write); bool write);
int __must_check int __must_check
i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj, i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
u32 alignment,
struct intel_ring_buffer *pipelined); struct intel_ring_buffer *pipelined);
int i915_gem_attach_phys_object(struct drm_device *dev, int i915_gem_attach_phys_object(struct drm_device *dev,
struct drm_i915_gem_object *obj, struct drm_i915_gem_object *obj,
...@@ -1196,9 +1201,14 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file); ...@@ -1196,9 +1201,14 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file);
uint32_t uint32_t
i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj); i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj);
int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
enum i915_cache_level cache_level);
/* i915_gem_gtt.c */ /* i915_gem_gtt.c */
void i915_gem_restore_gtt_mappings(struct drm_device *dev); void i915_gem_restore_gtt_mappings(struct drm_device *dev);
int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj); int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj);
void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj,
enum i915_cache_level cache_level);
void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj); void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj);
/* i915_gem_evict.c */ /* i915_gem_evict.c */
...@@ -1280,12 +1290,8 @@ extern void intel_modeset_init(struct drm_device *dev); ...@@ -1280,12 +1290,8 @@ extern void intel_modeset_init(struct drm_device *dev);
extern void intel_modeset_gem_init(struct drm_device *dev); extern void intel_modeset_gem_init(struct drm_device *dev);
extern void intel_modeset_cleanup(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev);
extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
extern void i8xx_disable_fbc(struct drm_device *dev);
extern void g4x_disable_fbc(struct drm_device *dev);
extern void ironlake_disable_fbc(struct drm_device *dev);
extern void intel_disable_fbc(struct drm_device *dev);
extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
extern bool intel_fbc_enabled(struct drm_device *dev); extern bool intel_fbc_enabled(struct drm_device *dev);
extern void intel_disable_fbc(struct drm_device *dev);
extern bool ironlake_set_drps(struct drm_device *dev, u8 val); extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
extern void ironlake_enable_rc6(struct drm_device *dev); extern void ironlake_enable_rc6(struct drm_device *dev);
extern void gen6_set_rps(struct drm_device *dev, u8 val); extern void gen6_set_rps(struct drm_device *dev, u8 val);
......
...@@ -1771,8 +1771,11 @@ i915_add_request(struct intel_ring_buffer *ring, ...@@ -1771,8 +1771,11 @@ i915_add_request(struct intel_ring_buffer *ring,
ring->outstanding_lazy_request = false; ring->outstanding_lazy_request = false;
if (!dev_priv->mm.suspended) { if (!dev_priv->mm.suspended) {
mod_timer(&dev_priv->hangcheck_timer, if (i915_enable_hangcheck) {
jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); mod_timer(&dev_priv->hangcheck_timer,
jiffies +
msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
}
if (was_empty) if (was_empty)
queue_delayed_work(dev_priv->wq, queue_delayed_work(dev_priv->wq,
&dev_priv->mm.retire_work, HZ); &dev_priv->mm.retire_work, HZ);
...@@ -2143,6 +2146,30 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj) ...@@ -2143,6 +2146,30 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj)
return 0; return 0;
} }
static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj)
{
u32 old_write_domain, old_read_domains;
/* Act a barrier for all accesses through the GTT */
mb();
/* Force a pagefault for domain tracking on next user access */
i915_gem_release_mmap(obj);
if ((obj->base.read_domains & I915_GEM_DOMAIN_GTT) == 0)
return;
old_read_domains = obj->base.read_domains;
old_write_domain = obj->base.write_domain;
obj->base.read_domains &= ~I915_GEM_DOMAIN_GTT;
obj->base.write_domain &= ~I915_GEM_DOMAIN_GTT;
trace_i915_gem_object_change_domain(obj,
old_read_domains,
old_write_domain);
}
/** /**
* Unbinds an object from the GTT aperture. * Unbinds an object from the GTT aperture.
*/ */
...@@ -2159,23 +2186,28 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) ...@@ -2159,23 +2186,28 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
return -EINVAL; return -EINVAL;
} }
/* blow away mappings if mapped through GTT */ ret = i915_gem_object_finish_gpu(obj);
i915_gem_release_mmap(obj);
/* Move the object to the CPU domain to ensure that
* any possible CPU writes while it's not in the GTT
* are flushed when we go to remap it. This will
* also ensure that all pending GPU writes are finished
* before we unbind.
*/
ret = i915_gem_object_set_to_cpu_domain(obj, 1);
if (ret == -ERESTARTSYS) if (ret == -ERESTARTSYS)
return ret; return ret;
/* Continue on if we fail due to EIO, the GPU is hung so we /* Continue on if we fail due to EIO, the GPU is hung so we
* should be safe and we need to cleanup or else we might * should be safe and we need to cleanup or else we might
* cause memory corruption through use-after-free. * cause memory corruption through use-after-free.
*/ */
i915_gem_object_finish_gtt(obj);
/* Move the object to the CPU domain to ensure that
* any possible CPU writes while it's not in the GTT
* are flushed when we go to remap it.
*/
if (ret == 0)
ret = i915_gem_object_set_to_cpu_domain(obj, 1);
if (ret == -ERESTARTSYS)
return ret;
if (ret) { if (ret) {
/* In the event of a disaster, abandon all caches and
* hope for the best.
*/
i915_gem_clflush_object(obj); i915_gem_clflush_object(obj);
obj->base.read_domains = obj->base.write_domain = I915_GEM_DOMAIN_CPU; obj->base.read_domains = obj->base.write_domain = I915_GEM_DOMAIN_CPU;
} }
...@@ -2997,51 +3029,139 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) ...@@ -2997,51 +3029,139 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
return 0; return 0;
} }
int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
enum i915_cache_level cache_level)
{
int ret;
if (obj->cache_level == cache_level)
return 0;
if (obj->pin_count) {
DRM_DEBUG("can not change the cache level of pinned objects\n");
return -EBUSY;
}
if (obj->gtt_space) {
ret = i915_gem_object_finish_gpu(obj);
if (ret)
return ret;
i915_gem_object_finish_gtt(obj);
/* Before SandyBridge, you could not use tiling or fence
* registers with snooped memory, so relinquish any fences
* currently pointing to our region in the aperture.
*/
if (INTEL_INFO(obj->base.dev)->gen < 6) {
ret = i915_gem_object_put_fence(obj);
if (ret)
return ret;
}
i915_gem_gtt_rebind_object(obj, cache_level);
}
if (cache_level == I915_CACHE_NONE) {
u32 old_read_domains, old_write_domain;
/* If we're coming from LLC cached, then we haven't
* actually been tracking whether the data is in the
* CPU cache or not, since we only allow one bit set
* in obj->write_domain and have been skipping the clflushes.
* Just set it to the CPU cache for now.
*/
WARN_ON(obj->base.write_domain & ~I915_GEM_DOMAIN_CPU);
WARN_ON(obj->base.read_domains & ~I915_GEM_DOMAIN_CPU);
old_read_domains = obj->base.read_domains;
old_write_domain = obj->base.write_domain;
obj->base.read_domains = I915_GEM_DOMAIN_CPU;
obj->base.write_domain = I915_GEM_DOMAIN_CPU;
trace_i915_gem_object_change_domain(obj,
old_read_domains,
old_write_domain);
}
obj->cache_level = cache_level;
return 0;
}
/* /*
* Prepare buffer for display plane. Use uninterruptible for possible flush * Prepare buffer for display plane (scanout, cursors, etc).
* wait, as in modesetting process we're not supposed to be interrupted. * Can be called from an uninterruptible phase (modesetting) and allows
* any flushes to be pipelined (for pageflips).
*
* For the display plane, we want to be in the GTT but out of any write
* domains. So in many ways this looks like set_to_gtt_domain() apart from the
* ability to pipeline the waits, pinning and any additional subtleties
* that may differentiate the display plane from ordinary buffers.
*/ */
int int
i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj, i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
u32 alignment,
struct intel_ring_buffer *pipelined) struct intel_ring_buffer *pipelined)
{ {
uint32_t old_read_domains; u32 old_read_domains, old_write_domain;
int ret; int ret;
/* Not valid to be called on unbound objects. */
if (obj->gtt_space == NULL)
return -EINVAL;
ret = i915_gem_object_flush_gpu_write_domain(obj); ret = i915_gem_object_flush_gpu_write_domain(obj);
if (ret) if (ret)
return ret; return ret;
/* Currently, we are always called from an non-interruptible context. */
if (pipelined != obj->ring) { if (pipelined != obj->ring) {
ret = i915_gem_object_wait_rendering(obj); ret = i915_gem_object_wait_rendering(obj);
if (ret) if (ret)
return ret; return ret;
} }
/* The display engine is not coherent with the LLC cache on gen6. As
* a result, we make sure that the pinning that is about to occur is
* done with uncached PTEs. This is lowest common denominator for all
* chipsets.
*
* However for gen6+, we could do better by using the GFDT bit instead
* of uncaching, which would allow us to flush all the LLC-cached data
* with that bit in the PTE to main memory with just one PIPE_CONTROL.
*/
ret = i915_gem_object_set_cache_level(obj, I915_CACHE_NONE);
if (ret)
return ret;
/* As the user may map the buffer once pinned in the display plane
* (e.g. libkms for the bootup splash), we have to ensure that we
* always use map_and_fenceable for all scanout buffers.
*/
ret = i915_gem_object_pin(obj, alignment, true);
if (ret)
return ret;
i915_gem_object_flush_cpu_write_domain(obj); i915_gem_object_flush_cpu_write_domain(obj);
old_write_domain = obj->base.write_domain;
old_read_domains = obj->base.read_domains; old_read_domains = obj->base.read_domains;
/* It should now be out of any other write domains, and we can update
* the domain values for our changes.
*/
BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
obj->base.read_domains |= I915_GEM_DOMAIN_GTT; obj->base.read_domains |= I915_GEM_DOMAIN_GTT;
trace_i915_gem_object_change_domain(obj, trace_i915_gem_object_change_domain(obj,
old_read_domains, old_read_domains,
obj->base.write_domain); old_write_domain);
return 0; return 0;
} }
int int
i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj) i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj)
{ {
int ret; int ret;
if (!obj->active) if ((obj->base.read_domains & I915_GEM_GPU_DOMAINS) == 0)
return 0; return 0;
if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
...@@ -3050,6 +3170,9 @@ i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj) ...@@ -3050,6 +3170,9 @@ i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj)
return ret; return ret;
} }
/* Ensure that we invalidate the GPU's caches and TLBs. */
obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
return i915_gem_object_wait_rendering(obj); return i915_gem_object_wait_rendering(obj);
} }
...@@ -3576,7 +3699,23 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, ...@@ -3576,7 +3699,23 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
obj->base.write_domain = I915_GEM_DOMAIN_CPU; obj->base.write_domain = I915_GEM_DOMAIN_CPU;
obj->base.read_domains = I915_GEM_DOMAIN_CPU; obj->base.read_domains = I915_GEM_DOMAIN_CPU;
obj->cache_level = I915_CACHE_NONE; if (IS_GEN6(dev)) {
/* On Gen6, we can have the GPU use the LLC (the CPU
* cache) for about a 10% performance improvement
* compared to uncached. Graphics requests other than
* display scanout are coherent with the CPU in
* accessing this cache. This means in this mode we
* don't need to clflush on the CPU side, and on the
* GPU side we only need to flush internal caches to
* get data visible to the CPU.
*
* However, we maintain the display planes as UC, and so
* need to rebind when first used as such.
*/
obj->cache_level = I915_CACHE_LLC;
} else
obj->cache_level = I915_CACHE_NONE;
obj->base.driver_private = NULL; obj->base.driver_private = NULL;
obj->fence_reg = I915_FENCE_REG_NONE; obj->fence_reg = I915_FENCE_REG_NONE;
INIT_LIST_HEAD(&obj->mm_list); INIT_LIST_HEAD(&obj->mm_list);
......
...@@ -59,24 +59,8 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) ...@@ -59,24 +59,8 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
(dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE); (dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE);
list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
unsigned int agp_type =
cache_level_to_agp_type(dev, obj->cache_level);
i915_gem_clflush_object(obj); i915_gem_clflush_object(obj);
i915_gem_gtt_rebind_object(obj, obj->cache_level);
if (dev_priv->mm.gtt->needs_dmar) {
BUG_ON(!obj->sg_list);
intel_gtt_insert_sg_entries(obj->sg_list,
obj->num_sg,
obj->gtt_space->start >> PAGE_SHIFT,
agp_type);
} else
intel_gtt_insert_pages(obj->gtt_space->start
>> PAGE_SHIFT,
obj->base.size >> PAGE_SHIFT,
obj->pages,
agp_type);
} }
intel_gtt_chipset_flush(); intel_gtt_chipset_flush();
...@@ -110,6 +94,27 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj) ...@@ -110,6 +94,27 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
return 0; return 0;
} }
void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj,
enum i915_cache_level cache_level)
{
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned int agp_type = cache_level_to_agp_type(dev, cache_level);
if (dev_priv->mm.gtt->needs_dmar) {
BUG_ON(!obj->sg_list);
intel_gtt_insert_sg_entries(obj->sg_list,
obj->num_sg,
obj->gtt_space->start >> PAGE_SHIFT,
agp_type);
} else
intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT,
obj->base.size >> PAGE_SHIFT,
obj->pages,
agp_type);
}
void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
{ {
intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT, intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT,
......
...@@ -361,10 +361,12 @@ static void notify_ring(struct drm_device *dev, ...@@ -361,10 +361,12 @@ static void notify_ring(struct drm_device *dev,
ring->irq_seqno = seqno; ring->irq_seqno = seqno;
wake_up_all(&ring->irq_queue); wake_up_all(&ring->irq_queue);
if (i915_enable_hangcheck) {
dev_priv->hangcheck_count = 0; dev_priv->hangcheck_count = 0;
mod_timer(&dev_priv->hangcheck_timer, mod_timer(&dev_priv->hangcheck_timer,
jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); jiffies +
msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
}
} }
static void gen6_pm_rps_work(struct work_struct *work) static void gen6_pm_rps_work(struct work_struct *work)
...@@ -1664,6 +1666,9 @@ void i915_hangcheck_elapsed(unsigned long data) ...@@ -1664,6 +1666,9 @@ void i915_hangcheck_elapsed(unsigned long data)
uint32_t acthd, instdone, instdone1; uint32_t acthd, instdone, instdone1;
bool err = false; bool err = false;
if (!i915_enable_hangcheck)
return;
/* If all work is done then ACTHD clearly hasn't advanced. */ /* If all work is done then ACTHD clearly hasn't advanced. */
if (i915_hangcheck_ring_idle(&dev_priv->ring[RCS], &err) && if (i915_hangcheck_ring_idle(&dev_priv->ring[RCS], &err) &&
i915_hangcheck_ring_idle(&dev_priv->ring[VCS], &err) && i915_hangcheck_ring_idle(&dev_priv->ring[VCS], &err) &&
......
...@@ -579,6 +579,7 @@ ...@@ -579,6 +579,7 @@
#define DPFC_CTL_PLANEA (0<<30) #define DPFC_CTL_PLANEA (0<<30)
#define DPFC_CTL_PLANEB (1<<30) #define DPFC_CTL_PLANEB (1<<30)
#define DPFC_CTL_FENCE_EN (1<<29) #define DPFC_CTL_FENCE_EN (1<<29)
#define DPFC_CTL_PERSISTENT_MODE (1<<25)
#define DPFC_SR_EN (1<<10) #define DPFC_SR_EN (1<<10)
#define DPFC_CTL_LIMIT_1X (0<<6) #define DPFC_CTL_LIMIT_1X (0<<6)
#define DPFC_CTL_LIMIT_2X (1<<6) #define DPFC_CTL_LIMIT_2X (1<<6)
...@@ -3360,6 +3361,7 @@ ...@@ -3360,6 +3361,7 @@
#define FORCEWAKE_ACK 0x130090 #define FORCEWAKE_ACK 0x130090
#define GT_FIFO_FREE_ENTRIES 0x120008 #define GT_FIFO_FREE_ENTRIES 0x120008
#define GT_FIFO_NUM_RESERVED_ENTRIES 20
#define GEN6_RPNSWREQ 0xA008 #define GEN6_RPNSWREQ 0xA008
#define GEN6_TURBO_DISABLE (1<<31) #define GEN6_TURBO_DISABLE (1<<31)
...@@ -3434,7 +3436,9 @@ ...@@ -3434,7 +3436,9 @@
#define GEN6_PCODE_MAILBOX 0x138124 #define GEN6_PCODE_MAILBOX 0x138124
#define GEN6_PCODE_READY (1<<31) #define GEN6_PCODE_READY (1<<31)
#define GEN6_READ_OC_PARAMS 0xc #define GEN6_READ_OC_PARAMS 0xc
#define GEN6_PCODE_WRITE_MIN_FREQ_TABLE 0x9 #define GEN6_PCODE_WRITE_MIN_FREQ_TABLE 0x8
#define GEN6_PCODE_READ_MIN_FREQ_TABLE 0x9
#define GEN6_PCODE_DATA 0x138128 #define GEN6_PCODE_DATA 0x138128
#define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8
#endif /* _I915_REG_H_ */ #endif /* _I915_REG_H_ */
...@@ -760,15 +760,13 @@ static void i915_restore_display(struct drm_device *dev) ...@@ -760,15 +760,13 @@ static void i915_restore_display(struct drm_device *dev)
/* FIXME: restore TV & SDVO state */ /* FIXME: restore TV & SDVO state */
/* only restore FBC info on the platform that supports FBC*/ /* only restore FBC info on the platform that supports FBC*/
intel_disable_fbc(dev);
if (I915_HAS_FBC(dev)) { if (I915_HAS_FBC(dev)) {
if (HAS_PCH_SPLIT(dev)) { if (HAS_PCH_SPLIT(dev)) {
ironlake_disable_fbc(dev);
I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE); I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
} else if (IS_GM45(dev)) { } else if (IS_GM45(dev)) {
g4x_disable_fbc(dev);
I915_WRITE(DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE); I915_WRITE(DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
} else { } else {
i8xx_disable_fbc(dev);
I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE); I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE);
I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE); I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE);
I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2); I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2);
...@@ -878,8 +876,10 @@ int i915_restore_state(struct drm_device *dev) ...@@ -878,8 +876,10 @@ int i915_restore_state(struct drm_device *dev)
intel_init_emon(dev); intel_init_emon(dev);
} }
if (IS_GEN6(dev)) if (IS_GEN6(dev)) {
gen6_enable_rps(dev_priv); gen6_enable_rps(dev_priv);
gen6_update_ring_freq(dev_priv);
}
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
......
...@@ -74,7 +74,7 @@ get_blocksize(void *p) ...@@ -74,7 +74,7 @@ get_blocksize(void *p)
static void static void
fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
struct lvds_dvo_timing *dvo_timing) const struct lvds_dvo_timing *dvo_timing)
{ {
panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) |
dvo_timing->hactive_lo; dvo_timing->hactive_lo;
...@@ -115,20 +115,75 @@ fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, ...@@ -115,20 +115,75 @@ fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
drm_mode_set_name(panel_fixed_mode); drm_mode_set_name(panel_fixed_mode);
} }
static bool
lvds_dvo_timing_equal_size(const struct lvds_dvo_timing *a,
const struct lvds_dvo_timing *b)
{
if (a->hactive_hi != b->hactive_hi ||
a->hactive_lo != b->hactive_lo)
return false;
if (a->hsync_off_hi != b->hsync_off_hi ||
a->hsync_off_lo != b->hsync_off_lo)
return false;
if (a->hsync_pulse_width != b->hsync_pulse_width)
return false;
if (a->hblank_hi != b->hblank_hi ||
a->hblank_lo != b->hblank_lo)
return false;
if (a->vactive_hi != b->vactive_hi ||
a->vactive_lo != b->vactive_lo)
return false;
if (a->vsync_off != b->vsync_off)
return false;
if (a->vsync_pulse_width != b->vsync_pulse_width)
return false;
if (a->vblank_hi != b->vblank_hi ||
a->vblank_lo != b->vblank_lo)
return false;
return true;
}
static const struct lvds_dvo_timing *
get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data,
const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs,
int index)
{
/*
* the size of fp_timing varies on the different platform.
* So calculate the DVO timing relative offset in LVDS data
* entry to get the DVO timing entry
*/
int lfp_data_size =
lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset -
lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset;
int dvo_timing_offset =
lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset -
lvds_lfp_data_ptrs->ptr[0].fp_timing_offset;
char *entry = (char *)lvds_lfp_data->data + lfp_data_size * index;
return (struct lvds_dvo_timing *)(entry + dvo_timing_offset);
}
/* Try to find integrated panel data */ /* Try to find integrated panel data */
static void static void
parse_lfp_panel_data(struct drm_i915_private *dev_priv, parse_lfp_panel_data(struct drm_i915_private *dev_priv,
struct bdb_header *bdb) struct bdb_header *bdb)
{ {
struct bdb_lvds_options *lvds_options; const struct bdb_lvds_options *lvds_options;
struct bdb_lvds_lfp_data *lvds_lfp_data; const struct bdb_lvds_lfp_data *lvds_lfp_data;
struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
struct bdb_lvds_lfp_data_entry *entry; const struct lvds_dvo_timing *panel_dvo_timing;
struct lvds_dvo_timing *dvo_timing;
struct drm_display_mode *panel_fixed_mode; struct drm_display_mode *panel_fixed_mode;
int lfp_data_size, dvo_timing_offset; int i, downclock;
int i, temp_downclock;
struct drm_display_mode *temp_mode;
lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
if (!lvds_options) if (!lvds_options)
...@@ -150,75 +205,44 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, ...@@ -150,75 +205,44 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
dev_priv->lvds_vbt = 1; dev_priv->lvds_vbt = 1;
lfp_data_size = lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset - panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset; lvds_lfp_data_ptrs,
entry = (struct bdb_lvds_lfp_data_entry *) lvds_options->panel_type);
((uint8_t *)lvds_lfp_data->data + (lfp_data_size *
lvds_options->panel_type));
dvo_timing_offset = lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset -
lvds_lfp_data_ptrs->ptr[0].fp_timing_offset;
/*
* the size of fp_timing varies on the different platform.
* So calculate the DVO timing relative offset in LVDS data
* entry to get the DVO timing entry
*/
dvo_timing = (struct lvds_dvo_timing *)
((unsigned char *)entry + dvo_timing_offset);
panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
if (!panel_fixed_mode) if (!panel_fixed_mode)
return; return;
fill_detail_timing_data(panel_fixed_mode, dvo_timing); fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing);
dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode;
DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n"); DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n");
drm_mode_debug_printmodeline(panel_fixed_mode); drm_mode_debug_printmodeline(panel_fixed_mode);
temp_mode = kzalloc(sizeof(*temp_mode), GFP_KERNEL);
temp_downclock = panel_fixed_mode->clock;
/* /*
* enumerate the LVDS panel timing info entry in VBT to check whether * Iterate over the LVDS panel timing info to find the lowest clock
* the LVDS downclock is found. * for the native resolution.
*/ */
downclock = panel_dvo_timing->clock;
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
entry = (struct bdb_lvds_lfp_data_entry *) const struct lvds_dvo_timing *dvo_timing;
((uint8_t *)lvds_lfp_data->data + (lfp_data_size * i));
dvo_timing = (struct lvds_dvo_timing *) dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
((unsigned char *)entry + dvo_timing_offset); lvds_lfp_data_ptrs,
i);
fill_detail_timing_data(temp_mode, dvo_timing); if (lvds_dvo_timing_equal_size(dvo_timing, panel_dvo_timing) &&
dvo_timing->clock < downclock)
if (temp_mode->hdisplay == panel_fixed_mode->hdisplay && downclock = dvo_timing->clock;
temp_mode->hsync_start == panel_fixed_mode->hsync_start &&
temp_mode->hsync_end == panel_fixed_mode->hsync_end &&
temp_mode->htotal == panel_fixed_mode->htotal &&
temp_mode->vdisplay == panel_fixed_mode->vdisplay &&
temp_mode->vsync_start == panel_fixed_mode->vsync_start &&
temp_mode->vsync_end == panel_fixed_mode->vsync_end &&
temp_mode->vtotal == panel_fixed_mode->vtotal &&
temp_mode->clock < temp_downclock) {
/*
* downclock is already found. But we expect
* to find the lower downclock.
*/
temp_downclock = temp_mode->clock;
}
/* clear it to zero */
memset(temp_mode, 0, sizeof(*temp_mode));
} }
kfree(temp_mode);
if (temp_downclock < panel_fixed_mode->clock && if (downclock < panel_dvo_timing->clock && i915_lvds_downclock) {
i915_lvds_downclock) {
dev_priv->lvds_downclock_avail = 1; dev_priv->lvds_downclock_avail = 1;
dev_priv->lvds_downclock = temp_downclock; dev_priv->lvds_downclock = downclock * 10;
DRM_DEBUG_KMS("LVDS downclock is found in VBT. " DRM_DEBUG_KMS("LVDS downclock is found in VBT. "
"Normal Clock %dKHz, downclock %dKHz\n", "Normal Clock %dKHz, downclock %dKHz\n",
temp_downclock, panel_fixed_mode->clock); panel_fixed_mode->clock, 10*downclock);
} }
return;
} }
/* Try to find sdvo panel data */ /* Try to find sdvo panel data */
......
...@@ -50,7 +50,6 @@ struct intel_dp { ...@@ -50,7 +50,6 @@ struct intel_dp {
bool has_audio; bool has_audio;
int force_audio; int force_audio;
uint32_t color_range; uint32_t color_range;
int dpms_mode;
uint8_t link_bw; uint8_t link_bw;
uint8_t lane_count; uint8_t lane_count;
uint8_t dpcd[4]; uint8_t dpcd[4];
...@@ -138,8 +137,8 @@ intel_dp_max_lane_count(struct intel_dp *intel_dp) ...@@ -138,8 +137,8 @@ intel_dp_max_lane_count(struct intel_dp *intel_dp)
{ {
int max_lane_count = 4; int max_lane_count = 4;
if (intel_dp->dpcd[0] >= 0x11) { if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) {
max_lane_count = intel_dp->dpcd[2] & 0x1f; max_lane_count = intel_dp->dpcd[DP_MAX_LANE_COUNT] & 0x1f;
switch (max_lane_count) { switch (max_lane_count) {
case 1: case 2: case 4: case 1: case 2: case 4:
break; break;
...@@ -153,7 +152,7 @@ intel_dp_max_lane_count(struct intel_dp *intel_dp) ...@@ -153,7 +152,7 @@ intel_dp_max_lane_count(struct intel_dp *intel_dp)
static int static int
intel_dp_max_link_bw(struct intel_dp *intel_dp) intel_dp_max_link_bw(struct intel_dp *intel_dp)
{ {
int max_link_bw = intel_dp->dpcd[1]; int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
switch (max_link_bw) { switch (max_link_bw) {
case DP_LINK_BW_1_62: case DP_LINK_BW_1_62:
...@@ -179,12 +178,14 @@ intel_dp_link_clock(uint8_t link_bw) ...@@ -179,12 +178,14 @@ intel_dp_link_clock(uint8_t link_bw)
static int static int
intel_dp_link_required(struct drm_device *dev, struct intel_dp *intel_dp, int pixel_clock) intel_dp_link_required(struct drm_device *dev, struct intel_dp *intel_dp, int pixel_clock)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = intel_dp->base.base.crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int bpp = 24;
if (is_edp(intel_dp)) if (intel_crtc)
return (pixel_clock * dev_priv->edp.bpp + 7) / 8; bpp = intel_crtc->bpp;
else
return pixel_clock * 3; return (pixel_clock * bpp + 7) / 8;
} }
static int static int
...@@ -682,7 +683,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, ...@@ -682,7 +683,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int lane_count = 4, bpp = 24; int lane_count = 4;
struct intel_dp_m_n m_n; struct intel_dp_m_n m_n;
int pipe = intel_crtc->pipe; int pipe = intel_crtc->pipe;
...@@ -701,7 +702,6 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, ...@@ -701,7 +702,6 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
break; break;
} else if (is_edp(intel_dp)) { } else if (is_edp(intel_dp)) {
lane_count = dev_priv->edp.lanes; lane_count = dev_priv->edp.lanes;
bpp = dev_priv->edp.bpp;
break; break;
} }
} }
...@@ -711,7 +711,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, ...@@ -711,7 +711,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
* the number of bytes_per_pixel post-LUT, which we always * the number of bytes_per_pixel post-LUT, which we always
* set up for 8-bits of R/G/B, or 3 bytes total. * set up for 8-bits of R/G/B, or 3 bytes total.
*/ */
intel_dp_compute_m_n(bpp, lane_count, intel_dp_compute_m_n(intel_crtc->bpp, lane_count,
mode->clock, adjusted_mode->clock, &m_n); mode->clock, adjusted_mode->clock, &m_n);
if (HAS_PCH_SPLIT(dev)) { if (HAS_PCH_SPLIT(dev)) {
...@@ -774,7 +774,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, ...@@ -774,7 +774,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
/* /*
* Check for DPCD version > 1.1 and enhanced framing support * Check for DPCD version > 1.1 and enhanced framing support
*/ */
if (intel_dp->dpcd[0] >= 0x11 && (intel_dp->dpcd[2] & DP_ENHANCED_FRAME_CAP)) { if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
(intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)) {
intel_dp->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; intel_dp->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
intel_dp->DP |= DP_ENHANCED_FRAMING; intel_dp->DP |= DP_ENHANCED_FRAMING;
} }
...@@ -942,11 +943,44 @@ static void ironlake_edp_pll_off(struct drm_encoder *encoder) ...@@ -942,11 +943,44 @@ static void ironlake_edp_pll_off(struct drm_encoder *encoder)
udelay(200); udelay(200);
} }
/* If the sink supports it, try to set the power state appropriately */
static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
{
int ret, i;
/* Should have a valid DPCD by this point */
if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
return;
if (mode != DRM_MODE_DPMS_ON) {
ret = intel_dp_aux_native_write_1(intel_dp, DP_SET_POWER,
DP_SET_POWER_D3);
if (ret != 1)
DRM_DEBUG_DRIVER("failed to write sink power state\n");
} else {
/*
* When turning on, we need to retry for 1ms to give the sink
* time to wake up.
*/
for (i = 0; i < 3; i++) {
ret = intel_dp_aux_native_write_1(intel_dp,
DP_SET_POWER,
DP_SET_POWER_D0);
if (ret == 1)
break;
msleep(1);
}
}
}
static void intel_dp_prepare(struct drm_encoder *encoder) static void intel_dp_prepare(struct drm_encoder *encoder)
{ {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
/* Wake up the sink first */
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
if (is_edp(intel_dp)) { if (is_edp(intel_dp)) {
ironlake_edp_backlight_off(dev); ironlake_edp_backlight_off(dev);
ironlake_edp_panel_off(dev); ironlake_edp_panel_off(dev);
...@@ -990,6 +1024,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) ...@@ -990,6 +1024,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
if (mode != DRM_MODE_DPMS_ON) { if (mode != DRM_MODE_DPMS_ON) {
if (is_edp(intel_dp)) if (is_edp(intel_dp))
ironlake_edp_backlight_off(dev); ironlake_edp_backlight_off(dev);
intel_dp_sink_dpms(intel_dp, mode);
intel_dp_link_down(intel_dp); intel_dp_link_down(intel_dp);
if (is_edp(intel_dp)) if (is_edp(intel_dp))
ironlake_edp_panel_off(dev); ironlake_edp_panel_off(dev);
...@@ -998,6 +1033,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) ...@@ -998,6 +1033,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
} else { } else {
if (is_edp(intel_dp)) if (is_edp(intel_dp))
ironlake_edp_panel_vdd_on(intel_dp); ironlake_edp_panel_vdd_on(intel_dp);
intel_dp_sink_dpms(intel_dp, mode);
if (!(dp_reg & DP_PORT_EN)) { if (!(dp_reg & DP_PORT_EN)) {
intel_dp_start_link_train(intel_dp); intel_dp_start_link_train(intel_dp);
if (is_edp(intel_dp)) { if (is_edp(intel_dp)) {
...@@ -1009,7 +1045,31 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) ...@@ -1009,7 +1045,31 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
if (is_edp(intel_dp)) if (is_edp(intel_dp))
ironlake_edp_backlight_on(dev); ironlake_edp_backlight_on(dev);
} }
intel_dp->dpms_mode = mode; }
/*
* Native read with retry for link status and receiver capability reads for
* cases where the sink may still be asleep.
*/
static bool
intel_dp_aux_native_read_retry(struct intel_dp *intel_dp, uint16_t address,
uint8_t *recv, int recv_bytes)
{
int ret, i;
/*
* Sinks are *supposed* to come up within 1ms from an off state,
* but we're also supposed to retry 3 times per the spec.
*/
for (i = 0; i < 3; i++) {
ret = intel_dp_aux_native_read(intel_dp, address, recv,
recv_bytes);
if (ret == recv_bytes)
return true;
msleep(1);
}
return false;
} }
/* /*
...@@ -1019,14 +1079,10 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) ...@@ -1019,14 +1079,10 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
static bool static bool
intel_dp_get_link_status(struct intel_dp *intel_dp) intel_dp_get_link_status(struct intel_dp *intel_dp)
{ {
int ret; return intel_dp_aux_native_read_retry(intel_dp,
DP_LANE0_1_STATUS,
ret = intel_dp_aux_native_read(intel_dp, intel_dp->link_status,
DP_LANE0_1_STATUS, DP_LINK_STATUS_SIZE);
intel_dp->link_status, DP_LINK_STATUS_SIZE);
if (ret != DP_LINK_STATUS_SIZE)
return false;
return true;
} }
static uint8_t static uint8_t
...@@ -1515,6 +1571,8 @@ intel_dp_link_down(struct intel_dp *intel_dp) ...@@ -1515,6 +1571,8 @@ intel_dp_link_down(struct intel_dp *intel_dp)
static void static void
intel_dp_check_link_status(struct intel_dp *intel_dp) intel_dp_check_link_status(struct intel_dp *intel_dp)
{ {
int ret;
if (!intel_dp->base.base.crtc) if (!intel_dp->base.base.crtc)
return; return;
...@@ -1523,6 +1581,15 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) ...@@ -1523,6 +1581,15 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
return; return;
} }
/* Try to read receiver status if the link appears to be up */
ret = intel_dp_aux_native_read(intel_dp,
0x000, intel_dp->dpcd,
sizeof (intel_dp->dpcd));
if (ret != sizeof(intel_dp->dpcd)) {
intel_dp_link_down(intel_dp);
return;
}
if (!intel_channel_eq_ok(intel_dp)) { if (!intel_channel_eq_ok(intel_dp)) {
intel_dp_start_link_train(intel_dp); intel_dp_start_link_train(intel_dp);
intel_dp_complete_link_train(intel_dp); intel_dp_complete_link_train(intel_dp);
...@@ -1533,6 +1600,7 @@ static enum drm_connector_status ...@@ -1533,6 +1600,7 @@ static enum drm_connector_status
ironlake_dp_detect(struct intel_dp *intel_dp) ironlake_dp_detect(struct intel_dp *intel_dp)
{ {
enum drm_connector_status status; enum drm_connector_status status;
bool ret;
/* Can't disconnect eDP, but you can close the lid... */ /* Can't disconnect eDP, but you can close the lid... */
if (is_edp(intel_dp)) { if (is_edp(intel_dp)) {
...@@ -1543,13 +1611,11 @@ ironlake_dp_detect(struct intel_dp *intel_dp) ...@@ -1543,13 +1611,11 @@ ironlake_dp_detect(struct intel_dp *intel_dp)
} }
status = connector_status_disconnected; status = connector_status_disconnected;
if (intel_dp_aux_native_read(intel_dp, ret = intel_dp_aux_native_read_retry(intel_dp,
0x000, intel_dp->dpcd, 0x000, intel_dp->dpcd,
sizeof (intel_dp->dpcd)) sizeof (intel_dp->dpcd));
== sizeof(intel_dp->dpcd)) { if (ret && intel_dp->dpcd[DP_DPCD_REV] != 0)
if (intel_dp->dpcd[0] != 0) status = connector_status_connected;
status = connector_status_connected;
}
DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0], DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0],
intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]); intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]);
return status; return status;
...@@ -1586,7 +1652,7 @@ g4x_dp_detect(struct intel_dp *intel_dp) ...@@ -1586,7 +1652,7 @@ g4x_dp_detect(struct intel_dp *intel_dp)
if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd, if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd,
sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd)) sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
{ {
if (intel_dp->dpcd[0] != 0) if (intel_dp->dpcd[DP_DPCD_REV] != 0)
status = connector_status_connected; status = connector_status_connected;
} }
...@@ -1790,8 +1856,7 @@ intel_dp_hot_plug(struct intel_encoder *intel_encoder) ...@@ -1790,8 +1856,7 @@ intel_dp_hot_plug(struct intel_encoder *intel_encoder)
{ {
struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base); struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base);
if (intel_dp->dpms_mode == DRM_MODE_DPMS_ON) intel_dp_check_link_status(intel_dp);
intel_dp_check_link_status(intel_dp);
} }
/* Return which DP Port should be selected for Transcoder DP control */ /* Return which DP Port should be selected for Transcoder DP control */
...@@ -1859,7 +1924,6 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -1859,7 +1924,6 @@ intel_dp_init(struct drm_device *dev, int output_reg)
return; return;
intel_dp->output_reg = output_reg; intel_dp->output_reg = output_reg;
intel_dp->dpms_mode = -1;
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
if (!intel_connector) { if (!intel_connector) {
...@@ -1954,8 +2018,9 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -1954,8 +2018,9 @@ intel_dp_init(struct drm_device *dev, int output_reg)
sizeof(intel_dp->dpcd)); sizeof(intel_dp->dpcd));
ironlake_edp_panel_vdd_off(intel_dp); ironlake_edp_panel_vdd_off(intel_dp);
if (ret == sizeof(intel_dp->dpcd)) { if (ret == sizeof(intel_dp->dpcd)) {
if (intel_dp->dpcd[0] >= 0x11) if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
dev_priv->no_aux_handshake = intel_dp->dpcd[3] & dev_priv->no_aux_handshake =
intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
DP_NO_AUX_HANDSHAKE_LINK_TRAINING; DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
} else { } else {
/* if this fails, presume the device is a ghost */ /* if this fails, presume the device is a ghost */
......
...@@ -170,6 +170,7 @@ struct intel_crtc { ...@@ -170,6 +170,7 @@ struct intel_crtc {
int16_t cursor_x, cursor_y; int16_t cursor_x, cursor_y;
int16_t cursor_width, cursor_height; int16_t cursor_width, cursor_height;
bool cursor_visible; bool cursor_visible;
unsigned int bpp;
}; };
#define to_intel_crtc(x) container_of(x, struct intel_crtc, base) #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
...@@ -233,6 +234,13 @@ struct intel_unpin_work { ...@@ -233,6 +234,13 @@ struct intel_unpin_work {
bool enable_stall_check; bool enable_stall_check;
}; };
struct intel_fbc_work {
struct delayed_work work;
struct drm_crtc *crtc;
struct drm_framebuffer *fb;
int interval;
};
int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter); int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus); extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
...@@ -317,6 +325,7 @@ extern void intel_enable_clock_gating(struct drm_device *dev); ...@@ -317,6 +325,7 @@ extern void intel_enable_clock_gating(struct drm_device *dev);
extern void ironlake_enable_drps(struct drm_device *dev); extern void ironlake_enable_drps(struct drm_device *dev);
extern void ironlake_disable_drps(struct drm_device *dev); extern void ironlake_disable_drps(struct drm_device *dev);
extern void gen6_enable_rps(struct drm_i915_private *dev_priv); extern void gen6_enable_rps(struct drm_i915_private *dev_priv);
extern void gen6_update_ring_freq(struct drm_i915_private *dev_priv);
extern void gen6_disable_rps(struct drm_device *dev); extern void gen6_disable_rps(struct drm_device *dev);
extern void intel_init_emon(struct drm_device *dev); extern void intel_init_emon(struct drm_device *dev);
......
...@@ -124,12 +124,18 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, ...@@ -124,12 +124,18 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
u32 sdvox; u32 sdvox;
sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE; sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE;
sdvox |= intel_hdmi->color_range; if (!HAS_PCH_SPLIT(dev))
sdvox |= intel_hdmi->color_range;
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
sdvox |= SDVO_VSYNC_ACTIVE_HIGH; sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
sdvox |= SDVO_HSYNC_ACTIVE_HIGH; sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
if (intel_crtc->bpp > 24)
sdvox |= COLOR_FORMAT_12bpc;
else
sdvox |= COLOR_FORMAT_8bpc;
/* Required on CPT */ /* Required on CPT */
if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev)) if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev))
sdvox |= HDMI_MODE_SELECT; sdvox |= HDMI_MODE_SELECT;
......
...@@ -297,19 +297,26 @@ static int intel_opregion_video_event(struct notifier_block *nb, ...@@ -297,19 +297,26 @@ static int intel_opregion_video_event(struct notifier_block *nb,
/* The only video events relevant to opregion are 0x80. These indicate /* The only video events relevant to opregion are 0x80. These indicate
either a docking event, lid switch or display switch request. In either a docking event, lid switch or display switch request. In
Linux, these are handled by the dock, button and video drivers. Linux, these are handled by the dock, button and video drivers.
We might want to fix the video driver to be opregion-aware in */
future, but right now we just indicate to the firmware that the
request has been handled */
struct opregion_acpi *acpi; struct opregion_acpi *acpi;
struct acpi_bus_event *event = data;
int ret = NOTIFY_OK;
if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0)
return NOTIFY_DONE;
if (!system_opregion) if (!system_opregion)
return NOTIFY_DONE; return NOTIFY_DONE;
acpi = system_opregion->acpi; acpi = system_opregion->acpi;
if (event->type == 0x80 && !(acpi->cevt & 0x1))
ret = NOTIFY_BAD;
acpi->csts = 0; acpi->csts = 0;
return NOTIFY_OK; return ret;
} }
static struct notifier_block intel_opregion_notifier = { static struct notifier_block intel_opregion_notifier = {
......
...@@ -773,14 +773,10 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, ...@@ -773,14 +773,10 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
if (ret != 0) if (ret != 0)
return ret; return ret;
ret = i915_gem_object_pin(new_bo, PAGE_SIZE, true); ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL);
if (ret != 0) if (ret != 0)
return ret; return ret;
ret = i915_gem_object_set_to_gtt_domain(new_bo, 0);
if (ret != 0)
goto out_unpin;
ret = i915_gem_object_put_fence(new_bo); ret = i915_gem_object_put_fence(new_bo);
if (ret) if (ret)
goto out_unpin; goto out_unpin;
......
...@@ -236,7 +236,8 @@ init_pipe_control(struct intel_ring_buffer *ring) ...@@ -236,7 +236,8 @@ init_pipe_control(struct intel_ring_buffer *ring)
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
obj->cache_level = I915_CACHE_LLC;
i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
ret = i915_gem_object_pin(obj, 4096, true); ret = i915_gem_object_pin(obj, 4096, true);
if (ret) if (ret)
...@@ -776,7 +777,8 @@ static int init_status_page(struct intel_ring_buffer *ring) ...@@ -776,7 +777,8 @@ static int init_status_page(struct intel_ring_buffer *ring)
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
obj->cache_level = I915_CACHE_LLC;
i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
ret = i915_gem_object_pin(obj, 4096, true); ret = i915_gem_object_pin(obj, 4096, true);
if (ret != 0) { if (ret != 0) {
......
...@@ -165,7 +165,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring); ...@@ -165,7 +165,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
int __must_check intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n); int __must_check intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n);
static inline int intel_wait_ring_idle(struct intel_ring_buffer *ring) static inline int intel_wait_ring_idle(struct intel_ring_buffer *ring)
{ {
return intel_wait_ring_buffer(ring, ring->space - 8); return intel_wait_ring_buffer(ring, ring->size - 8);
} }
int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n); int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n);
......
...@@ -1236,6 +1236,8 @@ intel_tv_detect_type (struct intel_tv *intel_tv, ...@@ -1236,6 +1236,8 @@ intel_tv_detect_type (struct intel_tv *intel_tv,
struct drm_connector *connector) struct drm_connector *connector)
{ {
struct drm_encoder *encoder = &intel_tv->base.base; struct drm_encoder *encoder = &intel_tv->base.base;
struct drm_crtc *crtc = encoder->crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long irqflags; unsigned long irqflags;
...@@ -1258,6 +1260,10 @@ intel_tv_detect_type (struct intel_tv *intel_tv, ...@@ -1258,6 +1260,10 @@ intel_tv_detect_type (struct intel_tv *intel_tv,
/* Poll for TV detection */ /* Poll for TV detection */
tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK); tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK);
tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
if (intel_crtc->pipe == 1)
tv_ctl |= TV_ENC_PIPEB_SELECT;
else
tv_ctl &= ~TV_ENC_PIPEB_SELECT;
tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK); tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
tv_dac |= (TVDAC_STATE_CHG_EN | tv_dac |= (TVDAC_STATE_CHG_EN |
...@@ -1277,26 +1283,26 @@ intel_tv_detect_type (struct intel_tv *intel_tv, ...@@ -1277,26 +1283,26 @@ intel_tv_detect_type (struct intel_tv *intel_tv,
to_intel_crtc(intel_tv->base.base.crtc)->pipe); to_intel_crtc(intel_tv->base.base.crtc)->pipe);
type = -1; type = -1;
if (wait_for((tv_dac = I915_READ(TV_DAC)) & TVDAC_STATE_CHG, 20) == 0) { tv_dac = I915_READ(TV_DAC);
DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac); DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
/* /*
* A B C * A B C
* 0 1 1 Composite * 0 1 1 Composite
* 1 0 X svideo * 1 0 X svideo
* 0 0 0 Component * 0 0 0 Component
*/ */
if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) { if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
DRM_DEBUG_KMS("Detected Composite TV connection\n"); DRM_DEBUG_KMS("Detected Composite TV connection\n");
type = DRM_MODE_CONNECTOR_Composite; type = DRM_MODE_CONNECTOR_Composite;
} else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) { } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
DRM_DEBUG_KMS("Detected S-Video TV connection\n"); DRM_DEBUG_KMS("Detected S-Video TV connection\n");
type = DRM_MODE_CONNECTOR_SVIDEO; type = DRM_MODE_CONNECTOR_SVIDEO;
} else if ((tv_dac & TVDAC_SENSE_MASK) == 0) { } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
DRM_DEBUG_KMS("Detected Component TV connection\n"); DRM_DEBUG_KMS("Detected Component TV connection\n");
type = DRM_MODE_CONNECTOR_Component; type = DRM_MODE_CONNECTOR_Component;
} else { } else {
DRM_DEBUG_KMS("Unrecognised TV connection\n"); DRM_DEBUG_KMS("Unrecognised TV connection\n");
} type = -1;
} }
I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN); I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
struct acpi_device; struct acpi_device;
#define ACPI_VIDEO_CLASS "video"
#define ACPI_VIDEO_DISPLAY_CRT 1 #define ACPI_VIDEO_DISPLAY_CRT 1
#define ACPI_VIDEO_DISPLAY_TV 2 #define ACPI_VIDEO_DISPLAY_TV 2
#define ACPI_VIDEO_DISPLAY_DVI 3 #define ACPI_VIDEO_DISPLAY_DVI 3
......
...@@ -324,11 +324,16 @@ static inline unsigned int cpufreq_get(unsigned int cpu) ...@@ -324,11 +324,16 @@ static inline unsigned int cpufreq_get(unsigned int cpu)
/* query the last known CPU freq (in kHz). If zero, cpufreq couldn't detect it */ /* query the last known CPU freq (in kHz). If zero, cpufreq couldn't detect it */
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
unsigned int cpufreq_quick_get(unsigned int cpu); unsigned int cpufreq_quick_get(unsigned int cpu);
unsigned int cpufreq_quick_get_max(unsigned int cpu);
#else #else
static inline unsigned int cpufreq_quick_get(unsigned int cpu) static inline unsigned int cpufreq_quick_get(unsigned int cpu)
{ {
return 0; return 0;
} }
static inline unsigned int cpufreq_quick_get_max(unsigned int cpu)
{
return 0;
}
#endif #endif
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册