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. ...
This commit is contained in:
commit
5762a179b6
|
@ -46,7 +46,6 @@
|
|||
|
||||
#define PREFIX "ACPI: "
|
||||
|
||||
#define ACPI_VIDEO_CLASS "video"
|
||||
#define ACPI_VIDEO_BUS_NAME "Video Bus"
|
||||
#define ACPI_VIDEO_DEVICE_NAME "Video Device"
|
||||
#define ACPI_VIDEO_NOTIFY_SWITCH 0x80
|
||||
|
@ -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,
|
||||
* most likely via hotkey. */
|
||||
acpi_bus_generate_proc_event(device, event, 0);
|
||||
keycode = KEY_SWITCHVIDEOMODE;
|
||||
if (!acpi_notifier_call_chain(device, event, 0))
|
||||
keycode = KEY_SWITCHVIDEOMODE;
|
||||
break;
|
||||
|
||||
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)
|
|||
break;
|
||||
}
|
||||
|
||||
acpi_notifier_call_chain(device, event, 0);
|
||||
if (event != ACPI_VIDEO_NOTIFY_SWITCH)
|
||||
acpi_notifier_call_chain(device, event, 0);
|
||||
|
||||
if (keycode) {
|
||||
input_report_key(input, keycode, 1);
|
||||
|
|
|
@ -1199,6 +1199,26 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
|
|||
}
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -560,6 +560,11 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
mode_changed = true;
|
||||
} else if (set->fb == NULL) {
|
||||
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
|
||||
fb_changed = true;
|
||||
}
|
||||
|
|
|
@ -865,7 +865,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
|
|||
MEMSTAT_VID_SHIFT);
|
||||
seq_printf(m, "Current P-state: %d\n",
|
||||
(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 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS);
|
||||
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)
|
|||
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)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
|
@ -1430,6 +1468,7 @@ static struct drm_info_list i915_debugfs_list[] = {
|
|||
{"i915_inttoext_table", i915_inttoext_table, 0},
|
||||
{"i915_drpc_info", i915_drpc_info, 0},
|
||||
{"i915_emon_status", i915_emon_status, 0},
|
||||
{"i915_ring_freq_table", i915_ring_freq_table, 0},
|
||||
{"i915_gfxec", i915_gfxec, 0},
|
||||
{"i915_fbc_status", i915_fbc_status, 0},
|
||||
{"i915_sr_status", i915_sr_status, 0},
|
||||
|
|
|
@ -1073,6 +1073,9 @@ static void i915_setup_compression(struct drm_device *dev, int size)
|
|||
unsigned long cfb_base;
|
||||
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);
|
||||
if (compressed_fb)
|
||||
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)
|
|||
|
||||
dev_priv->cfb_size = size;
|
||||
|
||||
intel_disable_fbc(dev);
|
||||
dev_priv->compressed_fb = compressed_fb;
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start);
|
||||
|
@ -1943,7 +1945,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
if (!dev_priv->mm.gtt) {
|
||||
DRM_ERROR("Failed to initialize GTT\n");
|
||||
ret = -ENODEV;
|
||||
goto out_iomapfree;
|
||||
goto out_rmmap;
|
||||
}
|
||||
|
||||
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)
|
|||
if (dev_priv->wq == NULL) {
|
||||
DRM_ERROR("Failed to create our workqueue.\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_iomapfree;
|
||||
goto out_mtrrfree;
|
||||
}
|
||||
|
||||
/* enable GEM by default */
|
||||
|
@ -2074,13 +2076,21 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
return 0;
|
||||
|
||||
out_gem_unload:
|
||||
if (dev_priv->mm.inactive_shrinker.shrink)
|
||||
unregister_shrinker(&dev_priv->mm.inactive_shrinker);
|
||||
|
||||
if (dev->pdev->msi_enabled)
|
||||
pci_disable_msi(dev->pdev);
|
||||
|
||||
intel_teardown_gmbus(dev);
|
||||
intel_teardown_mchbar(dev);
|
||||
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);
|
||||
out_rmmap:
|
||||
pci_iounmap(dev->pdev, dev_priv->regs);
|
||||
|
|
|
@ -37,38 +37,70 @@
|
|||
#include <linux/console.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_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);
|
||||
|
||||
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_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_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_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_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_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_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_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_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_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;
|
||||
extern int intel_agp_enabled;
|
||||
|
@ -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)
|
||||
{
|
||||
int loop = 500;
|
||||
u32 fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
|
||||
while (fifo < 20 && loop--) {
|
||||
udelay(10);
|
||||
fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
|
||||
if (dev_priv->gt_fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES ) {
|
||||
int loop = 500;
|
||||
u32 fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
|
||||
while (fifo <= GT_FIFO_NUM_RESERVED_ENTRIES && loop--) {
|
||||
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)
|
||||
|
@ -577,6 +614,7 @@ int i915_reset(struct drm_device *dev, u8 flags)
|
|||
if (get_seconds() - dev_priv->last_gpu_reset < 5) {
|
||||
DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
|
||||
} else switch (INTEL_INFO(dev)->gen) {
|
||||
case 7:
|
||||
case 6:
|
||||
ret = gen6_do_reset(dev, flags);
|
||||
/* If reset with a user forcewake, try to restore */
|
||||
|
|
|
@ -214,6 +214,8 @@ struct drm_i915_display_funcs {
|
|||
int (*queue_flip)(struct drm_device *dev, struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
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 */
|
||||
/* cursor updates */
|
||||
/* render clock increase/decrease */
|
||||
|
@ -264,6 +266,7 @@ enum intel_pch {
|
|||
#define QUIRK_PIPEA_FORCE (1<<0)
|
||||
|
||||
struct intel_fbdev;
|
||||
struct intel_fbc_work;
|
||||
|
||||
typedef struct drm_i915_private {
|
||||
struct drm_device *dev;
|
||||
|
@ -274,6 +277,7 @@ typedef struct drm_i915_private {
|
|||
int relative_constants_mode;
|
||||
|
||||
void __iomem *regs;
|
||||
u32 gt_fifo_count;
|
||||
|
||||
struct intel_gmbus {
|
||||
struct i2c_adapter adapter;
|
||||
|
@ -328,11 +332,10 @@ typedef struct drm_i915_private {
|
|||
uint32_t last_instdone1;
|
||||
|
||||
unsigned long cfb_size;
|
||||
unsigned long cfb_pitch;
|
||||
unsigned long cfb_offset;
|
||||
int cfb_fence;
|
||||
int cfb_plane;
|
||||
unsigned int cfb_fb;
|
||||
enum plane cfb_plane;
|
||||
int cfb_y;
|
||||
struct intel_fbc_work *fbc_work;
|
||||
|
||||
struct intel_opregion opregion;
|
||||
|
||||
|
@ -985,15 +988,16 @@ struct drm_i915_file_private {
|
|||
|
||||
extern struct drm_ioctl_desc i915_ioctls[];
|
||||
extern int i915_max_ioctl;
|
||||
extern unsigned int i915_fbpercrtc;
|
||||
extern int i915_panel_ignore_lid;
|
||||
extern unsigned int i915_powersave;
|
||||
extern unsigned int i915_semaphores;
|
||||
extern unsigned int i915_lvds_downclock;
|
||||
extern unsigned int i915_panel_use_ssc;
|
||||
extern int i915_vbt_sdvo_panel_type;
|
||||
extern unsigned int i915_enable_rc6;
|
||||
extern unsigned int i915_enable_fbc;
|
||||
extern unsigned int i915_fbpercrtc __always_unused;
|
||||
extern int i915_panel_ignore_lid __read_mostly;
|
||||
extern unsigned int i915_powersave __read_mostly;
|
||||
extern unsigned int i915_semaphores __read_mostly;
|
||||
extern unsigned int i915_lvds_downclock __read_mostly;
|
||||
extern unsigned int i915_panel_use_ssc __read_mostly;
|
||||
extern int i915_vbt_sdvo_panel_type __read_mostly;
|
||||
extern unsigned int i915_enable_rc6 __read_mostly;
|
||||
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_resume(struct drm_device *dev);
|
||||
|
@ -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,
|
||||
uint32_t read_domains,
|
||||
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);
|
||||
void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
|
||||
void i915_gem_do_init(struct drm_device *dev,
|
||||
|
@ -1182,7 +1186,8 @@ int __must_check
|
|||
i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj,
|
||||
bool write);
|
||||
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);
|
||||
int i915_gem_attach_phys_object(struct drm_device *dev,
|
||||
struct drm_i915_gem_object *obj,
|
||||
|
@ -1196,9 +1201,14 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file);
|
|||
uint32_t
|
||||
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 */
|
||||
void i915_gem_restore_gtt_mappings(struct drm_device *dev);
|
||||
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);
|
||||
|
||||
/* i915_gem_evict.c */
|
||||
|
@ -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_cleanup(struct drm_device *dev);
|
||||
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 void intel_disable_fbc(struct drm_device *dev);
|
||||
extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
|
||||
extern void ironlake_enable_rc6(struct drm_device *dev);
|
||||
extern void gen6_set_rps(struct drm_device *dev, u8 val);
|
||||
|
|
|
@ -1771,8 +1771,11 @@ i915_add_request(struct intel_ring_buffer *ring,
|
|||
ring->outstanding_lazy_request = false;
|
||||
|
||||
if (!dev_priv->mm.suspended) {
|
||||
mod_timer(&dev_priv->hangcheck_timer,
|
||||
jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
|
||||
if (i915_enable_hangcheck) {
|
||||
mod_timer(&dev_priv->hangcheck_timer,
|
||||
jiffies +
|
||||
msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
|
||||
}
|
||||
if (was_empty)
|
||||
queue_delayed_work(dev_priv->wq,
|
||||
&dev_priv->mm.retire_work, HZ);
|
||||
|
@ -2143,6 +2146,30 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj)
|
|||
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.
|
||||
*/
|
||||
|
@ -2159,23 +2186,28 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* blow away mappings if mapped through GTT */
|
||||
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);
|
||||
ret = i915_gem_object_finish_gpu(obj);
|
||||
if (ret == -ERESTARTSYS)
|
||||
return ret;
|
||||
/* 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
|
||||
* 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) {
|
||||
/* In the event of a disaster, abandon all caches and
|
||||
* hope for the best.
|
||||
*/
|
||||
i915_gem_clflush_object(obj);
|
||||
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)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare buffer for display plane. Use uninterruptible for possible flush
|
||||
* wait, as in modesetting process we're not supposed to be interrupted.
|
||||
*/
|
||||
int
|
||||
i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj,
|
||||
struct intel_ring_buffer *pipelined)
|
||||
int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
|
||||
enum i915_cache_level cache_level)
|
||||
{
|
||||
uint32_t old_read_domains;
|
||||
int ret;
|
||||
|
||||
/* Not valid to be called on unbound objects. */
|
||||
if (obj->gtt_space == NULL)
|
||||
return -EINVAL;
|
||||
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 (scanout, cursors, etc).
|
||||
* 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
|
||||
i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
|
||||
u32 alignment,
|
||||
struct intel_ring_buffer *pipelined)
|
||||
{
|
||||
u32 old_read_domains, old_write_domain;
|
||||
int ret;
|
||||
|
||||
ret = i915_gem_object_flush_gpu_write_domain(obj);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
/* Currently, we are always called from an non-interruptible context. */
|
||||
if (pipelined != obj->ring) {
|
||||
ret = i915_gem_object_wait_rendering(obj);
|
||||
if (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);
|
||||
|
||||
old_write_domain = obj->base.write_domain;
|
||||
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;
|
||||
|
||||
trace_i915_gem_object_change_domain(obj,
|
||||
old_read_domains,
|
||||
obj->base.write_domain);
|
||||
old_write_domain);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (!obj->active)
|
||||
if ((obj->base.read_domains & I915_GEM_GPU_DOMAINS) == 0)
|
||||
return 0;
|
||||
|
||||
if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
|
||||
|
@ -3050,6 +3170,9 @@ i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj)
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -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.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->fence_reg = I915_FENCE_REG_NONE;
|
||||
INIT_LIST_HEAD(&obj->mm_list);
|
||||
|
|
|
@ -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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
i915_gem_gtt_rebind_object(obj, obj->cache_level);
|
||||
}
|
||||
|
||||
intel_gtt_chipset_flush();
|
||||
|
@ -110,6 +94,27 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
|
|||
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)
|
||||
{
|
||||
intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT,
|
||||
|
|
|
@ -361,10 +361,12 @@ static void notify_ring(struct drm_device *dev,
|
|||
|
||||
ring->irq_seqno = seqno;
|
||||
wake_up_all(&ring->irq_queue);
|
||||
|
||||
dev_priv->hangcheck_count = 0;
|
||||
mod_timer(&dev_priv->hangcheck_timer,
|
||||
jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
|
||||
if (i915_enable_hangcheck) {
|
||||
dev_priv->hangcheck_count = 0;
|
||||
mod_timer(&dev_priv->hangcheck_timer,
|
||||
jiffies +
|
||||
msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
|
||||
}
|
||||
}
|
||||
|
||||
static void gen6_pm_rps_work(struct work_struct *work)
|
||||
|
@ -1664,6 +1666,9 @@ void i915_hangcheck_elapsed(unsigned long data)
|
|||
uint32_t acthd, instdone, instdone1;
|
||||
bool err = false;
|
||||
|
||||
if (!i915_enable_hangcheck)
|
||||
return;
|
||||
|
||||
/* If all work is done then ACTHD clearly hasn't advanced. */
|
||||
if (i915_hangcheck_ring_idle(&dev_priv->ring[RCS], &err) &&
|
||||
i915_hangcheck_ring_idle(&dev_priv->ring[VCS], &err) &&
|
||||
|
|
|
@ -579,6 +579,7 @@
|
|||
#define DPFC_CTL_PLANEA (0<<30)
|
||||
#define DPFC_CTL_PLANEB (1<<30)
|
||||
#define DPFC_CTL_FENCE_EN (1<<29)
|
||||
#define DPFC_CTL_PERSISTENT_MODE (1<<25)
|
||||
#define DPFC_SR_EN (1<<10)
|
||||
#define DPFC_CTL_LIMIT_1X (0<<6)
|
||||
#define DPFC_CTL_LIMIT_2X (1<<6)
|
||||
|
@ -3360,6 +3361,7 @@
|
|||
#define FORCEWAKE_ACK 0x130090
|
||||
|
||||
#define GT_FIFO_FREE_ENTRIES 0x120008
|
||||
#define GT_FIFO_NUM_RESERVED_ENTRIES 20
|
||||
|
||||
#define GEN6_RPNSWREQ 0xA008
|
||||
#define GEN6_TURBO_DISABLE (1<<31)
|
||||
|
@ -3434,7 +3436,9 @@
|
|||
#define GEN6_PCODE_MAILBOX 0x138124
|
||||
#define GEN6_PCODE_READY (1<<31)
|
||||
#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_FREQ_IA_RATIO_SHIFT 8
|
||||
|
||||
#endif /* _I915_REG_H_ */
|
||||
|
|
|
@ -760,15 +760,13 @@ static void i915_restore_display(struct drm_device *dev)
|
|||
/* FIXME: restore TV & SDVO state */
|
||||
|
||||
/* only restore FBC info on the platform that supports FBC*/
|
||||
intel_disable_fbc(dev);
|
||||
if (I915_HAS_FBC(dev)) {
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
ironlake_disable_fbc(dev);
|
||||
I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
|
||||
} else if (IS_GM45(dev)) {
|
||||
g4x_disable_fbc(dev);
|
||||
I915_WRITE(DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
|
||||
} else {
|
||||
i8xx_disable_fbc(dev);
|
||||
I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE);
|
||||
I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE);
|
||||
I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2);
|
||||
|
@ -878,8 +876,10 @@ int i915_restore_state(struct drm_device *dev)
|
|||
intel_init_emon(dev);
|
||||
}
|
||||
|
||||
if (IS_GEN6(dev))
|
||||
if (IS_GEN6(dev)) {
|
||||
gen6_enable_rps(dev_priv);
|
||||
gen6_update_ring_freq(dev_priv);
|
||||
}
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ get_blocksize(void *p)
|
|||
|
||||
static void
|
||||
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) |
|
||||
dvo_timing->hactive_lo;
|
||||
|
@ -115,20 +115,75 @@ fill_detail_timing_data(struct drm_display_mode *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 */
|
||||
static void
|
||||
parse_lfp_panel_data(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
struct bdb_lvds_options *lvds_options;
|
||||
struct bdb_lvds_lfp_data *lvds_lfp_data;
|
||||
struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
|
||||
struct bdb_lvds_lfp_data_entry *entry;
|
||||
struct lvds_dvo_timing *dvo_timing;
|
||||
const struct bdb_lvds_options *lvds_options;
|
||||
const struct bdb_lvds_lfp_data *lvds_lfp_data;
|
||||
const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
|
||||
const struct lvds_dvo_timing *panel_dvo_timing;
|
||||
struct drm_display_mode *panel_fixed_mode;
|
||||
int lfp_data_size, dvo_timing_offset;
|
||||
int i, temp_downclock;
|
||||
struct drm_display_mode *temp_mode;
|
||||
int i, downclock;
|
||||
|
||||
lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
|
||||
if (!lvds_options)
|
||||
|
@ -150,75 +205,44 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
|
|||
|
||||
dev_priv->lvds_vbt = 1;
|
||||
|
||||
lfp_data_size = lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset -
|
||||
lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset;
|
||||
entry = (struct bdb_lvds_lfp_data_entry *)
|
||||
((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_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
|
||||
lvds_lfp_data_ptrs,
|
||||
lvds_options->panel_type);
|
||||
|
||||
panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
|
||||
if (!panel_fixed_mode)
|
||||
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;
|
||||
|
||||
DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n");
|
||||
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
|
||||
* the LVDS downclock is found.
|
||||
* Iterate over the LVDS panel timing info to find the lowest clock
|
||||
* for the native resolution.
|
||||
*/
|
||||
downclock = panel_dvo_timing->clock;
|
||||
for (i = 0; i < 16; i++) {
|
||||
entry = (struct bdb_lvds_lfp_data_entry *)
|
||||
((uint8_t *)lvds_lfp_data->data + (lfp_data_size * i));
|
||||
dvo_timing = (struct lvds_dvo_timing *)
|
||||
((unsigned char *)entry + dvo_timing_offset);
|
||||
const struct lvds_dvo_timing *dvo_timing;
|
||||
|
||||
fill_detail_timing_data(temp_mode, dvo_timing);
|
||||
|
||||
if (temp_mode->hdisplay == panel_fixed_mode->hdisplay &&
|
||||
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));
|
||||
dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
|
||||
lvds_lfp_data_ptrs,
|
||||
i);
|
||||
if (lvds_dvo_timing_equal_size(dvo_timing, panel_dvo_timing) &&
|
||||
dvo_timing->clock < downclock)
|
||||
downclock = dvo_timing->clock;
|
||||
}
|
||||
kfree(temp_mode);
|
||||
if (temp_downclock < panel_fixed_mode->clock &&
|
||||
i915_lvds_downclock) {
|
||||
|
||||
if (downclock < panel_dvo_timing->clock && i915_lvds_downclock) {
|
||||
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. "
|
||||
"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 */
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
* Eric Anholt <eric@anholt.net>
|
||||
*/
|
||||
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/i2c.h>
|
||||
|
@ -1157,12 +1158,15 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
|
|||
|
||||
reg = TRANSCONF(pipe);
|
||||
val = I915_READ(reg);
|
||||
/*
|
||||
* make the BPC in transcoder be consistent with
|
||||
* that in pipeconf reg.
|
||||
*/
|
||||
val &= ~PIPE_BPC_MASK;
|
||||
val |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK;
|
||||
|
||||
if (HAS_PCH_IBX(dev_priv->dev)) {
|
||||
/*
|
||||
* make the BPC in transcoder be consistent with
|
||||
* that in pipeconf reg.
|
||||
*/
|
||||
val &= ~PIPE_BPC_MASK;
|
||||
val |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK;
|
||||
}
|
||||
I915_WRITE(reg, val | TRANS_ENABLE);
|
||||
if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
|
||||
DRM_ERROR("failed to enable transcoder %d\n", pipe);
|
||||
|
@ -1380,62 +1384,7 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
|
|||
disable_pch_hdmi(dev_priv, pipe, HDMID);
|
||||
}
|
||||
|
||||
static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_framebuffer *fb = crtc->fb;
|
||||
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
|
||||
struct drm_i915_gem_object *obj = intel_fb->obj;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int plane, i;
|
||||
u32 fbc_ctl, fbc_ctl2;
|
||||
|
||||
if (fb->pitch == dev_priv->cfb_pitch &&
|
||||
obj->fence_reg == dev_priv->cfb_fence &&
|
||||
intel_crtc->plane == dev_priv->cfb_plane &&
|
||||
I915_READ(FBC_CONTROL) & FBC_CTL_EN)
|
||||
return;
|
||||
|
||||
i8xx_disable_fbc(dev);
|
||||
|
||||
dev_priv->cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
|
||||
|
||||
if (fb->pitch < dev_priv->cfb_pitch)
|
||||
dev_priv->cfb_pitch = fb->pitch;
|
||||
|
||||
/* FBC_CTL wants 64B units */
|
||||
dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
|
||||
dev_priv->cfb_fence = obj->fence_reg;
|
||||
dev_priv->cfb_plane = intel_crtc->plane;
|
||||
plane = dev_priv->cfb_plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB;
|
||||
|
||||
/* Clear old tags */
|
||||
for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
|
||||
I915_WRITE(FBC_TAG + (i * 4), 0);
|
||||
|
||||
/* Set it up... */
|
||||
fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | plane;
|
||||
if (obj->tiling_mode != I915_TILING_NONE)
|
||||
fbc_ctl2 |= FBC_CTL_CPU_FENCE;
|
||||
I915_WRITE(FBC_CONTROL2, fbc_ctl2);
|
||||
I915_WRITE(FBC_FENCE_OFF, crtc->y);
|
||||
|
||||
/* enable it... */
|
||||
fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC;
|
||||
if (IS_I945GM(dev))
|
||||
fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
|
||||
fbc_ctl |= (dev_priv->cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
|
||||
fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
|
||||
if (obj->tiling_mode != I915_TILING_NONE)
|
||||
fbc_ctl |= dev_priv->cfb_fence;
|
||||
I915_WRITE(FBC_CONTROL, fbc_ctl);
|
||||
|
||||
DRM_DEBUG_KMS("enabled FBC, pitch %ld, yoff %d, plane %d, ",
|
||||
dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
|
||||
}
|
||||
|
||||
void i8xx_disable_fbc(struct drm_device *dev)
|
||||
static void i8xx_disable_fbc(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 fbc_ctl;
|
||||
|
@ -1457,6 +1406,49 @@ void i8xx_disable_fbc(struct drm_device *dev)
|
|||
DRM_DEBUG_KMS("disabled FBC\n");
|
||||
}
|
||||
|
||||
static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_framebuffer *fb = crtc->fb;
|
||||
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
|
||||
struct drm_i915_gem_object *obj = intel_fb->obj;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int cfb_pitch;
|
||||
int plane, i;
|
||||
u32 fbc_ctl, fbc_ctl2;
|
||||
|
||||
cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
|
||||
if (fb->pitch < cfb_pitch)
|
||||
cfb_pitch = fb->pitch;
|
||||
|
||||
/* FBC_CTL wants 64B units */
|
||||
cfb_pitch = (cfb_pitch / 64) - 1;
|
||||
plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB;
|
||||
|
||||
/* Clear old tags */
|
||||
for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
|
||||
I915_WRITE(FBC_TAG + (i * 4), 0);
|
||||
|
||||
/* Set it up... */
|
||||
fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
|
||||
fbc_ctl2 |= plane;
|
||||
I915_WRITE(FBC_CONTROL2, fbc_ctl2);
|
||||
I915_WRITE(FBC_FENCE_OFF, crtc->y);
|
||||
|
||||
/* enable it... */
|
||||
fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC;
|
||||
if (IS_I945GM(dev))
|
||||
fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
|
||||
fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
|
||||
fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
|
||||
fbc_ctl |= obj->fence_reg;
|
||||
I915_WRITE(FBC_CONTROL, fbc_ctl);
|
||||
|
||||
DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %d, ",
|
||||
cfb_pitch, crtc->y, intel_crtc->plane);
|
||||
}
|
||||
|
||||
static bool i8xx_fbc_enabled(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
@ -1476,30 +1468,9 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
|
|||
unsigned long stall_watermark = 200;
|
||||
u32 dpfc_ctl;
|
||||
|
||||
dpfc_ctl = I915_READ(DPFC_CONTROL);
|
||||
if (dpfc_ctl & DPFC_CTL_EN) {
|
||||
if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
|
||||
dev_priv->cfb_fence == obj->fence_reg &&
|
||||
dev_priv->cfb_plane == intel_crtc->plane &&
|
||||
dev_priv->cfb_y == crtc->y)
|
||||
return;
|
||||
|
||||
I915_WRITE(DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
}
|
||||
|
||||
dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
|
||||
dev_priv->cfb_fence = obj->fence_reg;
|
||||
dev_priv->cfb_plane = intel_crtc->plane;
|
||||
dev_priv->cfb_y = crtc->y;
|
||||
|
||||
dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
|
||||
if (obj->tiling_mode != I915_TILING_NONE) {
|
||||
dpfc_ctl |= DPFC_CTL_FENCE_EN | dev_priv->cfb_fence;
|
||||
I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY);
|
||||
} else {
|
||||
I915_WRITE(DPFC_CHICKEN, ~DPFC_HT_MODIFY);
|
||||
}
|
||||
dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
|
||||
I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY);
|
||||
|
||||
I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
|
||||
(stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
|
||||
|
@ -1512,7 +1483,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
|
|||
DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
|
||||
}
|
||||
|
||||
void g4x_disable_fbc(struct drm_device *dev)
|
||||
static void g4x_disable_fbc(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 dpfc_ctl;
|
||||
|
@ -1567,32 +1538,12 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
|
|||
u32 dpfc_ctl;
|
||||
|
||||
dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
|
||||
if (dpfc_ctl & DPFC_CTL_EN) {
|
||||
if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
|
||||
dev_priv->cfb_fence == obj->fence_reg &&
|
||||
dev_priv->cfb_plane == intel_crtc->plane &&
|
||||
dev_priv->cfb_offset == obj->gtt_offset &&
|
||||
dev_priv->cfb_y == crtc->y)
|
||||
return;
|
||||
|
||||
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
}
|
||||
|
||||
dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
|
||||
dev_priv->cfb_fence = obj->fence_reg;
|
||||
dev_priv->cfb_plane = intel_crtc->plane;
|
||||
dev_priv->cfb_offset = obj->gtt_offset;
|
||||
dev_priv->cfb_y = crtc->y;
|
||||
|
||||
dpfc_ctl &= DPFC_RESERVED;
|
||||
dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
|
||||
if (obj->tiling_mode != I915_TILING_NONE) {
|
||||
dpfc_ctl |= (DPFC_CTL_FENCE_EN | dev_priv->cfb_fence);
|
||||
I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
|
||||
} else {
|
||||
I915_WRITE(ILK_DPFC_CHICKEN, ~DPFC_HT_MODIFY);
|
||||
}
|
||||
/* Set persistent mode for front-buffer rendering, ala X. */
|
||||
dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE;
|
||||
dpfc_ctl |= (DPFC_CTL_FENCE_EN | obj->fence_reg);
|
||||
I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
|
||||
|
||||
I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
|
||||
(stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
|
||||
|
@ -1604,7 +1555,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
|
|||
|
||||
if (IS_GEN6(dev)) {
|
||||
I915_WRITE(SNB_DPFC_CTL_SA,
|
||||
SNB_CPU_FENCE_ENABLE | dev_priv->cfb_fence);
|
||||
SNB_CPU_FENCE_ENABLE | obj->fence_reg);
|
||||
I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
|
||||
sandybridge_blit_fbc_update(dev);
|
||||
}
|
||||
|
@ -1612,7 +1563,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
|
|||
DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
|
||||
}
|
||||
|
||||
void ironlake_disable_fbc(struct drm_device *dev)
|
||||
static void ironlake_disable_fbc(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 dpfc_ctl;
|
||||
|
@ -1644,24 +1595,109 @@ bool intel_fbc_enabled(struct drm_device *dev)
|
|||
return dev_priv->display.fbc_enabled(dev);
|
||||
}
|
||||
|
||||
void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
|
||||
static void intel_fbc_work_fn(struct work_struct *__work)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = crtc->dev->dev_private;
|
||||
struct intel_fbc_work *work =
|
||||
container_of(to_delayed_work(__work),
|
||||
struct intel_fbc_work, work);
|
||||
struct drm_device *dev = work->crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (work == dev_priv->fbc_work) {
|
||||
/* Double check that we haven't switched fb without cancelling
|
||||
* the prior work.
|
||||
*/
|
||||
if (work->crtc->fb == work->fb) {
|
||||
dev_priv->display.enable_fbc(work->crtc,
|
||||
work->interval);
|
||||
|
||||
dev_priv->cfb_plane = to_intel_crtc(work->crtc)->plane;
|
||||
dev_priv->cfb_fb = work->crtc->fb->base.id;
|
||||
dev_priv->cfb_y = work->crtc->y;
|
||||
}
|
||||
|
||||
dev_priv->fbc_work = NULL;
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
kfree(work);
|
||||
}
|
||||
|
||||
static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
if (dev_priv->fbc_work == NULL)
|
||||
return;
|
||||
|
||||
DRM_DEBUG_KMS("cancelling pending FBC enable\n");
|
||||
|
||||
/* Synchronisation is provided by struct_mutex and checking of
|
||||
* dev_priv->fbc_work, so we can perform the cancellation
|
||||
* entirely asynchronously.
|
||||
*/
|
||||
if (cancel_delayed_work(&dev_priv->fbc_work->work))
|
||||
/* tasklet was killed before being run, clean up */
|
||||
kfree(dev_priv->fbc_work);
|
||||
|
||||
/* Mark the work as no longer wanted so that if it does
|
||||
* wake-up (because the work was already running and waiting
|
||||
* for our mutex), it will discover that is no longer
|
||||
* necessary to run.
|
||||
*/
|
||||
dev_priv->fbc_work = NULL;
|
||||
}
|
||||
|
||||
static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
|
||||
{
|
||||
struct intel_fbc_work *work;
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (!dev_priv->display.enable_fbc)
|
||||
return;
|
||||
|
||||
dev_priv->display.enable_fbc(crtc, interval);
|
||||
intel_cancel_fbc_work(dev_priv);
|
||||
|
||||
work = kzalloc(sizeof *work, GFP_KERNEL);
|
||||
if (work == NULL) {
|
||||
dev_priv->display.enable_fbc(crtc, interval);
|
||||
return;
|
||||
}
|
||||
|
||||
work->crtc = crtc;
|
||||
work->fb = crtc->fb;
|
||||
work->interval = interval;
|
||||
INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
|
||||
|
||||
dev_priv->fbc_work = work;
|
||||
|
||||
DRM_DEBUG_KMS("scheduling delayed FBC enable\n");
|
||||
|
||||
/* Delay the actual enabling to let pageflipping cease and the
|
||||
* display to settle before starting the compression. Note that
|
||||
* this delay also serves a second purpose: it allows for a
|
||||
* vblank to pass after disabling the FBC before we attempt
|
||||
* to modify the control registers.
|
||||
*
|
||||
* A more complicated solution would involve tracking vblanks
|
||||
* following the termination of the page-flipping sequence
|
||||
* and indeed performing the enable as a co-routine and not
|
||||
* waiting synchronously upon the vblank.
|
||||
*/
|
||||
schedule_delayed_work(&work->work, msecs_to_jiffies(50));
|
||||
}
|
||||
|
||||
void intel_disable_fbc(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
intel_cancel_fbc_work(dev_priv);
|
||||
|
||||
if (!dev_priv->display.disable_fbc)
|
||||
return;
|
||||
|
||||
dev_priv->display.disable_fbc(dev);
|
||||
dev_priv->cfb_plane = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1760,8 +1796,13 @@ static void intel_update_fbc(struct drm_device *dev)
|
|||
dev_priv->no_fbc_reason = FBC_BAD_PLANE;
|
||||
goto out_disable;
|
||||
}
|
||||
if (obj->tiling_mode != I915_TILING_X) {
|
||||
DRM_DEBUG_KMS("framebuffer not tiled, disabling compression\n");
|
||||
|
||||
/* The use of a CPU fence is mandatory in order to detect writes
|
||||
* by the CPU to the scanout and trigger updates to the FBC.
|
||||
*/
|
||||
if (obj->tiling_mode != I915_TILING_X ||
|
||||
obj->fence_reg == I915_FENCE_REG_NONE) {
|
||||
DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
|
||||
dev_priv->no_fbc_reason = FBC_NOT_TILED;
|
||||
goto out_disable;
|
||||
}
|
||||
|
@ -1770,6 +1811,44 @@ static void intel_update_fbc(struct drm_device *dev)
|
|||
if (in_dbg_master())
|
||||
goto out_disable;
|
||||
|
||||
/* If the scanout has not changed, don't modify the FBC settings.
|
||||
* Note that we make the fundamental assumption that the fb->obj
|
||||
* cannot be unpinned (and have its GTT offset and fence revoked)
|
||||
* without first being decoupled from the scanout and FBC disabled.
|
||||
*/
|
||||
if (dev_priv->cfb_plane == intel_crtc->plane &&
|
||||
dev_priv->cfb_fb == fb->base.id &&
|
||||
dev_priv->cfb_y == crtc->y)
|
||||
return;
|
||||
|
||||
if (intel_fbc_enabled(dev)) {
|
||||
/* We update FBC along two paths, after changing fb/crtc
|
||||
* configuration (modeswitching) and after page-flipping
|
||||
* finishes. For the latter, we know that not only did
|
||||
* we disable the FBC at the start of the page-flip
|
||||
* sequence, but also more than one vblank has passed.
|
||||
*
|
||||
* For the former case of modeswitching, it is possible
|
||||
* to switch between two FBC valid configurations
|
||||
* instantaneously so we do need to disable the FBC
|
||||
* before we can modify its control registers. We also
|
||||
* have to wait for the next vblank for that to take
|
||||
* effect. However, since we delay enabling FBC we can
|
||||
* assume that a vblank has passed since disabling and
|
||||
* that we can safely alter the registers in the deferred
|
||||
* callback.
|
||||
*
|
||||
* In the scenario that we go from a valid to invalid
|
||||
* and then back to valid FBC configuration we have
|
||||
* no strict enforcement that a vblank occurred since
|
||||
* disabling the FBC. However, along all current pipe
|
||||
* disabling paths we do need to wait for a vblank at
|
||||
* some point. And we wait before enabling FBC anyway.
|
||||
*/
|
||||
DRM_DEBUG_KMS("disabling active FBC for update\n");
|
||||
intel_disable_fbc(dev);
|
||||
}
|
||||
|
||||
intel_enable_fbc(crtc, 500);
|
||||
return;
|
||||
|
||||
|
@ -1812,14 +1891,10 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev,
|
|||
}
|
||||
|
||||
dev_priv->mm.interruptible = false;
|
||||
ret = i915_gem_object_pin(obj, alignment, true);
|
||||
ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined);
|
||||
if (ret)
|
||||
goto err_interruptible;
|
||||
|
||||
ret = i915_gem_object_set_to_display_plane(obj, pipelined);
|
||||
if (ret)
|
||||
goto err_unpin;
|
||||
|
||||
/* Install a fence for tiled scan-out. Pre-i965 always needs a
|
||||
* fence, whereas 965+ only requires a fence if using
|
||||
* framebuffer compression. For simplicity, we always install
|
||||
|
@ -1841,10 +1916,8 @@ err_interruptible:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Assume fb object is pinned & idle & fenced and just update base pointers */
|
||||
static int
|
||||
intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
||||
int x, int y, enum mode_set_atomic state)
|
||||
static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
||||
int x, int y)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
@ -1887,7 +1960,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
|||
dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Unknown color depth\n");
|
||||
DRM_ERROR("Unknown color depth %d\n", fb->bits_per_pixel);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
|
@ -1897,10 +1970,6 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
|||
dspcntr &= ~DISPPLANE_TILED;
|
||||
}
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
/* must disable */
|
||||
dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
|
||||
|
||||
I915_WRITE(reg, dspcntr);
|
||||
|
||||
Start = obj->gtt_offset;
|
||||
|
@ -1917,6 +1986,99 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
|||
I915_WRITE(DSPADDR(plane), Start + Offset);
|
||||
POSTING_READ(reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ironlake_update_plane(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb, int x, int y)
|
||||
{
|
||||
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 intel_framebuffer *intel_fb;
|
||||
struct drm_i915_gem_object *obj;
|
||||
int plane = intel_crtc->plane;
|
||||
unsigned long Start, Offset;
|
||||
u32 dspcntr;
|
||||
u32 reg;
|
||||
|
||||
switch (plane) {
|
||||
case 0:
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Can't update plane %d in SAREA\n", plane);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
intel_fb = to_intel_framebuffer(fb);
|
||||
obj = intel_fb->obj;
|
||||
|
||||
reg = DSPCNTR(plane);
|
||||
dspcntr = I915_READ(reg);
|
||||
/* Mask out pixel format bits in case we change it */
|
||||
dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
|
||||
switch (fb->bits_per_pixel) {
|
||||
case 8:
|
||||
dspcntr |= DISPPLANE_8BPP;
|
||||
break;
|
||||
case 16:
|
||||
if (fb->depth != 16)
|
||||
return -EINVAL;
|
||||
|
||||
dspcntr |= DISPPLANE_16BPP;
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
if (fb->depth == 24)
|
||||
dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
|
||||
else if (fb->depth == 30)
|
||||
dspcntr |= DISPPLANE_32BPP_30BIT_NO_ALPHA;
|
||||
else
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Unknown color depth %d\n", fb->bits_per_pixel);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (obj->tiling_mode != I915_TILING_NONE)
|
||||
dspcntr |= DISPPLANE_TILED;
|
||||
else
|
||||
dspcntr &= ~DISPPLANE_TILED;
|
||||
|
||||
/* must disable */
|
||||
dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
|
||||
|
||||
I915_WRITE(reg, dspcntr);
|
||||
|
||||
Start = obj->gtt_offset;
|
||||
Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8);
|
||||
|
||||
DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
|
||||
Start, Offset, x, y, fb->pitch);
|
||||
I915_WRITE(DSPSTRIDE(plane), fb->pitch);
|
||||
I915_WRITE(DSPSURF(plane), Start);
|
||||
I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
|
||||
I915_WRITE(DSPADDR(plane), Offset);
|
||||
POSTING_READ(reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assume fb object is pinned & idle & fenced and just update base pointers */
|
||||
static int
|
||||
intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
||||
int x, int y, enum mode_set_atomic state)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
|
||||
ret = dev_priv->display.update_plane(crtc, fb, x, y);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
intel_update_fbc(dev);
|
||||
intel_increase_pllclock(crtc);
|
||||
|
||||
|
@ -1971,7 +2133,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
* This should only fail upon a hung GPU, in which case we
|
||||
* can safely continue.
|
||||
*/
|
||||
ret = i915_gem_object_flush_gpu(obj);
|
||||
ret = i915_gem_object_finish_gpu(obj);
|
||||
(void) ret;
|
||||
}
|
||||
|
||||
|
@ -2622,6 +2784,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
|
|||
/* For PCH DP, enable TRANS_DP_CTL */
|
||||
if (HAS_PCH_CPT(dev) &&
|
||||
intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
|
||||
u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) >> 5;
|
||||
reg = TRANS_DP_CTL(pipe);
|
||||
temp = I915_READ(reg);
|
||||
temp &= ~(TRANS_DP_PORT_SEL_MASK |
|
||||
|
@ -2629,7 +2792,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
|
|||
TRANS_DP_BPC_MASK);
|
||||
temp |= (TRANS_DP_OUTPUT_ENABLE |
|
||||
TRANS_DP_ENH_FRAMING);
|
||||
temp |= TRANS_DP_8BPC;
|
||||
temp |= bpc << 9; /* same format but at 11:9 */
|
||||
|
||||
if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
|
||||
temp |= TRANS_DP_HSYNC_ACTIVE_HIGH;
|
||||
|
@ -2732,9 +2895,8 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
|
|||
|
||||
intel_disable_plane(dev_priv, plane, pipe);
|
||||
|
||||
if (dev_priv->cfb_plane == plane &&
|
||||
dev_priv->display.disable_fbc)
|
||||
dev_priv->display.disable_fbc(dev);
|
||||
if (dev_priv->cfb_plane == plane)
|
||||
intel_disable_fbc(dev);
|
||||
|
||||
intel_disable_pipe(dev_priv, pipe);
|
||||
|
||||
|
@ -2898,9 +3060,8 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
|
|||
intel_crtc_dpms_overlay(intel_crtc, false);
|
||||
intel_crtc_update_cursor(crtc, false);
|
||||
|
||||
if (dev_priv->cfb_plane == plane &&
|
||||
dev_priv->display.disable_fbc)
|
||||
dev_priv->display.disable_fbc(dev);
|
||||
if (dev_priv->cfb_plane == plane)
|
||||
intel_disable_fbc(dev);
|
||||
|
||||
intel_disable_plane(dev_priv, plane, pipe);
|
||||
intel_disable_pipe(dev_priv, pipe);
|
||||
|
@ -4308,6 +4469,133 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
|
|||
return dev_priv->lvds_use_ssc && i915_panel_use_ssc;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_choose_pipe_bpp_dither - figure out what color depth the pipe should send
|
||||
* @crtc: CRTC structure
|
||||
*
|
||||
* A pipe may be connected to one or more outputs. Based on the depth of the
|
||||
* attached framebuffer, choose a good color depth to use on the pipe.
|
||||
*
|
||||
* If possible, match the pipe depth to the fb depth. In some cases, this
|
||||
* isn't ideal, because the connected output supports a lesser or restricted
|
||||
* set of depths. Resolve that here:
|
||||
* LVDS typically supports only 6bpc, so clamp down in that case
|
||||
* HDMI supports only 8bpc or 12bpc, so clamp to 8bpc with dither for 10bpc
|
||||
* Displays may support a restricted set as well, check EDID and clamp as
|
||||
* appropriate.
|
||||
*
|
||||
* RETURNS:
|
||||
* Dithering requirement (i.e. false if display bpc and pipe bpc match,
|
||||
* true if they don't match).
|
||||
*/
|
||||
static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
|
||||
unsigned int *pipe_bpp)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
unsigned int display_bpc = UINT_MAX, bpc;
|
||||
|
||||
/* Walk the encoders & connectors on this crtc, get min bpc */
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
|
||||
|
||||
if (encoder->crtc != crtc)
|
||||
continue;
|
||||
|
||||
if (intel_encoder->type == INTEL_OUTPUT_LVDS) {
|
||||
unsigned int lvds_bpc;
|
||||
|
||||
if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) ==
|
||||
LVDS_A3_POWER_UP)
|
||||
lvds_bpc = 8;
|
||||
else
|
||||
lvds_bpc = 6;
|
||||
|
||||
if (lvds_bpc < display_bpc) {
|
||||
DRM_DEBUG_DRIVER("clamping display bpc (was %d) to LVDS (%d)\n", display_bpc, lvds_bpc);
|
||||
display_bpc = lvds_bpc;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (intel_encoder->type == INTEL_OUTPUT_EDP) {
|
||||
/* Use VBT settings if we have an eDP panel */
|
||||
unsigned int edp_bpc = dev_priv->edp.bpp / 3;
|
||||
|
||||
if (edp_bpc < display_bpc) {
|
||||
DRM_DEBUG_DRIVER("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc);
|
||||
display_bpc = edp_bpc;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Not one of the known troublemakers, check the EDID */
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list,
|
||||
head) {
|
||||
if (connector->encoder != encoder)
|
||||
continue;
|
||||
|
||||
if (connector->display_info.bpc < display_bpc) {
|
||||
DRM_DEBUG_DRIVER("clamping display bpc (was %d) to EDID reported max of %d\n", display_bpc, connector->display_info.bpc);
|
||||
display_bpc = connector->display_info.bpc;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* HDMI is either 12 or 8, so if the display lets 10bpc sneak
|
||||
* through, clamp it down. (Note: >12bpc will be caught below.)
|
||||
*/
|
||||
if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
|
||||
if (display_bpc > 8 && display_bpc < 12) {
|
||||
DRM_DEBUG_DRIVER("forcing bpc to 12 for HDMI\n");
|
||||
display_bpc = 12;
|
||||
} else {
|
||||
DRM_DEBUG_DRIVER("forcing bpc to 8 for HDMI\n");
|
||||
display_bpc = 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We could just drive the pipe at the highest bpc all the time and
|
||||
* enable dithering as needed, but that costs bandwidth. So choose
|
||||
* the minimum value that expresses the full color range of the fb but
|
||||
* also stays within the max display bpc discovered above.
|
||||
*/
|
||||
|
||||
switch (crtc->fb->depth) {
|
||||
case 8:
|
||||
bpc = 8; /* since we go through a colormap */
|
||||
break;
|
||||
case 15:
|
||||
case 16:
|
||||
bpc = 6; /* min is 18bpp */
|
||||
break;
|
||||
case 24:
|
||||
bpc = min((unsigned int)8, display_bpc);
|
||||
break;
|
||||
case 30:
|
||||
bpc = min((unsigned int)10, display_bpc);
|
||||
break;
|
||||
case 48:
|
||||
bpc = min((unsigned int)12, display_bpc);
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG("unsupported depth, assuming 24 bits\n");
|
||||
bpc = min((unsigned int)8, display_bpc);
|
||||
break;
|
||||
}
|
||||
|
||||
DRM_DEBUG_DRIVER("setting pipe bpc to %d (max display bpc %d)\n",
|
||||
bpc, display_bpc);
|
||||
|
||||
*pipe_bpp = bpc * 3;
|
||||
|
||||
return display_bpc != bpc;
|
||||
}
|
||||
|
||||
static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode,
|
||||
|
@ -4720,7 +5008,9 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
|
|||
struct fdi_m_n m_n = {0};
|
||||
u32 temp;
|
||||
u32 lvds_sync = 0;
|
||||
int target_clock, pixel_multiplier, lane, link_bw, bpp, factor;
|
||||
int target_clock, pixel_multiplier, lane, link_bw, factor;
|
||||
unsigned int pipe_bpp;
|
||||
bool dither;
|
||||
|
||||
list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
|
||||
if (encoder->base.crtc != crtc)
|
||||
|
@ -4847,56 +5137,37 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
|
|||
/* determine panel color depth */
|
||||
temp = I915_READ(PIPECONF(pipe));
|
||||
temp &= ~PIPE_BPC_MASK;
|
||||
if (is_lvds) {
|
||||
/* the BPC will be 6 if it is 18-bit LVDS panel */
|
||||
if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
|
||||
temp |= PIPE_8BPC;
|
||||
else
|
||||
temp |= PIPE_6BPC;
|
||||
} else if (has_edp_encoder) {
|
||||
switch (dev_priv->edp.bpp/3) {
|
||||
case 8:
|
||||
temp |= PIPE_8BPC;
|
||||
break;
|
||||
case 10:
|
||||
temp |= PIPE_10BPC;
|
||||
break;
|
||||
case 6:
|
||||
temp |= PIPE_6BPC;
|
||||
break;
|
||||
case 12:
|
||||
temp |= PIPE_12BPC;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp);
|
||||
switch (pipe_bpp) {
|
||||
case 18:
|
||||
temp |= PIPE_6BPC;
|
||||
break;
|
||||
case 24:
|
||||
temp |= PIPE_8BPC;
|
||||
I915_WRITE(PIPECONF(pipe), temp);
|
||||
|
||||
switch (temp & PIPE_BPC_MASK) {
|
||||
case PIPE_8BPC:
|
||||
bpp = 24;
|
||||
break;
|
||||
case PIPE_10BPC:
|
||||
bpp = 30;
|
||||
case 30:
|
||||
temp |= PIPE_10BPC;
|
||||
break;
|
||||
case PIPE_6BPC:
|
||||
bpp = 18;
|
||||
break;
|
||||
case PIPE_12BPC:
|
||||
bpp = 36;
|
||||
case 36:
|
||||
temp |= PIPE_12BPC;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("unknown pipe bpc value\n");
|
||||
bpp = 24;
|
||||
WARN(1, "intel_choose_pipe_bpp returned invalid value\n");
|
||||
temp |= PIPE_8BPC;
|
||||
pipe_bpp = 24;
|
||||
break;
|
||||
}
|
||||
|
||||
intel_crtc->bpp = pipe_bpp;
|
||||
I915_WRITE(PIPECONF(pipe), temp);
|
||||
|
||||
if (!lane) {
|
||||
/*
|
||||
* Account for spread spectrum to avoid
|
||||
* oversubscribing the link. Max center spread
|
||||
* is 2.5%; use 5% for safety's sake.
|
||||
*/
|
||||
u32 bps = target_clock * bpp * 21 / 20;
|
||||
u32 bps = target_clock * intel_crtc->bpp * 21 / 20;
|
||||
lane = bps / (link_bw * 8) + 1;
|
||||
}
|
||||
|
||||
|
@ -4904,7 +5175,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
|
|||
|
||||
if (pixel_multiplier > 1)
|
||||
link_bw *= pixel_multiplier;
|
||||
ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n);
|
||||
ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw,
|
||||
&m_n);
|
||||
|
||||
/* Ironlake: try to setup display ref clock before DPLL
|
||||
* enabling. This is only under driver's control after
|
||||
|
@ -5107,14 +5379,12 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
|
|||
I915_WRITE(PCH_LVDS, temp);
|
||||
}
|
||||
|
||||
/* set the dithering flag and clear for anything other than a panel. */
|
||||
pipeconf &= ~PIPECONF_DITHER_EN;
|
||||
pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
|
||||
if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) {
|
||||
if ((is_lvds && dev_priv->lvds_dither) || dither) {
|
||||
pipeconf |= PIPECONF_DITHER_EN;
|
||||
pipeconf |= PIPECONF_DITHER_TYPE_ST1;
|
||||
}
|
||||
|
||||
if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
|
||||
intel_dp_set_m_n(crtc, mode, adjusted_mode);
|
||||
} else {
|
||||
|
@ -5434,21 +5704,15 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
|||
goto fail_locked;
|
||||
}
|
||||
|
||||
ret = i915_gem_object_pin(obj, PAGE_SIZE, true);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to pin cursor bo\n");
|
||||
goto fail_locked;
|
||||
}
|
||||
|
||||
ret = i915_gem_object_set_to_gtt_domain(obj, 0);
|
||||
ret = i915_gem_object_pin_to_display_plane(obj, 0, NULL);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to move cursor bo into the GTT\n");
|
||||
goto fail_unpin;
|
||||
goto fail_locked;
|
||||
}
|
||||
|
||||
ret = i915_gem_object_put_fence(obj);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to move cursor bo into the GTT\n");
|
||||
DRM_ERROR("failed to release fence for cursor");
|
||||
goto fail_unpin;
|
||||
}
|
||||
|
||||
|
@ -6151,6 +6415,7 @@ static void intel_unpin_work_fn(struct work_struct *__work)
|
|||
drm_gem_object_unreference(&work->pending_flip_obj->base);
|
||||
drm_gem_object_unreference(&work->old_fb_obj->base);
|
||||
|
||||
intel_update_fbc(work->dev);
|
||||
mutex_unlock(&work->dev->struct_mutex);
|
||||
kfree(work);
|
||||
}
|
||||
|
@ -6515,6 +6780,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
|
|||
if (ret)
|
||||
goto cleanup_pending;
|
||||
|
||||
intel_disable_fbc(dev);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
trace_i915_flip_request(intel_crtc->plane, obj);
|
||||
|
@ -6643,6 +6909,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
|
|||
|
||||
intel_crtc_reset(&intel_crtc->base);
|
||||
intel_crtc->active = true; /* force the pipe off on setup_init_config */
|
||||
intel_crtc->bpp = 24; /* default for pre-Ironlake */
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
intel_helper_funcs.prepare = ironlake_crtc_prepare;
|
||||
|
@ -6869,6 +7136,11 @@ int intel_framebuffer_init(struct drm_device *dev,
|
|||
switch (mode_cmd->bpp) {
|
||||
case 8:
|
||||
case 16:
|
||||
/* Only pre-ILK can handle 5:5:5 */
|
||||
if (mode_cmd->depth == 15 && !HAS_PCH_SPLIT(dev))
|
||||
return -EINVAL;
|
||||
break;
|
||||
|
||||
case 24:
|
||||
case 32:
|
||||
break;
|
||||
|
@ -7283,6 +7555,59 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
|
|||
mutex_unlock(&dev_priv->dev->struct_mutex);
|
||||
}
|
||||
|
||||
void gen6_update_ring_freq(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
int min_freq = 15;
|
||||
int gpu_freq, ia_freq, max_ia_freq;
|
||||
int scaling_factor = 180;
|
||||
|
||||
max_ia_freq = cpufreq_quick_get_max(0);
|
||||
/*
|
||||
* Default to measured freq if none found, PCU will ensure we don't go
|
||||
* over
|
||||
*/
|
||||
if (!max_ia_freq)
|
||||
max_ia_freq = tsc_khz;
|
||||
|
||||
/* Convert from kHz to MHz */
|
||||
max_ia_freq /= 1000;
|
||||
|
||||
mutex_lock(&dev_priv->dev->struct_mutex);
|
||||
|
||||
/*
|
||||
* For each potential GPU frequency, load a ring frequency we'd like
|
||||
* to use for memory access. We do this by specifying the IA frequency
|
||||
* the PCU should use as a reference to determine the ring frequency.
|
||||
*/
|
||||
for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay;
|
||||
gpu_freq--) {
|
||||
int diff = dev_priv->max_delay - gpu_freq;
|
||||
|
||||
/*
|
||||
* For GPU frequencies less than 750MHz, just use the lowest
|
||||
* ring freq.
|
||||
*/
|
||||
if (gpu_freq < min_freq)
|
||||
ia_freq = 800;
|
||||
else
|
||||
ia_freq = max_ia_freq - ((diff * scaling_factor) / 2);
|
||||
ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100);
|
||||
|
||||
I915_WRITE(GEN6_PCODE_DATA,
|
||||
(ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) |
|
||||
gpu_freq);
|
||||
I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
|
||||
GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
|
||||
if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) &
|
||||
GEN6_PCODE_READY) == 0, 10)) {
|
||||
DRM_ERROR("pcode write of freq table timed out\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&dev_priv->dev->struct_mutex);
|
||||
}
|
||||
|
||||
static void ironlake_init_clock_gating(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
@ -7639,9 +7964,11 @@ static void intel_init_display(struct drm_device *dev)
|
|||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->display.dpms = ironlake_crtc_dpms;
|
||||
dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
|
||||
dev_priv->display.update_plane = ironlake_update_plane;
|
||||
} else {
|
||||
dev_priv->display.dpms = i9xx_crtc_dpms;
|
||||
dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
|
||||
dev_priv->display.update_plane = i9xx_update_plane;
|
||||
}
|
||||
|
||||
if (I915_HAS_FBC(dev)) {
|
||||
|
@ -7926,8 +8253,10 @@ void intel_modeset_init(struct drm_device *dev)
|
|||
intel_init_emon(dev);
|
||||
}
|
||||
|
||||
if (IS_GEN6(dev))
|
||||
if (IS_GEN6(dev) || IS_GEN7(dev)) {
|
||||
gen6_enable_rps(dev_priv);
|
||||
gen6_update_ring_freq(dev_priv);
|
||||
}
|
||||
|
||||
INIT_WORK(&dev_priv->idle_work, intel_idle_update);
|
||||
setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
|
||||
|
@ -7963,12 +8292,11 @@ void intel_modeset_cleanup(struct drm_device *dev)
|
|||
intel_increase_pllclock(crtc);
|
||||
}
|
||||
|
||||
if (dev_priv->display.disable_fbc)
|
||||
dev_priv->display.disable_fbc(dev);
|
||||
intel_disable_fbc(dev);
|
||||
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
ironlake_disable_drps(dev);
|
||||
if (IS_GEN6(dev))
|
||||
if (IS_GEN6(dev) || IS_GEN7(dev))
|
||||
gen6_disable_rps(dev);
|
||||
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
|
@ -7981,6 +8309,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
|
|||
drm_irq_uninstall(dev);
|
||||
cancel_work_sync(&dev_priv->hotplug_work);
|
||||
|
||||
/* flush any delayed tasks or pending work */
|
||||
flush_scheduled_work();
|
||||
|
||||
/* Shut off idle work before the crtcs get freed. */
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
intel_crtc = to_intel_crtc(crtc);
|
||||
|
|
|
@ -50,7 +50,6 @@ struct intel_dp {
|
|||
bool has_audio;
|
||||
int force_audio;
|
||||
uint32_t color_range;
|
||||
int dpms_mode;
|
||||
uint8_t link_bw;
|
||||
uint8_t lane_count;
|
||||
uint8_t dpcd[4];
|
||||
|
@ -138,8 +137,8 @@ intel_dp_max_lane_count(struct intel_dp *intel_dp)
|
|||
{
|
||||
int max_lane_count = 4;
|
||||
|
||||
if (intel_dp->dpcd[0] >= 0x11) {
|
||||
max_lane_count = intel_dp->dpcd[2] & 0x1f;
|
||||
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) {
|
||||
max_lane_count = intel_dp->dpcd[DP_MAX_LANE_COUNT] & 0x1f;
|
||||
switch (max_lane_count) {
|
||||
case 1: case 2: case 4:
|
||||
break;
|
||||
|
@ -153,7 +152,7 @@ intel_dp_max_lane_count(struct intel_dp *intel_dp)
|
|||
static int
|
||||
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) {
|
||||
case DP_LINK_BW_1_62:
|
||||
|
@ -179,12 +178,14 @@ intel_dp_link_clock(uint8_t link_bw)
|
|||
static int
|
||||
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))
|
||||
return (pixel_clock * dev_priv->edp.bpp + 7) / 8;
|
||||
else
|
||||
return pixel_clock * 3;
|
||||
if (intel_crtc)
|
||||
bpp = intel_crtc->bpp;
|
||||
|
||||
return (pixel_clock * bpp + 7) / 8;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -682,7 +683,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
|||
struct drm_encoder *encoder;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
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;
|
||||
int pipe = intel_crtc->pipe;
|
||||
|
||||
|
@ -701,7 +702,6 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
|||
break;
|
||||
} else if (is_edp(intel_dp)) {
|
||||
lane_count = dev_priv->edp.lanes;
|
||||
bpp = dev_priv->edp.bpp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
* 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);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
|
@ -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
|
||||
*/
|
||||
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->DP |= DP_ENHANCED_FRAMING;
|
||||
}
|
||||
|
@ -942,11 +943,44 @@ static void ironlake_edp_pll_off(struct drm_encoder *encoder)
|
|||
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)
|
||||
{
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
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)) {
|
||||
ironlake_edp_backlight_off(dev);
|
||||
ironlake_edp_panel_off(dev);
|
||||
|
@ -990,6 +1024,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
|
|||
if (mode != DRM_MODE_DPMS_ON) {
|
||||
if (is_edp(intel_dp))
|
||||
ironlake_edp_backlight_off(dev);
|
||||
intel_dp_sink_dpms(intel_dp, mode);
|
||||
intel_dp_link_down(intel_dp);
|
||||
if (is_edp(intel_dp))
|
||||
ironlake_edp_panel_off(dev);
|
||||
|
@ -998,6 +1033,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
|
|||
} else {
|
||||
if (is_edp(intel_dp))
|
||||
ironlake_edp_panel_vdd_on(intel_dp);
|
||||
intel_dp_sink_dpms(intel_dp, mode);
|
||||
if (!(dp_reg & DP_PORT_EN)) {
|
||||
intel_dp_start_link_train(intel_dp);
|
||||
if (is_edp(intel_dp)) {
|
||||
|
@ -1009,7 +1045,31 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
|
|||
if (is_edp(intel_dp))
|
||||
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)
|
|||
static bool
|
||||
intel_dp_get_link_status(struct intel_dp *intel_dp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = intel_dp_aux_native_read(intel_dp,
|
||||
DP_LANE0_1_STATUS,
|
||||
intel_dp->link_status, DP_LINK_STATUS_SIZE);
|
||||
if (ret != DP_LINK_STATUS_SIZE)
|
||||
return false;
|
||||
return true;
|
||||
return intel_dp_aux_native_read_retry(intel_dp,
|
||||
DP_LANE0_1_STATUS,
|
||||
intel_dp->link_status,
|
||||
DP_LINK_STATUS_SIZE);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
|
@ -1515,6 +1571,8 @@ intel_dp_link_down(struct intel_dp *intel_dp)
|
|||
static void
|
||||
intel_dp_check_link_status(struct intel_dp *intel_dp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!intel_dp->base.base.crtc)
|
||||
return;
|
||||
|
||||
|
@ -1523,6 +1581,15 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
|
|||
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)) {
|
||||
intel_dp_start_link_train(intel_dp);
|
||||
intel_dp_complete_link_train(intel_dp);
|
||||
|
@ -1533,6 +1600,7 @@ static enum drm_connector_status
|
|||
ironlake_dp_detect(struct intel_dp *intel_dp)
|
||||
{
|
||||
enum drm_connector_status status;
|
||||
bool ret;
|
||||
|
||||
/* Can't disconnect eDP, but you can close the lid... */
|
||||
if (is_edp(intel_dp)) {
|
||||
|
@ -1543,13 +1611,11 @@ ironlake_dp_detect(struct intel_dp *intel_dp)
|
|||
}
|
||||
|
||||
status = connector_status_disconnected;
|
||||
if (intel_dp_aux_native_read(intel_dp,
|
||||
0x000, intel_dp->dpcd,
|
||||
sizeof (intel_dp->dpcd))
|
||||
== sizeof(intel_dp->dpcd)) {
|
||||
if (intel_dp->dpcd[0] != 0)
|
||||
status = connector_status_connected;
|
||||
}
|
||||
ret = intel_dp_aux_native_read_retry(intel_dp,
|
||||
0x000, intel_dp->dpcd,
|
||||
sizeof (intel_dp->dpcd));
|
||||
if (ret && intel_dp->dpcd[DP_DPCD_REV] != 0)
|
||||
status = connector_status_connected;
|
||||
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]);
|
||||
return status;
|
||||
|
@ -1586,7 +1652,7 @@ g4x_dp_detect(struct intel_dp *intel_dp)
|
|||
if (intel_dp_aux_native_read(intel_dp, 0x000, 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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
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 */
|
||||
|
@ -1859,7 +1924,6 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|||
return;
|
||||
|
||||
intel_dp->output_reg = output_reg;
|
||||
intel_dp->dpms_mode = -1;
|
||||
|
||||
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
|
||||
if (!intel_connector) {
|
||||
|
@ -1954,8 +2018,9 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|||
sizeof(intel_dp->dpcd));
|
||||
ironlake_edp_panel_vdd_off(intel_dp);
|
||||
if (ret == sizeof(intel_dp->dpcd)) {
|
||||
if (intel_dp->dpcd[0] >= 0x11)
|
||||
dev_priv->no_aux_handshake = intel_dp->dpcd[3] &
|
||||
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
|
||||
dev_priv->no_aux_handshake =
|
||||
intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
|
||||
DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
|
||||
} else {
|
||||
/* if this fails, presume the device is a ghost */
|
||||
|
|
|
@ -170,6 +170,7 @@ struct intel_crtc {
|
|||
int16_t cursor_x, cursor_y;
|
||||
int16_t cursor_width, cursor_height;
|
||||
bool cursor_visible;
|
||||
unsigned int bpp;
|
||||
};
|
||||
|
||||
#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
|
||||
|
@ -233,6 +234,13 @@ struct intel_unpin_work {
|
|||
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);
|
||||
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);
|
|||
extern void ironlake_enable_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_update_ring_freq(struct drm_i915_private *dev_priv);
|
||||
extern void gen6_disable_rps(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,
|
|||
u32 sdvox;
|
||||
|
||||
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)
|
||||
sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
|
||||
sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
|
||||
|
||||
if (intel_crtc->bpp > 24)
|
||||
sdvox |= COLOR_FORMAT_12bpc;
|
||||
else
|
||||
sdvox |= COLOR_FORMAT_8bpc;
|
||||
|
||||
/* Required on CPT */
|
||||
if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev))
|
||||
sdvox |= HDMI_MODE_SELECT;
|
||||
|
|
|
@ -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
|
||||
either a docking event, lid switch or display switch request. In
|
||||
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 acpi_bus_event *event = data;
|
||||
int ret = NOTIFY_OK;
|
||||
|
||||
if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (!system_opregion)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
acpi = system_opregion->acpi;
|
||||
|
||||
if (event->type == 0x80 && !(acpi->cevt & 0x1))
|
||||
ret = NOTIFY_BAD;
|
||||
|
||||
acpi->csts = 0;
|
||||
|
||||
return NOTIFY_OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct notifier_block intel_opregion_notifier = {
|
||||
|
|
|
@ -773,14 +773,10 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
|
|||
if (ret != 0)
|
||||
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)
|
||||
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);
|
||||
if (ret)
|
||||
goto out_unpin;
|
||||
|
|
|
@ -236,7 +236,8 @@ init_pipe_control(struct intel_ring_buffer *ring)
|
|||
ret = -ENOMEM;
|
||||
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);
|
||||
if (ret)
|
||||
|
@ -776,7 +777,8 @@ static int init_status_page(struct intel_ring_buffer *ring)
|
|||
ret = -ENOMEM;
|
||||
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);
|
||||
if (ret != 0) {
|
||||
|
|
|
@ -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);
|
||||
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);
|
||||
|
|
|
@ -1236,6 +1236,8 @@ intel_tv_detect_type (struct intel_tv *intel_tv,
|
|||
struct drm_connector *connector)
|
||||
{
|
||||
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_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
|
@ -1258,6 +1260,10 @@ intel_tv_detect_type (struct intel_tv *intel_tv,
|
|||
/* Poll for TV detection */
|
||||
tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK);
|
||||
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_STATE_CHG_EN |
|
||||
|
@ -1277,26 +1283,26 @@ intel_tv_detect_type (struct intel_tv *intel_tv,
|
|||
to_intel_crtc(intel_tv->base.base.crtc)->pipe);
|
||||
|
||||
type = -1;
|
||||
if (wait_for((tv_dac = I915_READ(TV_DAC)) & TVDAC_STATE_CHG, 20) == 0) {
|
||||
DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
|
||||
/*
|
||||
* A B C
|
||||
* 0 1 1 Composite
|
||||
* 1 0 X svideo
|
||||
* 0 0 0 Component
|
||||
*/
|
||||
if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
|
||||
DRM_DEBUG_KMS("Detected Composite TV connection\n");
|
||||
type = DRM_MODE_CONNECTOR_Composite;
|
||||
} else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
|
||||
DRM_DEBUG_KMS("Detected S-Video TV connection\n");
|
||||
type = DRM_MODE_CONNECTOR_SVIDEO;
|
||||
} else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
|
||||
DRM_DEBUG_KMS("Detected Component TV connection\n");
|
||||
type = DRM_MODE_CONNECTOR_Component;
|
||||
} else {
|
||||
DRM_DEBUG_KMS("Unrecognised TV connection\n");
|
||||
}
|
||||
tv_dac = I915_READ(TV_DAC);
|
||||
DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
|
||||
/*
|
||||
* A B C
|
||||
* 0 1 1 Composite
|
||||
* 1 0 X svideo
|
||||
* 0 0 0 Component
|
||||
*/
|
||||
if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
|
||||
DRM_DEBUG_KMS("Detected Composite TV connection\n");
|
||||
type = DRM_MODE_CONNECTOR_Composite;
|
||||
} else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
|
||||
DRM_DEBUG_KMS("Detected S-Video TV connection\n");
|
||||
type = DRM_MODE_CONNECTOR_SVIDEO;
|
||||
} else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
|
||||
DRM_DEBUG_KMS("Detected Component TV connection\n");
|
||||
type = DRM_MODE_CONNECTOR_Component;
|
||||
} else {
|
||||
DRM_DEBUG_KMS("Unrecognised TV connection\n");
|
||||
type = -1;
|
||||
}
|
||||
|
||||
I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
struct acpi_device;
|
||||
|
||||
#define ACPI_VIDEO_CLASS "video"
|
||||
|
||||
#define ACPI_VIDEO_DISPLAY_CRT 1
|
||||
#define ACPI_VIDEO_DISPLAY_TV 2
|
||||
#define ACPI_VIDEO_DISPLAY_DVI 3
|
||||
|
|
|
@ -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 */
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
unsigned int cpufreq_quick_get(unsigned int cpu);
|
||||
unsigned int cpufreq_quick_get_max(unsigned int cpu);
|
||||
#else
|
||||
static inline unsigned int cpufreq_quick_get(unsigned int cpu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline unsigned int cpufreq_quick_get_max(unsigned int cpu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue