提交 4238a417 编写于 作者: L Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel: (58 commits)
  drm/i915,intel_agp: Add support for Sandybridge D0
  drm/i915: fix render pipe control notify on sandybridge
  agp/intel: set 40-bit dma mask on Sandybridge
  drm/i915: Remove the conflicting BUG_ON()
  drm/i915/suspend: s/IS_IRONLAKE/HAS_PCH_SPLIT/
  drm/i915/suspend: Flush register writes before busy-waiting.
  i915: disable DAC on Ironlake also when doing CRT load detection.
  drm/i915: wait for actual vblank, not just 20ms
  drm/i915: make sure eDP PLL is enabled at the right time
  drm/i915: fix VGA plane disable for Ironlake+
  drm/i915: eDP mode set sequence corrections
  drm/i915: add panel reset workaround
  drm/i915: Enable RC6 on Ironlake.
  drm/i915/sdvo: Only set is_lvds if we have a valid fixed mode.
  drm/i915: Set up a render context on Ironlake
  drm/i915 invalidate indirect state pointers at end of ring exec
  drm/i915: Wake-up wait_request() from elapsed hang-check (v2)
  drm/i915: Apply i830 errata for cursor alignment
  drm/i915: Only update i845/i865 CURBASE when disabled (v2)
  drm/i915: FBC is updated within set_base() so remove second call in mode_set()
  ...
...@@ -819,13 +819,16 @@ static const struct intel_driver_description { ...@@ -819,13 +819,16 @@ static const struct intel_driver_description {
"Sandybridge", NULL, &intel_gen6_driver }, "Sandybridge", NULL, &intel_gen6_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG,
"Sandybridge", NULL, &intel_gen6_driver }, "Sandybridge", NULL, &intel_gen6_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_D0_IG,
"Sandybridge", NULL, &intel_gen6_driver },
{ 0, 0, NULL, NULL, NULL } { 0, 0, NULL, NULL, NULL }
}; };
static int __devinit intel_gmch_probe(struct pci_dev *pdev, static int __devinit intel_gmch_probe(struct pci_dev *pdev,
struct agp_bridge_data *bridge) struct agp_bridge_data *bridge)
{ {
int i; int i, mask;
bridge->driver = NULL; bridge->driver = NULL;
for (i = 0; intel_agp_chipsets[i].name != NULL; i++) { for (i = 0; intel_agp_chipsets[i].name != NULL; i++) {
...@@ -845,14 +848,19 @@ static int __devinit intel_gmch_probe(struct pci_dev *pdev, ...@@ -845,14 +848,19 @@ static int __devinit intel_gmch_probe(struct pci_dev *pdev,
dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name); dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
if (bridge->driver->mask_memory == intel_i965_mask_memory) { if (bridge->driver->mask_memory == intel_gen6_mask_memory)
if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36))) mask = 40;
dev_err(&intel_private.pcidev->dev, else if (bridge->driver->mask_memory == intel_i965_mask_memory)
"set gfx device dma mask 36bit failed!\n"); mask = 36;
else else
pci_set_consistent_dma_mask(intel_private.pcidev, mask = 32;
DMA_BIT_MASK(36));
} if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)))
dev_err(&intel_private.pcidev->dev,
"set gfx device dma mask %d-bit failed!\n", mask);
else
pci_set_consistent_dma_mask(intel_private.pcidev,
DMA_BIT_MASK(mask));
return 1; return 1;
} }
......
...@@ -204,6 +204,7 @@ ...@@ -204,6 +204,7 @@
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG 0x0102 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG 0x0102
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB 0x0104 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB 0x0104
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG 0x0106 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG 0x0106
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_D0_IG 0x0126
/* cover 915 and 945 variants */ /* cover 915 and 945 variants */
#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \ #define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
......
...@@ -8,6 +8,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ ...@@ -8,6 +8,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
i915_suspend.o \ i915_suspend.o \
i915_gem.o \ i915_gem.o \
i915_gem_debug.o \ i915_gem_debug.o \
i915_gem_evict.o \
i915_gem_tiling.o \ i915_gem_tiling.o \
i915_trace_points.o \ i915_trace_points.o \
intel_display.o \ intel_display.o \
...@@ -18,6 +19,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ ...@@ -18,6 +19,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
intel_hdmi.o \ intel_hdmi.o \
intel_sdvo.o \ intel_sdvo.o \
intel_modes.o \ intel_modes.o \
intel_panel.o \
intel_i2c.o \ intel_i2c.o \
intel_fb.o \ intel_fb.o \
intel_tv.o \ intel_tv.o \
......
...@@ -30,20 +30,17 @@ ...@@ -30,20 +30,17 @@
#include "intel_drv.h" #include "intel_drv.h"
struct intel_dvo_device { struct intel_dvo_device {
char *name; const char *name;
int type; int type;
/* DVOA/B/C output register */ /* DVOA/B/C output register */
u32 dvo_reg; u32 dvo_reg;
/* GPIO register used for i2c bus to control this device */ /* GPIO register used for i2c bus to control this device */
u32 gpio; u32 gpio;
int slave_addr; int slave_addr;
struct i2c_adapter *i2c_bus;
const struct intel_dvo_dev_ops *dev_ops; const struct intel_dvo_dev_ops *dev_ops;
void *dev_priv; void *dev_priv;
struct i2c_adapter *i2c_bus;
struct drm_display_mode *panel_fixed_mode;
bool panel_wants_dither;
}; };
struct intel_dvo_dev_ops { struct intel_dvo_dev_ops {
......
...@@ -467,6 +467,9 @@ static int i915_error_state(struct seq_file *m, void *unused) ...@@ -467,6 +467,9 @@ static int i915_error_state(struct seq_file *m, void *unused)
} }
} }
if (error->overlay)
intel_overlay_print_error_state(m, error->overlay);
out: out:
spin_unlock_irqrestore(&dev_priv->error_lock, flags); spin_unlock_irqrestore(&dev_priv->error_lock, flags);
......
...@@ -499,6 +499,13 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, ...@@ -499,6 +499,13 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
} }
} }
if (IS_G4X(dev) || IS_IRONLAKE(dev)) {
BEGIN_LP_RING(2);
OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP);
OUT_RING(MI_NOOP);
ADVANCE_LP_RING();
}
i915_emit_breadcrumb(dev); i915_emit_breadcrumb(dev);
return 0; return 0;
......
...@@ -181,6 +181,7 @@ static const struct pci_device_id pciidlist[] = { /* aka */ ...@@ -181,6 +181,7 @@ static const struct pci_device_id pciidlist[] = { /* aka */
INTEL_VGA_DEVICE(0x0046, &intel_ironlake_m_info), INTEL_VGA_DEVICE(0x0046, &intel_ironlake_m_info),
INTEL_VGA_DEVICE(0x0102, &intel_sandybridge_d_info), INTEL_VGA_DEVICE(0x0102, &intel_sandybridge_d_info),
INTEL_VGA_DEVICE(0x0106, &intel_sandybridge_m_info), INTEL_VGA_DEVICE(0x0106, &intel_sandybridge_m_info),
INTEL_VGA_DEVICE(0x0126, &intel_sandybridge_m_info),
{0, 0, 0} {0, 0, 0}
}; };
......
...@@ -113,6 +113,9 @@ struct intel_opregion { ...@@ -113,6 +113,9 @@ struct intel_opregion {
int enabled; int enabled;
}; };
struct intel_overlay;
struct intel_overlay_error_state;
struct drm_i915_master_private { struct drm_i915_master_private {
drm_local_map_t *sarea; drm_local_map_t *sarea;
struct _drm_i915_sarea *sarea_priv; struct _drm_i915_sarea *sarea_priv;
...@@ -166,6 +169,7 @@ struct drm_i915_error_state { ...@@ -166,6 +169,7 @@ struct drm_i915_error_state {
u32 purgeable:1; u32 purgeable:1;
} *active_bo; } *active_bo;
u32 active_bo_count; u32 active_bo_count;
struct intel_overlay_error_state *overlay;
}; };
struct drm_i915_display_funcs { struct drm_i915_display_funcs {
...@@ -186,8 +190,6 @@ struct drm_i915_display_funcs { ...@@ -186,8 +190,6 @@ struct drm_i915_display_funcs {
/* clock gating init */ /* clock gating init */
}; };
struct intel_overlay;
struct intel_device_info { struct intel_device_info {
u8 is_mobile : 1; u8 is_mobile : 1;
u8 is_i8xx : 1; u8 is_i8xx : 1;
...@@ -242,6 +244,7 @@ typedef struct drm_i915_private { ...@@ -242,6 +244,7 @@ typedef struct drm_i915_private {
struct pci_dev *bridge_dev; struct pci_dev *bridge_dev;
struct intel_ring_buffer render_ring; struct intel_ring_buffer render_ring;
struct intel_ring_buffer bsd_ring; struct intel_ring_buffer bsd_ring;
uint32_t next_seqno;
drm_dma_handle_t *status_page_dmah; drm_dma_handle_t *status_page_dmah;
void *seqno_page; void *seqno_page;
...@@ -251,6 +254,7 @@ typedef struct drm_i915_private { ...@@ -251,6 +254,7 @@ typedef struct drm_i915_private {
drm_local_map_t hws_map; drm_local_map_t hws_map;
struct drm_gem_object *seqno_obj; struct drm_gem_object *seqno_obj;
struct drm_gem_object *pwrctx; struct drm_gem_object *pwrctx;
struct drm_gem_object *renderctx;
struct resource mch_res; struct resource mch_res;
...@@ -285,6 +289,9 @@ typedef struct drm_i915_private { ...@@ -285,6 +289,9 @@ typedef struct drm_i915_private {
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
int vblank_pipe; int vblank_pipe;
int num_pipe; int num_pipe;
u32 flush_rings;
#define FLUSH_RENDER_RING 0x1
#define FLUSH_BSD_RING 0x2
/* For hangcheck timer */ /* For hangcheck timer */
#define DRM_I915_HANGCHECK_PERIOD 75 /* in jiffies */ #define DRM_I915_HANGCHECK_PERIOD 75 /* in jiffies */
...@@ -568,8 +575,6 @@ typedef struct drm_i915_private { ...@@ -568,8 +575,6 @@ typedef struct drm_i915_private {
*/ */
struct delayed_work retire_work; struct delayed_work retire_work;
uint32_t next_gem_seqno;
/** /**
* Waiting sequence number, if any * Waiting sequence number, if any
*/ */
...@@ -610,6 +615,8 @@ typedef struct drm_i915_private { ...@@ -610,6 +615,8 @@ typedef struct drm_i915_private {
struct sdvo_device_mapping sdvo_mappings[2]; struct sdvo_device_mapping sdvo_mappings[2];
/* indicate whether the LVDS_BORDER should be enabled or not */ /* indicate whether the LVDS_BORDER should be enabled or not */
unsigned int lvds_border_bits; unsigned int lvds_border_bits;
/* Panel fitter placement and size for Ironlake+ */
u32 pch_pf_pos, pch_pf_size;
struct drm_crtc *plane_to_crtc_mapping[2]; struct drm_crtc *plane_to_crtc_mapping[2];
struct drm_crtc *pipe_to_crtc_mapping[2]; struct drm_crtc *pipe_to_crtc_mapping[2];
...@@ -669,6 +676,8 @@ struct drm_i915_gem_object { ...@@ -669,6 +676,8 @@ struct drm_i915_gem_object {
struct list_head list; struct list_head list;
/** This object's place on GPU write list */ /** This object's place on GPU write list */
struct list_head gpu_write_list; struct list_head gpu_write_list;
/** This object's place on eviction list */
struct list_head evict_list;
/** /**
* This is set if the object is on the active or flushing lists * This is set if the object is on the active or flushing lists
...@@ -978,6 +987,7 @@ int i915_gem_init_ringbuffer(struct drm_device *dev); ...@@ -978,6 +987,7 @@ int i915_gem_init_ringbuffer(struct drm_device *dev);
void i915_gem_cleanup_ringbuffer(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
int i915_gem_do_init(struct drm_device *dev, unsigned long start, int i915_gem_do_init(struct drm_device *dev, unsigned long start,
unsigned long end); unsigned long end);
int i915_gpu_idle(struct drm_device *dev);
int i915_gem_idle(struct drm_device *dev); int i915_gem_idle(struct drm_device *dev);
uint32_t i915_add_request(struct drm_device *dev, uint32_t i915_add_request(struct drm_device *dev,
struct drm_file *file_priv, struct drm_file *file_priv,
...@@ -991,7 +1001,9 @@ int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, ...@@ -991,7 +1001,9 @@ int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
int write); int write);
int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj); int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj);
int i915_gem_attach_phys_object(struct drm_device *dev, int i915_gem_attach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj, int id); struct drm_gem_object *obj,
int id,
int align);
void i915_gem_detach_phys_object(struct drm_device *dev, void i915_gem_detach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj); struct drm_gem_object *obj);
void i915_gem_free_all_phys_object(struct drm_device *dev); void i915_gem_free_all_phys_object(struct drm_device *dev);
...@@ -1003,6 +1015,11 @@ int i915_gem_object_flush_write_domain(struct drm_gem_object *obj); ...@@ -1003,6 +1015,11 @@ int i915_gem_object_flush_write_domain(struct drm_gem_object *obj);
void i915_gem_shrinker_init(void); void i915_gem_shrinker_init(void);
void i915_gem_shrinker_exit(void); void i915_gem_shrinker_exit(void);
/* i915_gem_evict.c */
int i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment);
int i915_gem_evict_everything(struct drm_device *dev);
int i915_gem_evict_inactive(struct drm_device *dev);
/* i915_gem_tiling.c */ /* i915_gem_tiling.c */
void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
void i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj); void i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj);
...@@ -1066,6 +1083,10 @@ extern bool ironlake_set_drps(struct drm_device *dev, u8 val); ...@@ -1066,6 +1083,10 @@ extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
extern void intel_detect_pch (struct drm_device *dev); extern void intel_detect_pch (struct drm_device *dev);
extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
/* overlay */
extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error);
/** /**
* Lock test for when it's just for synchronization of ring access. * Lock test for when it's just for synchronization of ring access.
* *
...@@ -1092,26 +1113,26 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); ...@@ -1092,26 +1113,26 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
#define I915_VERBOSE 0 #define I915_VERBOSE 0
#define BEGIN_LP_RING(n) do { \ #define BEGIN_LP_RING(n) do { \
drm_i915_private_t *dev_priv = dev->dev_private; \ drm_i915_private_t *dev_priv__ = dev->dev_private; \
if (I915_VERBOSE) \ if (I915_VERBOSE) \
DRM_DEBUG(" BEGIN_LP_RING %x\n", (int)(n)); \ DRM_DEBUG(" BEGIN_LP_RING %x\n", (int)(n)); \
intel_ring_begin(dev, &dev_priv->render_ring, (n)); \ intel_ring_begin(dev, &dev_priv__->render_ring, (n)); \
} while (0) } while (0)
#define OUT_RING(x) do { \ #define OUT_RING(x) do { \
drm_i915_private_t *dev_priv = dev->dev_private; \ drm_i915_private_t *dev_priv__ = dev->dev_private; \
if (I915_VERBOSE) \ if (I915_VERBOSE) \
DRM_DEBUG(" OUT_RING %x\n", (int)(x)); \ DRM_DEBUG(" OUT_RING %x\n", (int)(x)); \
intel_ring_emit(dev, &dev_priv->render_ring, x); \ intel_ring_emit(dev, &dev_priv__->render_ring, x); \
} while (0) } while (0)
#define ADVANCE_LP_RING() do { \ #define ADVANCE_LP_RING() do { \
drm_i915_private_t *dev_priv = dev->dev_private; \ drm_i915_private_t *dev_priv__ = dev->dev_private; \
if (I915_VERBOSE) \ if (I915_VERBOSE) \
DRM_DEBUG("ADVANCE_LP_RING %x\n", \ DRM_DEBUG("ADVANCE_LP_RING %x\n", \
dev_priv->render_ring.tail); \ dev_priv__->render_ring.tail); \
intel_ring_advance(dev, &dev_priv->render_ring); \ intel_ring_advance(dev, &dev_priv__->render_ring); \
} while(0) } while(0)
/** /**
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/pci.h> #include <linux/pci.h>
static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj);
static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj);
static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj);
static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj);
...@@ -48,8 +49,6 @@ static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); ...@@ -48,8 +49,6 @@ static int i915_gem_object_wait_rendering(struct drm_gem_object *obj);
static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
unsigned alignment); unsigned alignment);
static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
static int i915_gem_evict_something(struct drm_device *dev, int min_size);
static int i915_gem_evict_from_inactive_list(struct drm_device *dev);
static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
struct drm_i915_gem_pwrite *args, struct drm_i915_gem_pwrite *args,
struct drm_file *file_priv); struct drm_file *file_priv);
...@@ -58,6 +57,14 @@ static void i915_gem_free_object_tail(struct drm_gem_object *obj); ...@@ -58,6 +57,14 @@ static void i915_gem_free_object_tail(struct drm_gem_object *obj);
static LIST_HEAD(shrink_list); static LIST_HEAD(shrink_list);
static DEFINE_SPINLOCK(shrink_list_lock); static DEFINE_SPINLOCK(shrink_list_lock);
static inline bool
i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv)
{
return obj_priv->gtt_space &&
!obj_priv->active &&
obj_priv->pin_count == 0;
}
int i915_gem_do_init(struct drm_device *dev, unsigned long start, int i915_gem_do_init(struct drm_device *dev, unsigned long start,
unsigned long end) unsigned long end)
{ {
...@@ -313,7 +320,8 @@ i915_gem_object_get_pages_or_evict(struct drm_gem_object *obj) ...@@ -313,7 +320,8 @@ i915_gem_object_get_pages_or_evict(struct drm_gem_object *obj)
if (ret == -ENOMEM) { if (ret == -ENOMEM) {
struct drm_device *dev = obj->dev; struct drm_device *dev = obj->dev;
ret = i915_gem_evict_something(dev, obj->size); ret = i915_gem_evict_something(dev, obj->size,
i915_gem_get_gtt_alignment(obj));
if (ret) if (ret)
return ret; return ret;
...@@ -1036,6 +1044,11 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, ...@@ -1036,6 +1044,11 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0); ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0);
} }
/* Maintain LRU order of "inactive" objects */
if (ret == 0 && i915_gem_object_is_inactive(obj_priv))
list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
drm_gem_object_unreference(obj); drm_gem_object_unreference(obj);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return ret; return ret;
...@@ -1137,7 +1150,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -1137,7 +1150,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{ {
struct drm_gem_object *obj = vma->vm_private_data; struct drm_gem_object *obj = vma->vm_private_data;
struct drm_device *dev = obj->dev; struct drm_device *dev = obj->dev;
struct drm_i915_private *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
pgoff_t page_offset; pgoff_t page_offset;
unsigned long pfn; unsigned long pfn;
...@@ -1155,8 +1168,6 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -1155,8 +1168,6 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
if (ret) if (ret)
goto unlock; goto unlock;
list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
ret = i915_gem_object_set_to_gtt_domain(obj, write); ret = i915_gem_object_set_to_gtt_domain(obj, write);
if (ret) if (ret)
goto unlock; goto unlock;
...@@ -1169,6 +1180,9 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -1169,6 +1180,9 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
goto unlock; goto unlock;
} }
if (i915_gem_object_is_inactive(obj_priv))
list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) + pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) +
page_offset; page_offset;
...@@ -1363,7 +1377,6 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, ...@@ -1363,7 +1377,6 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_i915_gem_mmap_gtt *args = data; struct drm_i915_gem_mmap_gtt *args = data;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_gem_object *obj; struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv; struct drm_i915_gem_object *obj_priv;
int ret; int ret;
...@@ -1409,7 +1422,6 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, ...@@ -1409,7 +1422,6 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return ret; return ret;
} }
list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
} }
drm_gem_object_unreference(obj); drm_gem_object_unreference(obj);
...@@ -1493,9 +1505,16 @@ i915_gem_object_truncate(struct drm_gem_object *obj) ...@@ -1493,9 +1505,16 @@ i915_gem_object_truncate(struct drm_gem_object *obj)
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
struct inode *inode; struct inode *inode;
/* Our goal here is to return as much of the memory as
* is possible back to the system as we are called from OOM.
* To do this we must instruct the shmfs to drop all of its
* backing pages, *now*. Here we mirror the actions taken
* when by shmem_delete_inode() to release the backing store.
*/
inode = obj->filp->f_path.dentry->d_inode; inode = obj->filp->f_path.dentry->d_inode;
if (inode->i_op->truncate) truncate_inode_pages(inode->i_mapping, 0);
inode->i_op->truncate (inode); if (inode->i_op->truncate_range)
inode->i_op->truncate_range(inode, 0, (loff_t)-1);
obj_priv->madv = __I915_MADV_PURGED; obj_priv->madv = __I915_MADV_PURGED;
} }
...@@ -1887,19 +1906,6 @@ i915_gem_flush(struct drm_device *dev, ...@@ -1887,19 +1906,6 @@ i915_gem_flush(struct drm_device *dev,
flush_domains); flush_domains);
} }
static void
i915_gem_flush_ring(struct drm_device *dev,
uint32_t invalidate_domains,
uint32_t flush_domains,
struct intel_ring_buffer *ring)
{
if (flush_domains & I915_GEM_DOMAIN_CPU)
drm_agp_chipset_flush(dev);
ring->flush(dev, ring,
invalidate_domains,
flush_domains);
}
/** /**
* Ensures that all rendering to the object has completed and the object is * Ensures that all rendering to the object has completed and the object is
* safe to unbind from the GTT or access from the CPU. * safe to unbind from the GTT or access from the CPU.
...@@ -1973,8 +1979,6 @@ i915_gem_object_unbind(struct drm_gem_object *obj) ...@@ -1973,8 +1979,6 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
* cause memory corruption through use-after-free. * cause memory corruption through use-after-free.
*/ */
BUG_ON(obj_priv->active);
/* release the fence reg _after_ flushing */ /* release the fence reg _after_ flushing */
if (obj_priv->fence_reg != I915_FENCE_REG_NONE) if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
i915_gem_clear_fence_reg(obj); i915_gem_clear_fence_reg(obj);
...@@ -2010,34 +2014,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) ...@@ -2010,34 +2014,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
return ret; return ret;
} }
static struct drm_gem_object * int
i915_gem_find_inactive_object(struct drm_device *dev, int min_size)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv;
struct drm_gem_object *best = NULL;
struct drm_gem_object *first = NULL;
/* Try to find the smallest clean object */
list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
struct drm_gem_object *obj = &obj_priv->base;
if (obj->size >= min_size) {
if ((!obj_priv->dirty ||
i915_gem_object_is_purgeable(obj_priv)) &&
(!best || obj->size < best->size)) {
best = obj;
if (best->size == min_size)
return best;
}
if (!first)
first = obj;
}
}
return best ? best : first;
}
static int
i915_gpu_idle(struct drm_device *dev) i915_gpu_idle(struct drm_device *dev)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
...@@ -2078,155 +2055,6 @@ i915_gpu_idle(struct drm_device *dev) ...@@ -2078,155 +2055,6 @@ i915_gpu_idle(struct drm_device *dev)
return ret; return ret;
} }
static int
i915_gem_evict_everything(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
bool lists_empty;
spin_lock(&dev_priv->mm.active_list_lock);
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
list_empty(&dev_priv->mm.flushing_list) &&
list_empty(&dev_priv->render_ring.active_list) &&
(!HAS_BSD(dev)
|| list_empty(&dev_priv->bsd_ring.active_list)));
spin_unlock(&dev_priv->mm.active_list_lock);
if (lists_empty)
return -ENOSPC;
/* Flush everything (on to the inactive lists) and evict */
ret = i915_gpu_idle(dev);
if (ret)
return ret;
BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
ret = i915_gem_evict_from_inactive_list(dev);
if (ret)
return ret;
spin_lock(&dev_priv->mm.active_list_lock);
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
list_empty(&dev_priv->mm.flushing_list) &&
list_empty(&dev_priv->render_ring.active_list) &&
(!HAS_BSD(dev)
|| list_empty(&dev_priv->bsd_ring.active_list)));
spin_unlock(&dev_priv->mm.active_list_lock);
BUG_ON(!lists_empty);
return 0;
}
static int
i915_gem_evict_something(struct drm_device *dev, int min_size)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_gem_object *obj;
int ret;
struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring;
for (;;) {
i915_gem_retire_requests(dev);
/* If there's an inactive buffer available now, grab it
* and be done.
*/
obj = i915_gem_find_inactive_object(dev, min_size);
if (obj) {
struct drm_i915_gem_object *obj_priv;
#if WATCH_LRU
DRM_INFO("%s: evicting %p\n", __func__, obj);
#endif
obj_priv = to_intel_bo(obj);
BUG_ON(obj_priv->pin_count != 0);
BUG_ON(obj_priv->active);
/* Wait on the rendering and unbind the buffer. */
return i915_gem_object_unbind(obj);
}
/* If we didn't get anything, but the ring is still processing
* things, wait for the next to finish and hopefully leave us
* a buffer to evict.
*/
if (!list_empty(&render_ring->request_list)) {
struct drm_i915_gem_request *request;
request = list_first_entry(&render_ring->request_list,
struct drm_i915_gem_request,
list);
ret = i915_wait_request(dev,
request->seqno, request->ring);
if (ret)
return ret;
continue;
}
if (HAS_BSD(dev) && !list_empty(&bsd_ring->request_list)) {
struct drm_i915_gem_request *request;
request = list_first_entry(&bsd_ring->request_list,
struct drm_i915_gem_request,
list);
ret = i915_wait_request(dev,
request->seqno, request->ring);
if (ret)
return ret;
continue;
}
/* If we didn't have anything on the request list but there
* are buffers awaiting a flush, emit one and try again.
* When we wait on it, those buffers waiting for that flush
* will get moved to inactive.
*/
if (!list_empty(&dev_priv->mm.flushing_list)) {
struct drm_i915_gem_object *obj_priv;
/* Find an object that we can immediately reuse */
list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) {
obj = &obj_priv->base;
if (obj->size >= min_size)
break;
obj = NULL;
}
if (obj != NULL) {
uint32_t seqno;
i915_gem_flush_ring(dev,
obj->write_domain,
obj->write_domain,
obj_priv->ring);
seqno = i915_add_request(dev, NULL,
obj->write_domain,
obj_priv->ring);
if (seqno == 0)
return -ENOMEM;
continue;
}
}
/* If we didn't do any of the above, there's no single buffer
* large enough to swap out for the new one, so just evict
* everything and start again. (This should be rare.)
*/
if (!list_empty (&dev_priv->mm.inactive_list))
return i915_gem_evict_from_inactive_list(dev);
else
return i915_gem_evict_everything(dev);
}
}
int int
i915_gem_object_get_pages(struct drm_gem_object *obj, i915_gem_object_get_pages(struct drm_gem_object *obj,
gfp_t gfpmask) gfp_t gfpmask)
...@@ -2666,7 +2494,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) ...@@ -2666,7 +2494,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
#if WATCH_LRU #if WATCH_LRU
DRM_INFO("%s: GTT full, evicting something\n", __func__); DRM_INFO("%s: GTT full, evicting something\n", __func__);
#endif #endif
ret = i915_gem_evict_something(dev, obj->size); ret = i915_gem_evict_something(dev, obj->size, alignment);
if (ret) if (ret)
return ret; return ret;
...@@ -2684,7 +2512,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) ...@@ -2684,7 +2512,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
if (ret == -ENOMEM) { if (ret == -ENOMEM) {
/* first try to clear up some space from the GTT */ /* first try to clear up some space from the GTT */
ret = i915_gem_evict_something(dev, obj->size); ret = i915_gem_evict_something(dev, obj->size,
alignment);
if (ret) { if (ret) {
/* now try to shrink everyone else */ /* now try to shrink everyone else */
if (gfpmask) { if (gfpmask) {
...@@ -2714,7 +2543,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) ...@@ -2714,7 +2543,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
drm_mm_put_block(obj_priv->gtt_space); drm_mm_put_block(obj_priv->gtt_space);
obj_priv->gtt_space = NULL; obj_priv->gtt_space = NULL;
ret = i915_gem_evict_something(dev, obj->size); ret = i915_gem_evict_something(dev, obj->size, alignment);
if (ret) if (ret)
return ret; return ret;
...@@ -2723,6 +2552,9 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) ...@@ -2723,6 +2552,9 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
atomic_inc(&dev->gtt_count); atomic_inc(&dev->gtt_count);
atomic_add(obj->size, &dev->gtt_memory); atomic_add(obj->size, &dev->gtt_memory);
/* keep track of bounds object by adding it to the inactive list */
list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
/* Assert that the object is not currently in any GPU domain. As it /* Assert that the object is not currently in any GPU domain. As it
* wasn't in the GTT, there shouldn't be any way it could have been in * wasn't in the GTT, there shouldn't be any way it could have been in
* a GPU cache * a GPU cache
...@@ -3117,6 +2949,7 @@ static void ...@@ -3117,6 +2949,7 @@ static void
i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
{ {
struct drm_device *dev = obj->dev; struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
uint32_t invalidate_domains = 0; uint32_t invalidate_domains = 0;
uint32_t flush_domains = 0; uint32_t flush_domains = 0;
...@@ -3179,6 +3012,13 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj) ...@@ -3179,6 +3012,13 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
obj->pending_write_domain = obj->write_domain; obj->pending_write_domain = obj->write_domain;
obj->read_domains = obj->pending_read_domains; obj->read_domains = obj->pending_read_domains;
if (flush_domains & I915_GEM_GPU_DOMAINS) {
if (obj_priv->ring == &dev_priv->render_ring)
dev_priv->flush_rings |= FLUSH_RENDER_RING;
else if (obj_priv->ring == &dev_priv->bsd_ring)
dev_priv->flush_rings |= FLUSH_BSD_RING;
}
dev->invalidate_domains |= invalidate_domains; dev->invalidate_domains |= invalidate_domains;
dev->flush_domains |= flush_domains; dev->flush_domains |= flush_domains;
#if WATCH_BUF #if WATCH_BUF
...@@ -3718,7 +3558,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, ...@@ -3718,7 +3558,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
ring = &dev_priv->render_ring; ring = &dev_priv->render_ring;
} }
if (args->buffer_count < 1) { if (args->buffer_count < 1) {
DRM_ERROR("execbuf with %d buffers\n", args->buffer_count); DRM_ERROR("execbuf with %d buffers\n", args->buffer_count);
return -EINVAL; return -EINVAL;
...@@ -3892,6 +3731,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, ...@@ -3892,6 +3731,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
*/ */
dev->invalidate_domains = 0; dev->invalidate_domains = 0;
dev->flush_domains = 0; dev->flush_domains = 0;
dev_priv->flush_rings = 0;
for (i = 0; i < args->buffer_count; i++) { for (i = 0; i < args->buffer_count; i++) {
struct drm_gem_object *obj = object_list[i]; struct drm_gem_object *obj = object_list[i];
...@@ -3912,16 +3752,14 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, ...@@ -3912,16 +3752,14 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
i915_gem_flush(dev, i915_gem_flush(dev,
dev->invalidate_domains, dev->invalidate_domains,
dev->flush_domains); dev->flush_domains);
if (dev->flush_domains & I915_GEM_GPU_DOMAINS) { if (dev_priv->flush_rings & FLUSH_RENDER_RING)
(void)i915_add_request(dev, file_priv, (void)i915_add_request(dev, file_priv,
dev->flush_domains, dev->flush_domains,
&dev_priv->render_ring); &dev_priv->render_ring);
if (dev_priv->flush_rings & FLUSH_BSD_RING)
if (HAS_BSD(dev)) (void)i915_add_request(dev, file_priv,
(void)i915_add_request(dev, file_priv, dev->flush_domains,
dev->flush_domains, &dev_priv->bsd_ring);
&dev_priv->bsd_ring);
}
} }
for (i = 0; i < args->buffer_count; i++) { for (i = 0; i < args->buffer_count; i++) {
...@@ -4192,6 +4030,10 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) ...@@ -4192,6 +4030,10 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
if (alignment == 0) if (alignment == 0)
alignment = i915_gem_get_gtt_alignment(obj); alignment = i915_gem_get_gtt_alignment(obj);
if (obj_priv->gtt_offset & (alignment - 1)) { if (obj_priv->gtt_offset & (alignment - 1)) {
WARN(obj_priv->pin_count,
"bo is already pinned with incorrect alignment:"
" offset=%x, req.alignment=%x\n",
obj_priv->gtt_offset, alignment);
ret = i915_gem_object_unbind(obj); ret = i915_gem_object_unbind(obj);
if (ret) if (ret)
return ret; return ret;
...@@ -4213,8 +4055,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) ...@@ -4213,8 +4055,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
atomic_inc(&dev->pin_count); atomic_inc(&dev->pin_count);
atomic_add(obj->size, &dev->pin_memory); atomic_add(obj->size, &dev->pin_memory);
if (!obj_priv->active && if (!obj_priv->active &&
(obj->write_domain & I915_GEM_GPU_DOMAINS) == 0 && (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
!list_empty(&obj_priv->list))
list_del_init(&obj_priv->list); list_del_init(&obj_priv->list);
} }
i915_verify_inactive(dev, __FILE__, __LINE__); i915_verify_inactive(dev, __FILE__, __LINE__);
...@@ -4359,22 +4200,34 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, ...@@ -4359,22 +4200,34 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
} }
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
/* Update the active list for the hardware's current position.
* Otherwise this only updates on a delayed timer or when irqs are
* actually unmasked, and our working set ends up being larger than
* required.
*/
i915_gem_retire_requests(dev);
obj_priv = to_intel_bo(obj); /* Count all active objects as busy, even if they are currently not used
/* Don't count being on the flushing list against the object being * by the gpu. Users of this interface expect objects to eventually
* done. Otherwise, a buffer left on the flushing list but not getting * become non-busy without any further actions, therefore emit any
* flushed (because nobody's flushing that domain) won't ever return * necessary flushes here.
* unbusy and get reused by libdrm's bo cache. The other expected
* consumer of this interface, OpenGL's occlusion queries, also specs
* that the objects get unbusy "eventually" without any interference.
*/ */
args->busy = obj_priv->active && obj_priv->last_rendering_seqno != 0; obj_priv = to_intel_bo(obj);
args->busy = obj_priv->active;
if (args->busy) {
/* Unconditionally flush objects, even when the gpu still uses this
* object. Userspace calling this function indicates that it wants to
* use this buffer rather sooner than later, so issuing the required
* flush earlier is beneficial.
*/
if (obj->write_domain) {
i915_gem_flush(dev, 0, obj->write_domain);
(void)i915_add_request(dev, file_priv, obj->write_domain, obj_priv->ring);
}
/* Update the active list for the hardware's current position.
* Otherwise this only updates on a delayed timer or when irqs
* are actually unmasked, and our working set ends up being
* larger than required.
*/
i915_gem_retire_requests_ring(dev, obj_priv->ring);
args->busy = obj_priv->active;
}
drm_gem_object_unreference(obj); drm_gem_object_unreference(obj);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
...@@ -4514,30 +4367,6 @@ void i915_gem_free_object(struct drm_gem_object *obj) ...@@ -4514,30 +4367,6 @@ void i915_gem_free_object(struct drm_gem_object *obj)
i915_gem_free_object_tail(obj); i915_gem_free_object_tail(obj);
} }
/** Unbinds all inactive objects. */
static int
i915_gem_evict_from_inactive_list(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
while (!list_empty(&dev_priv->mm.inactive_list)) {
struct drm_gem_object *obj;
int ret;
obj = &list_first_entry(&dev_priv->mm.inactive_list,
struct drm_i915_gem_object,
list)->base;
ret = i915_gem_object_unbind(obj);
if (ret != 0) {
DRM_ERROR("Error unbinding object: %d\n", ret);
return ret;
}
}
return 0;
}
int int
i915_gem_idle(struct drm_device *dev) i915_gem_idle(struct drm_device *dev)
{ {
...@@ -4562,7 +4391,7 @@ i915_gem_idle(struct drm_device *dev) ...@@ -4562,7 +4391,7 @@ i915_gem_idle(struct drm_device *dev)
/* Under UMS, be paranoid and evict. */ /* Under UMS, be paranoid and evict. */
if (!drm_core_check_feature(dev, DRIVER_MODESET)) { if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
ret = i915_gem_evict_from_inactive_list(dev); ret = i915_gem_evict_inactive(dev);
if (ret) { if (ret) {
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return ret; return ret;
...@@ -4680,6 +4509,8 @@ i915_gem_init_ringbuffer(struct drm_device *dev) ...@@ -4680,6 +4509,8 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
goto cleanup_render_ring; goto cleanup_render_ring;
} }
dev_priv->next_seqno = 1;
return 0; return 0;
cleanup_render_ring: cleanup_render_ring:
...@@ -4841,7 +4672,7 @@ i915_gem_load(struct drm_device *dev) ...@@ -4841,7 +4672,7 @@ i915_gem_load(struct drm_device *dev)
* e.g. for cursor + overlay regs * e.g. for cursor + overlay regs
*/ */
int i915_gem_init_phys_object(struct drm_device *dev, int i915_gem_init_phys_object(struct drm_device *dev,
int id, int size) int id, int size, int align)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_phys_object *phys_obj; struct drm_i915_gem_phys_object *phys_obj;
...@@ -4856,7 +4687,7 @@ int i915_gem_init_phys_object(struct drm_device *dev, ...@@ -4856,7 +4687,7 @@ int i915_gem_init_phys_object(struct drm_device *dev,
phys_obj->id = id; phys_obj->id = id;
phys_obj->handle = drm_pci_alloc(dev, size, 0); phys_obj->handle = drm_pci_alloc(dev, size, align);
if (!phys_obj->handle) { if (!phys_obj->handle) {
ret = -ENOMEM; ret = -ENOMEM;
goto kfree_obj; goto kfree_obj;
...@@ -4938,7 +4769,9 @@ void i915_gem_detach_phys_object(struct drm_device *dev, ...@@ -4938,7 +4769,9 @@ void i915_gem_detach_phys_object(struct drm_device *dev,
int int
i915_gem_attach_phys_object(struct drm_device *dev, i915_gem_attach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj, int id) struct drm_gem_object *obj,
int id,
int align)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv; struct drm_i915_gem_object *obj_priv;
...@@ -4957,11 +4790,10 @@ i915_gem_attach_phys_object(struct drm_device *dev, ...@@ -4957,11 +4790,10 @@ i915_gem_attach_phys_object(struct drm_device *dev,
i915_gem_detach_phys_object(dev, obj); i915_gem_detach_phys_object(dev, obj);
} }
/* create a new object */ /* create a new object */
if (!dev_priv->mm.phys_objs[id - 1]) { if (!dev_priv->mm.phys_objs[id - 1]) {
ret = i915_gem_init_phys_object(dev, id, ret = i915_gem_init_phys_object(dev, id,
obj->size); obj->size, align);
if (ret) { if (ret) {
DRM_ERROR("failed to init phys object %d size: %zu\n", id, obj->size); DRM_ERROR("failed to init phys object %d size: %zu\n", id, obj->size);
goto out; goto out;
......
/*
* Copyright © 2008-2010 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* Authors:
* Eric Anholt <eric@anholt.net>
* Chris Wilson <chris@chris-wilson.co.uuk>
*
*/
#include "drmP.h"
#include "drm.h"
#include "i915_drv.h"
#include "i915_drm.h"
static struct drm_i915_gem_object *
i915_gem_next_active_object(struct drm_device *dev,
struct list_head **render_iter,
struct list_head **bsd_iter)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *render_obj = NULL, *bsd_obj = NULL;
if (*render_iter != &dev_priv->render_ring.active_list)
render_obj = list_entry(*render_iter,
struct drm_i915_gem_object,
list);
if (HAS_BSD(dev)) {
if (*bsd_iter != &dev_priv->bsd_ring.active_list)
bsd_obj = list_entry(*bsd_iter,
struct drm_i915_gem_object,
list);
if (render_obj == NULL) {
*bsd_iter = (*bsd_iter)->next;
return bsd_obj;
}
if (bsd_obj == NULL) {
*render_iter = (*render_iter)->next;
return render_obj;
}
/* XXX can we handle seqno wrapping? */
if (render_obj->last_rendering_seqno < bsd_obj->last_rendering_seqno) {
*render_iter = (*render_iter)->next;
return render_obj;
} else {
*bsd_iter = (*bsd_iter)->next;
return bsd_obj;
}
} else {
*render_iter = (*render_iter)->next;
return render_obj;
}
}
static bool
mark_free(struct drm_i915_gem_object *obj_priv,
struct list_head *unwind)
{
list_add(&obj_priv->evict_list, unwind);
return drm_mm_scan_add_block(obj_priv->gtt_space);
}
#define i915_for_each_active_object(OBJ, R, B) \
*(R) = dev_priv->render_ring.active_list.next; \
*(B) = dev_priv->bsd_ring.active_list.next; \
while (((OBJ) = i915_gem_next_active_object(dev, (R), (B))) != NULL)
int
i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct list_head eviction_list, unwind_list;
struct drm_i915_gem_object *obj_priv, *tmp_obj_priv;
struct list_head *render_iter, *bsd_iter;
int ret = 0;
i915_gem_retire_requests(dev);
/* Re-check for free space after retiring requests */
if (drm_mm_search_free(&dev_priv->mm.gtt_space,
min_size, alignment, 0))
return 0;
/*
* The goal is to evict objects and amalgamate space in LRU order.
* The oldest idle objects reside on the inactive list, which is in
* retirement order. The next objects to retire are those on the (per
* ring) active list that do not have an outstanding flush. Once the
* hardware reports completion (the seqno is updated after the
* batchbuffer has been finished) the clean buffer objects would
* be retired to the inactive list. Any dirty objects would be added
* to the tail of the flushing list. So after processing the clean
* active objects we need to emit a MI_FLUSH to retire the flushing
* list, hence the retirement order of the flushing list is in
* advance of the dirty objects on the active lists.
*
* The retirement sequence is thus:
* 1. Inactive objects (already retired)
* 2. Clean active objects
* 3. Flushing list
* 4. Dirty active objects.
*
* On each list, the oldest objects lie at the HEAD with the freshest
* object on the TAIL.
*/
INIT_LIST_HEAD(&unwind_list);
drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment);
/* First see if there is a large enough contiguous idle region... */
list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
if (mark_free(obj_priv, &unwind_list))
goto found;
}
/* Now merge in the soon-to-be-expired objects... */
i915_for_each_active_object(obj_priv, &render_iter, &bsd_iter) {
/* Does the object require an outstanding flush? */
if (obj_priv->base.write_domain || obj_priv->pin_count)
continue;
if (mark_free(obj_priv, &unwind_list))
goto found;
}
/* Finally add anything with a pending flush (in order of retirement) */
list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) {
if (obj_priv->pin_count)
continue;
if (mark_free(obj_priv, &unwind_list))
goto found;
}
i915_for_each_active_object(obj_priv, &render_iter, &bsd_iter) {
if (! obj_priv->base.write_domain || obj_priv->pin_count)
continue;
if (mark_free(obj_priv, &unwind_list))
goto found;
}
/* Nothing found, clean up and bail out! */
list_for_each_entry(obj_priv, &unwind_list, evict_list) {
ret = drm_mm_scan_remove_block(obj_priv->gtt_space);
BUG_ON(ret);
}
/* We expect the caller to unpin, evict all and try again, or give up.
* So calling i915_gem_evict_everything() is unnecessary.
*/
return -ENOSPC;
found:
INIT_LIST_HEAD(&eviction_list);
list_for_each_entry_safe(obj_priv, tmp_obj_priv,
&unwind_list, evict_list) {
if (drm_mm_scan_remove_block(obj_priv->gtt_space)) {
/* drm_mm doesn't allow any other other operations while
* scanning, therefore store to be evicted objects on a
* temporary list. */
list_move(&obj_priv->evict_list, &eviction_list);
}
}
/* Unbinding will emit any required flushes */
list_for_each_entry_safe(obj_priv, tmp_obj_priv,
&eviction_list, evict_list) {
#if WATCH_LRU
DRM_INFO("%s: evicting %p\n", __func__, obj);
#endif
ret = i915_gem_object_unbind(&obj_priv->base);
if (ret)
return ret;
}
/* The just created free hole should be on the top of the free stack
* maintained by drm_mm, so this BUG_ON actually executes in O(1).
* Furthermore all accessed data has just recently been used, so it
* should be really fast, too. */
BUG_ON(!drm_mm_search_free(&dev_priv->mm.gtt_space, min_size,
alignment, 0));
return 0;
}
int
i915_gem_evict_everything(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
bool lists_empty;
spin_lock(&dev_priv->mm.active_list_lock);
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
list_empty(&dev_priv->mm.flushing_list) &&
list_empty(&dev_priv->render_ring.active_list) &&
(!HAS_BSD(dev)
|| list_empty(&dev_priv->bsd_ring.active_list)));
spin_unlock(&dev_priv->mm.active_list_lock);
if (lists_empty)
return -ENOSPC;
/* Flush everything (on to the inactive lists) and evict */
ret = i915_gpu_idle(dev);
if (ret)
return ret;
BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
ret = i915_gem_evict_inactive(dev);
if (ret)
return ret;
spin_lock(&dev_priv->mm.active_list_lock);
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
list_empty(&dev_priv->mm.flushing_list) &&
list_empty(&dev_priv->render_ring.active_list) &&
(!HAS_BSD(dev)
|| list_empty(&dev_priv->bsd_ring.active_list)));
spin_unlock(&dev_priv->mm.active_list_lock);
BUG_ON(!lists_empty);
return 0;
}
/** Unbinds all inactive objects. */
int
i915_gem_evict_inactive(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
while (!list_empty(&dev_priv->mm.inactive_list)) {
struct drm_gem_object *obj;
int ret;
obj = &list_first_entry(&dev_priv->mm.inactive_list,
struct drm_i915_gem_object,
list)->base;
ret = i915_gem_object_unbind(obj);
if (ret != 0) {
DRM_ERROR("Error unbinding object: %d\n", ret);
return ret;
}
}
return 0;
}
...@@ -425,9 +425,11 @@ static struct drm_i915_error_object * ...@@ -425,9 +425,11 @@ static struct drm_i915_error_object *
i915_error_object_create(struct drm_device *dev, i915_error_object_create(struct drm_device *dev,
struct drm_gem_object *src) struct drm_gem_object *src)
{ {
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_error_object *dst; struct drm_i915_error_object *dst;
struct drm_i915_gem_object *src_priv; struct drm_i915_gem_object *src_priv;
int page, page_count; int page, page_count;
u32 reloc_offset;
if (src == NULL) if (src == NULL)
return NULL; return NULL;
...@@ -442,18 +444,27 @@ i915_error_object_create(struct drm_device *dev, ...@@ -442,18 +444,27 @@ i915_error_object_create(struct drm_device *dev,
if (dst == NULL) if (dst == NULL)
return NULL; return NULL;
reloc_offset = src_priv->gtt_offset;
for (page = 0; page < page_count; page++) { for (page = 0; page < page_count; page++) {
void *s, *d = kmalloc(PAGE_SIZE, GFP_ATOMIC);
unsigned long flags; unsigned long flags;
void __iomem *s;
void *d;
d = kmalloc(PAGE_SIZE, GFP_ATOMIC);
if (d == NULL) if (d == NULL)
goto unwind; goto unwind;
local_irq_save(flags); local_irq_save(flags);
s = kmap_atomic(src_priv->pages[page], KM_IRQ0); s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
memcpy(d, s, PAGE_SIZE); reloc_offset,
kunmap_atomic(s, KM_IRQ0); KM_IRQ0);
memcpy_fromio(d, s, PAGE_SIZE);
io_mapping_unmap_atomic(s, KM_IRQ0);
local_irq_restore(flags); local_irq_restore(flags);
dst->pages[page] = d; dst->pages[page] = d;
reloc_offset += PAGE_SIZE;
} }
dst->page_count = page_count; dst->page_count = page_count;
dst->gtt_offset = src_priv->gtt_offset; dst->gtt_offset = src_priv->gtt_offset;
...@@ -489,6 +500,7 @@ i915_error_state_free(struct drm_device *dev, ...@@ -489,6 +500,7 @@ i915_error_state_free(struct drm_device *dev,
i915_error_object_free(error->batchbuffer[1]); i915_error_object_free(error->batchbuffer[1]);
i915_error_object_free(error->ringbuffer); i915_error_object_free(error->ringbuffer);
kfree(error->active_bo); kfree(error->active_bo);
kfree(error->overlay);
kfree(error); kfree(error);
} }
...@@ -612,18 +624,57 @@ static void i915_capture_error_state(struct drm_device *dev) ...@@ -612,18 +624,57 @@ static void i915_capture_error_state(struct drm_device *dev)
if (batchbuffer[1] == NULL && if (batchbuffer[1] == NULL &&
error->acthd >= obj_priv->gtt_offset && error->acthd >= obj_priv->gtt_offset &&
error->acthd < obj_priv->gtt_offset + obj->size && error->acthd < obj_priv->gtt_offset + obj->size)
batchbuffer[0] != obj)
batchbuffer[1] = obj; batchbuffer[1] = obj;
count++; count++;
} }
/* Scan the other lists for completeness for those bizarre errors. */
if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) {
list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) {
struct drm_gem_object *obj = &obj_priv->base;
if (batchbuffer[0] == NULL &&
bbaddr >= obj_priv->gtt_offset &&
bbaddr < obj_priv->gtt_offset + obj->size)
batchbuffer[0] = obj;
if (batchbuffer[1] == NULL &&
error->acthd >= obj_priv->gtt_offset &&
error->acthd < obj_priv->gtt_offset + obj->size)
batchbuffer[1] = obj;
if (batchbuffer[0] && batchbuffer[1])
break;
}
}
if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) {
list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
struct drm_gem_object *obj = &obj_priv->base;
if (batchbuffer[0] == NULL &&
bbaddr >= obj_priv->gtt_offset &&
bbaddr < obj_priv->gtt_offset + obj->size)
batchbuffer[0] = obj;
if (batchbuffer[1] == NULL &&
error->acthd >= obj_priv->gtt_offset &&
error->acthd < obj_priv->gtt_offset + obj->size)
batchbuffer[1] = obj;
if (batchbuffer[0] && batchbuffer[1])
break;
}
}
/* We need to copy these to an anonymous buffer as the simplest /* We need to copy these to an anonymous buffer as the simplest
* method to avoid being overwritten by userpace. * method to avoid being overwritten by userpace.
*/ */
error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]); error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]);
error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]); if (batchbuffer[1] != batchbuffer[0])
error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]);
else
error->batchbuffer[1] = NULL;
/* Record the ringbuffer */ /* Record the ringbuffer */
error->ringbuffer = i915_error_object_create(dev, error->ringbuffer = i915_error_object_create(dev,
...@@ -667,6 +718,8 @@ static void i915_capture_error_state(struct drm_device *dev) ...@@ -667,6 +718,8 @@ static void i915_capture_error_state(struct drm_device *dev)
do_gettimeofday(&error->time); do_gettimeofday(&error->time);
error->overlay = intel_overlay_capture_error_state(dev);
spin_lock_irqsave(&dev_priv->error_lock, flags); spin_lock_irqsave(&dev_priv->error_lock, flags);
if (dev_priv->first_error == NULL) { if (dev_priv->first_error == NULL) {
dev_priv->first_error = error; dev_priv->first_error = error;
...@@ -1251,6 +1304,16 @@ void i915_hangcheck_elapsed(unsigned long data) ...@@ -1251,6 +1304,16 @@ void i915_hangcheck_elapsed(unsigned long data)
&dev_priv->render_ring), &dev_priv->render_ring),
i915_get_tail_request(dev)->seqno)) { i915_get_tail_request(dev)->seqno)) {
dev_priv->hangcheck_count = 0; dev_priv->hangcheck_count = 0;
/* Issue a wake-up to catch stuck h/w. */
if (dev_priv->render_ring.waiting_gem_seqno |
dev_priv->bsd_ring.waiting_gem_seqno) {
DRM_ERROR("Hangcheck timer elapsed... GPU idle, missed IRQ.\n");
if (dev_priv->render_ring.waiting_gem_seqno)
DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
if (dev_priv->bsd_ring.waiting_gem_seqno)
DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
}
return; return;
} }
...@@ -1318,12 +1381,17 @@ static int ironlake_irq_postinstall(struct drm_device *dev) ...@@ -1318,12 +1381,17 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
I915_WRITE(DEIER, dev_priv->de_irq_enable_reg); I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
(void) I915_READ(DEIER); (void) I915_READ(DEIER);
/* user interrupt should be enabled, but masked initial */ /* Gen6 only needs render pipe_control now */
if (IS_GEN6(dev))
render_mask = GT_PIPE_NOTIFY;
dev_priv->gt_irq_mask_reg = ~render_mask; dev_priv->gt_irq_mask_reg = ~render_mask;
dev_priv->gt_irq_enable_reg = render_mask; dev_priv->gt_irq_enable_reg = render_mask;
I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIIR, I915_READ(GTIIR));
I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
if (IS_GEN6(dev))
I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT);
I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg); I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
(void) I915_READ(GTIER); (void) I915_READ(GTIER);
......
...@@ -114,10 +114,6 @@ struct opregion_asle { ...@@ -114,10 +114,6 @@ struct opregion_asle {
#define ASLE_REQ_MSK 0xf #define ASLE_REQ_MSK 0xf
/* response bits of ASLE irq request */ /* response bits of ASLE irq request */
#define ASLE_ALS_ILLUM_FAIL (2<<10)
#define ASLE_BACKLIGHT_FAIL (2<<12)
#define ASLE_PFIT_FAIL (2<<14)
#define ASLE_PWM_FREQ_FAIL (2<<16)
#define ASLE_ALS_ILLUM_FAILED (1<<10) #define ASLE_ALS_ILLUM_FAILED (1<<10)
#define ASLE_BACKLIGHT_FAILED (1<<12) #define ASLE_BACKLIGHT_FAILED (1<<12)
#define ASLE_PFIT_FAILED (1<<14) #define ASLE_PFIT_FAILED (1<<14)
...@@ -155,11 +151,11 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) ...@@ -155,11 +151,11 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
u32 max_backlight, level, shift; u32 max_backlight, level, shift;
if (!(bclp & ASLE_BCLP_VALID)) if (!(bclp & ASLE_BCLP_VALID))
return ASLE_BACKLIGHT_FAIL; return ASLE_BACKLIGHT_FAILED;
bclp &= ASLE_BCLP_MSK; bclp &= ASLE_BCLP_MSK;
if (bclp < 0 || bclp > 255) if (bclp < 0 || bclp > 255)
return ASLE_BACKLIGHT_FAIL; return ASLE_BACKLIGHT_FAILED;
blc_pwm_ctl = I915_READ(BLC_PWM_CTL); blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2); blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2);
...@@ -211,7 +207,7 @@ static u32 asle_set_pfit(struct drm_device *dev, u32 pfit) ...@@ -211,7 +207,7 @@ static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
/* Panel fitting is currently controlled by the X code, so this is a /* Panel fitting is currently controlled by the X code, so this is a
noop until modesetting support works fully */ noop until modesetting support works fully */
if (!(pfit & ASLE_PFIT_VALID)) if (!(pfit & ASLE_PFIT_VALID))
return ASLE_PFIT_FAIL; return ASLE_PFIT_FAILED;
return 0; return 0;
} }
......
...@@ -170,6 +170,7 @@ ...@@ -170,6 +170,7 @@
#define MI_NO_WRITE_FLUSH (1 << 2) #define MI_NO_WRITE_FLUSH (1 << 2)
#define MI_SCENE_COUNT (1 << 3) /* just increment scene count */ #define MI_SCENE_COUNT (1 << 3) /* just increment scene count */
#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ #define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */
#define MI_INVALIDATE_ISP (1 << 5) /* invalidate indirect state pointers */
#define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) #define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0)
#define MI_REPORT_HEAD MI_INSTR(0x07, 0) #define MI_REPORT_HEAD MI_INSTR(0x07, 0)
#define MI_OVERLAY_FLIP MI_INSTR(0x11,0) #define MI_OVERLAY_FLIP MI_INSTR(0x11,0)
...@@ -180,6 +181,12 @@ ...@@ -180,6 +181,12 @@
#define MI_DISPLAY_FLIP MI_INSTR(0x14, 2) #define MI_DISPLAY_FLIP MI_INSTR(0x14, 2)
#define MI_DISPLAY_FLIP_I915 MI_INSTR(0x14, 1) #define MI_DISPLAY_FLIP_I915 MI_INSTR(0x14, 1)
#define MI_DISPLAY_FLIP_PLANE(n) ((n) << 20) #define MI_DISPLAY_FLIP_PLANE(n) ((n) << 20)
#define MI_SET_CONTEXT MI_INSTR(0x18, 0)
#define MI_MM_SPACE_GTT (1<<8)
#define MI_MM_SPACE_PHYSICAL (0<<8)
#define MI_SAVE_EXT_STATE_EN (1<<3)
#define MI_RESTORE_EXT_STATE_EN (1<<2)
#define MI_RESTORE_INHIBIT (1<<0)
#define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) #define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1)
#define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ #define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */
#define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1) #define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1)
...@@ -1099,6 +1106,11 @@ ...@@ -1099,6 +1106,11 @@
#define DDRMPLL1 0X12c20 #define DDRMPLL1 0X12c20
#define PEG_BAND_GAP_DATA 0x14d68 #define PEG_BAND_GAP_DATA 0x14d68
/*
* Logical Context regs
*/
#define CCID 0x2180
#define CCID_EN (1<<0)
/* /*
* Overlay regs * Overlay regs
*/ */
...@@ -2069,6 +2081,7 @@ ...@@ -2069,6 +2081,7 @@
#define PIPE_DITHER_TYPE_ST01 (1 << 2) #define PIPE_DITHER_TYPE_ST01 (1 << 2)
/* Pipe A */ /* Pipe A */
#define PIPEADSL 0x70000 #define PIPEADSL 0x70000
#define DSL_LINEMASK 0x00000fff
#define PIPEACONF 0x70008 #define PIPEACONF 0x70008
#define PIPEACONF_ENABLE (1<<31) #define PIPEACONF_ENABLE (1<<31)
#define PIPEACONF_DISABLE 0 #define PIPEACONF_DISABLE 0
...@@ -2928,6 +2941,7 @@ ...@@ -2928,6 +2941,7 @@
#define TRANS_DP_VSYNC_ACTIVE_LOW 0 #define TRANS_DP_VSYNC_ACTIVE_LOW 0
#define TRANS_DP_HSYNC_ACTIVE_HIGH (1<<3) #define TRANS_DP_HSYNC_ACTIVE_HIGH (1<<3)
#define TRANS_DP_HSYNC_ACTIVE_LOW 0 #define TRANS_DP_HSYNC_ACTIVE_LOW 0
#define TRANS_DP_SYNC_MASK (3<<3)
/* SNB eDP training params */ /* SNB eDP training params */
/* SNB A-stepping */ /* SNB A-stepping */
......
...@@ -34,7 +34,7 @@ static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) ...@@ -34,7 +34,7 @@ static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 dpll_reg; u32 dpll_reg;
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
dpll_reg = (pipe == PIPE_A) ? PCH_DPLL_A: PCH_DPLL_B; dpll_reg = (pipe == PIPE_A) ? PCH_DPLL_A: PCH_DPLL_B;
} else { } else {
dpll_reg = (pipe == PIPE_A) ? DPLL_A: DPLL_B; dpll_reg = (pipe == PIPE_A) ? DPLL_A: DPLL_B;
...@@ -53,7 +53,7 @@ static void i915_save_palette(struct drm_device *dev, enum pipe pipe) ...@@ -53,7 +53,7 @@ static void i915_save_palette(struct drm_device *dev, enum pipe pipe)
if (!i915_pipe_enabled(dev, pipe)) if (!i915_pipe_enabled(dev, pipe))
return; return;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
reg = (pipe == PIPE_A) ? LGC_PALETTE_A : LGC_PALETTE_B; reg = (pipe == PIPE_A) ? LGC_PALETTE_A : LGC_PALETTE_B;
if (pipe == PIPE_A) if (pipe == PIPE_A)
...@@ -75,7 +75,7 @@ static void i915_restore_palette(struct drm_device *dev, enum pipe pipe) ...@@ -75,7 +75,7 @@ static void i915_restore_palette(struct drm_device *dev, enum pipe pipe)
if (!i915_pipe_enabled(dev, pipe)) if (!i915_pipe_enabled(dev, pipe))
return; return;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
reg = (pipe == PIPE_A) ? LGC_PALETTE_A : LGC_PALETTE_B; reg = (pipe == PIPE_A) ? LGC_PALETTE_A : LGC_PALETTE_B;
if (pipe == PIPE_A) if (pipe == PIPE_A)
...@@ -239,7 +239,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) ...@@ -239,7 +239,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
if (drm_core_check_feature(dev, DRIVER_MODESET)) if (drm_core_check_feature(dev, DRIVER_MODESET))
return; return;
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
dev_priv->savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL); dev_priv->savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL);
dev_priv->saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL); dev_priv->saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL);
} }
...@@ -247,7 +247,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) ...@@ -247,7 +247,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
/* Pipe & plane A info */ /* Pipe & plane A info */
dev_priv->savePIPEACONF = I915_READ(PIPEACONF); dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
dev_priv->savePIPEASRC = I915_READ(PIPEASRC); dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
dev_priv->saveFPA0 = I915_READ(PCH_FPA0); dev_priv->saveFPA0 = I915_READ(PCH_FPA0);
dev_priv->saveFPA1 = I915_READ(PCH_FPA1); dev_priv->saveFPA1 = I915_READ(PCH_FPA1);
dev_priv->saveDPLL_A = I915_READ(PCH_DPLL_A); dev_priv->saveDPLL_A = I915_READ(PCH_DPLL_A);
...@@ -256,7 +256,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) ...@@ -256,7 +256,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
dev_priv->saveFPA1 = I915_READ(FPA1); dev_priv->saveFPA1 = I915_READ(FPA1);
dev_priv->saveDPLL_A = I915_READ(DPLL_A); dev_priv->saveDPLL_A = I915_READ(DPLL_A);
} }
if (IS_I965G(dev) && !IS_IRONLAKE(dev)) if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD); dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD);
dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A); dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A);
dev_priv->saveHBLANK_A = I915_READ(HBLANK_A); dev_priv->saveHBLANK_A = I915_READ(HBLANK_A);
...@@ -264,10 +264,10 @@ static void i915_save_modeset_reg(struct drm_device *dev) ...@@ -264,10 +264,10 @@ static void i915_save_modeset_reg(struct drm_device *dev)
dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A); dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A);
dev_priv->saveVBLANK_A = I915_READ(VBLANK_A); dev_priv->saveVBLANK_A = I915_READ(VBLANK_A);
dev_priv->saveVSYNC_A = I915_READ(VSYNC_A); dev_priv->saveVSYNC_A = I915_READ(VSYNC_A);
if (!IS_IRONLAKE(dev)) if (!HAS_PCH_SPLIT(dev))
dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A); dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A);
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
dev_priv->savePIPEA_DATA_M1 = I915_READ(PIPEA_DATA_M1); dev_priv->savePIPEA_DATA_M1 = I915_READ(PIPEA_DATA_M1);
dev_priv->savePIPEA_DATA_N1 = I915_READ(PIPEA_DATA_N1); dev_priv->savePIPEA_DATA_N1 = I915_READ(PIPEA_DATA_N1);
dev_priv->savePIPEA_LINK_M1 = I915_READ(PIPEA_LINK_M1); dev_priv->savePIPEA_LINK_M1 = I915_READ(PIPEA_LINK_M1);
...@@ -304,7 +304,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) ...@@ -304,7 +304,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
/* Pipe & plane B info */ /* Pipe & plane B info */
dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF);
dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC); dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC);
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
dev_priv->saveFPB0 = I915_READ(PCH_FPB0); dev_priv->saveFPB0 = I915_READ(PCH_FPB0);
dev_priv->saveFPB1 = I915_READ(PCH_FPB1); dev_priv->saveFPB1 = I915_READ(PCH_FPB1);
dev_priv->saveDPLL_B = I915_READ(PCH_DPLL_B); dev_priv->saveDPLL_B = I915_READ(PCH_DPLL_B);
...@@ -313,7 +313,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) ...@@ -313,7 +313,7 @@ static void i915_save_modeset_reg(struct drm_device *dev)
dev_priv->saveFPB1 = I915_READ(FPB1); dev_priv->saveFPB1 = I915_READ(FPB1);
dev_priv->saveDPLL_B = I915_READ(DPLL_B); dev_priv->saveDPLL_B = I915_READ(DPLL_B);
} }
if (IS_I965G(dev) && !IS_IRONLAKE(dev)) if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD); dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD);
dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B); dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B);
dev_priv->saveHBLANK_B = I915_READ(HBLANK_B); dev_priv->saveHBLANK_B = I915_READ(HBLANK_B);
...@@ -321,10 +321,10 @@ static void i915_save_modeset_reg(struct drm_device *dev) ...@@ -321,10 +321,10 @@ static void i915_save_modeset_reg(struct drm_device *dev)
dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B); dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B);
dev_priv->saveVBLANK_B = I915_READ(VBLANK_B); dev_priv->saveVBLANK_B = I915_READ(VBLANK_B);
dev_priv->saveVSYNC_B = I915_READ(VSYNC_B); dev_priv->saveVSYNC_B = I915_READ(VSYNC_B);
if (!IS_IRONLAKE(dev)) if (!HAS_PCH_SPLIT(dev))
dev_priv->saveBCLRPAT_B = I915_READ(BCLRPAT_B); dev_priv->saveBCLRPAT_B = I915_READ(BCLRPAT_B);
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
dev_priv->savePIPEB_DATA_M1 = I915_READ(PIPEB_DATA_M1); dev_priv->savePIPEB_DATA_M1 = I915_READ(PIPEB_DATA_M1);
dev_priv->savePIPEB_DATA_N1 = I915_READ(PIPEB_DATA_N1); dev_priv->savePIPEB_DATA_N1 = I915_READ(PIPEB_DATA_N1);
dev_priv->savePIPEB_LINK_M1 = I915_READ(PIPEB_LINK_M1); dev_priv->savePIPEB_LINK_M1 = I915_READ(PIPEB_LINK_M1);
...@@ -369,7 +369,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) ...@@ -369,7 +369,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
if (drm_core_check_feature(dev, DRIVER_MODESET)) if (drm_core_check_feature(dev, DRIVER_MODESET))
return; return;
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
dpll_a_reg = PCH_DPLL_A; dpll_a_reg = PCH_DPLL_A;
dpll_b_reg = PCH_DPLL_B; dpll_b_reg = PCH_DPLL_B;
fpa0_reg = PCH_FPA0; fpa0_reg = PCH_FPA0;
...@@ -385,7 +385,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) ...@@ -385,7 +385,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
fpb1_reg = FPB1; fpb1_reg = FPB1;
} }
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(PCH_DREF_CONTROL, dev_priv->savePCH_DREF_CONTROL); I915_WRITE(PCH_DREF_CONTROL, dev_priv->savePCH_DREF_CONTROL);
I915_WRITE(DISP_ARB_CTL, dev_priv->saveDISP_ARB_CTL); I915_WRITE(DISP_ARB_CTL, dev_priv->saveDISP_ARB_CTL);
} }
...@@ -395,16 +395,20 @@ static void i915_restore_modeset_reg(struct drm_device *dev) ...@@ -395,16 +395,20 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A & I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A &
~DPLL_VCO_ENABLE); ~DPLL_VCO_ENABLE);
DRM_UDELAY(150); POSTING_READ(dpll_a_reg);
udelay(150);
} }
I915_WRITE(fpa0_reg, dev_priv->saveFPA0); I915_WRITE(fpa0_reg, dev_priv->saveFPA0);
I915_WRITE(fpa1_reg, dev_priv->saveFPA1); I915_WRITE(fpa1_reg, dev_priv->saveFPA1);
/* Actually enable it */ /* Actually enable it */
I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A); I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A);
DRM_UDELAY(150); POSTING_READ(dpll_a_reg);
if (IS_I965G(dev) && !IS_IRONLAKE(dev)) udelay(150);
if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD); I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
DRM_UDELAY(150); POSTING_READ(DPLL_A_MD);
}
udelay(150);
/* Restore mode */ /* Restore mode */
I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A); I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
...@@ -413,10 +417,10 @@ static void i915_restore_modeset_reg(struct drm_device *dev) ...@@ -413,10 +417,10 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A); I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A); I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A); I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
if (!IS_IRONLAKE(dev)) if (!HAS_PCH_SPLIT(dev))
I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A); I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(PIPEA_DATA_M1, dev_priv->savePIPEA_DATA_M1); I915_WRITE(PIPEA_DATA_M1, dev_priv->savePIPEA_DATA_M1);
I915_WRITE(PIPEA_DATA_N1, dev_priv->savePIPEA_DATA_N1); I915_WRITE(PIPEA_DATA_N1, dev_priv->savePIPEA_DATA_N1);
I915_WRITE(PIPEA_LINK_M1, dev_priv->savePIPEA_LINK_M1); I915_WRITE(PIPEA_LINK_M1, dev_priv->savePIPEA_LINK_M1);
...@@ -460,16 +464,20 @@ static void i915_restore_modeset_reg(struct drm_device *dev) ...@@ -460,16 +464,20 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B & I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B &
~DPLL_VCO_ENABLE); ~DPLL_VCO_ENABLE);
DRM_UDELAY(150); POSTING_READ(dpll_b_reg);
udelay(150);
} }
I915_WRITE(fpb0_reg, dev_priv->saveFPB0); I915_WRITE(fpb0_reg, dev_priv->saveFPB0);
I915_WRITE(fpb1_reg, dev_priv->saveFPB1); I915_WRITE(fpb1_reg, dev_priv->saveFPB1);
/* Actually enable it */ /* Actually enable it */
I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B); I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B);
DRM_UDELAY(150); POSTING_READ(dpll_b_reg);
if (IS_I965G(dev) && !IS_IRONLAKE(dev)) udelay(150);
if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
DRM_UDELAY(150); POSTING_READ(DPLL_B_MD);
}
udelay(150);
/* Restore mode */ /* Restore mode */
I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B); I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
...@@ -478,10 +486,10 @@ static void i915_restore_modeset_reg(struct drm_device *dev) ...@@ -478,10 +486,10 @@ static void i915_restore_modeset_reg(struct drm_device *dev)
I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B); I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B); I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B); I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
if (!IS_IRONLAKE(dev)) if (!HAS_PCH_SPLIT(dev))
I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B); I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(PIPEB_DATA_M1, dev_priv->savePIPEB_DATA_M1); I915_WRITE(PIPEB_DATA_M1, dev_priv->savePIPEB_DATA_M1);
I915_WRITE(PIPEB_DATA_N1, dev_priv->savePIPEB_DATA_N1); I915_WRITE(PIPEB_DATA_N1, dev_priv->savePIPEB_DATA_N1);
I915_WRITE(PIPEB_LINK_M1, dev_priv->savePIPEB_LINK_M1); I915_WRITE(PIPEB_LINK_M1, dev_priv->savePIPEB_LINK_M1);
...@@ -546,14 +554,14 @@ void i915_save_display(struct drm_device *dev) ...@@ -546,14 +554,14 @@ void i915_save_display(struct drm_device *dev)
dev_priv->saveCURSIZE = I915_READ(CURSIZE); dev_priv->saveCURSIZE = I915_READ(CURSIZE);
/* CRT state */ /* CRT state */
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
dev_priv->saveADPA = I915_READ(PCH_ADPA); dev_priv->saveADPA = I915_READ(PCH_ADPA);
} else { } else {
dev_priv->saveADPA = I915_READ(ADPA); dev_priv->saveADPA = I915_READ(ADPA);
} }
/* LVDS state */ /* LVDS state */
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
dev_priv->savePP_CONTROL = I915_READ(PCH_PP_CONTROL); dev_priv->savePP_CONTROL = I915_READ(PCH_PP_CONTROL);
dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1); dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1);
dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2); dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2);
...@@ -571,10 +579,10 @@ void i915_save_display(struct drm_device *dev) ...@@ -571,10 +579,10 @@ void i915_save_display(struct drm_device *dev)
dev_priv->saveLVDS = I915_READ(LVDS); dev_priv->saveLVDS = I915_READ(LVDS);
} }
if (!IS_I830(dev) && !IS_845G(dev) && !IS_IRONLAKE(dev)) if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev))
dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL); dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
dev_priv->savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS); dev_priv->savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS);
dev_priv->savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS); dev_priv->savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS);
dev_priv->savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR); dev_priv->savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR);
...@@ -602,7 +610,7 @@ void i915_save_display(struct drm_device *dev) ...@@ -602,7 +610,7 @@ void i915_save_display(struct drm_device *dev)
/* Only save FBC state on the platform that supports FBC */ /* Only save FBC state on the platform that supports FBC */
if (I915_HAS_FBC(dev)) { if (I915_HAS_FBC(dev)) {
if (IS_IRONLAKE_M(dev)) { if (HAS_PCH_SPLIT(dev)) {
dev_priv->saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE); dev_priv->saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE);
} else if (IS_GM45(dev)) { } else if (IS_GM45(dev)) {
dev_priv->saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE); dev_priv->saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE);
...@@ -618,7 +626,7 @@ void i915_save_display(struct drm_device *dev) ...@@ -618,7 +626,7 @@ void i915_save_display(struct drm_device *dev)
dev_priv->saveVGA0 = I915_READ(VGA0); dev_priv->saveVGA0 = I915_READ(VGA0);
dev_priv->saveVGA1 = I915_READ(VGA1); dev_priv->saveVGA1 = I915_READ(VGA1);
dev_priv->saveVGA_PD = I915_READ(VGA_PD); dev_priv->saveVGA_PD = I915_READ(VGA_PD);
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
dev_priv->saveVGACNTRL = I915_READ(CPU_VGACNTRL); dev_priv->saveVGACNTRL = I915_READ(CPU_VGACNTRL);
else else
dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); dev_priv->saveVGACNTRL = I915_READ(VGACNTRL);
...@@ -660,24 +668,24 @@ void i915_restore_display(struct drm_device *dev) ...@@ -660,24 +668,24 @@ void i915_restore_display(struct drm_device *dev)
I915_WRITE(CURSIZE, dev_priv->saveCURSIZE); I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
/* CRT state */ /* CRT state */
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
I915_WRITE(PCH_ADPA, dev_priv->saveADPA); I915_WRITE(PCH_ADPA, dev_priv->saveADPA);
else else
I915_WRITE(ADPA, dev_priv->saveADPA); I915_WRITE(ADPA, dev_priv->saveADPA);
/* LVDS state */ /* LVDS state */
if (IS_I965G(dev) && !IS_IRONLAKE(dev)) if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2); I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(PCH_LVDS, dev_priv->saveLVDS); I915_WRITE(PCH_LVDS, dev_priv->saveLVDS);
} else if (IS_MOBILE(dev) && !IS_I830(dev)) } else if (IS_MOBILE(dev) && !IS_I830(dev))
I915_WRITE(LVDS, dev_priv->saveLVDS); I915_WRITE(LVDS, dev_priv->saveLVDS);
if (!IS_I830(dev) && !IS_845G(dev) && !IS_IRONLAKE(dev)) if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev))
I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL); I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL);
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->saveBLC_PWM_CTL); I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->saveBLC_PWM_CTL);
I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->saveBLC_PWM_CTL2); I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->saveBLC_PWM_CTL2);
I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->saveBLC_CPU_PWM_CTL); I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->saveBLC_CPU_PWM_CTL);
...@@ -708,7 +716,7 @@ void i915_restore_display(struct drm_device *dev) ...@@ -708,7 +716,7 @@ void i915_restore_display(struct drm_device *dev)
/* only restore FBC info on the platform that supports FBC*/ /* only restore FBC info on the platform that supports FBC*/
if (I915_HAS_FBC(dev)) { if (I915_HAS_FBC(dev)) {
if (IS_IRONLAKE_M(dev)) { if (HAS_PCH_SPLIT(dev)) {
ironlake_disable_fbc(dev); ironlake_disable_fbc(dev);
I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE); I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
} else if (IS_GM45(dev)) { } else if (IS_GM45(dev)) {
...@@ -723,14 +731,15 @@ void i915_restore_display(struct drm_device *dev) ...@@ -723,14 +731,15 @@ void i915_restore_display(struct drm_device *dev)
} }
} }
/* VGA state */ /* VGA state */
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
I915_WRITE(CPU_VGACNTRL, dev_priv->saveVGACNTRL); I915_WRITE(CPU_VGACNTRL, dev_priv->saveVGACNTRL);
else else
I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL); I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL);
I915_WRITE(VGA0, dev_priv->saveVGA0); I915_WRITE(VGA0, dev_priv->saveVGA0);
I915_WRITE(VGA1, dev_priv->saveVGA1); I915_WRITE(VGA1, dev_priv->saveVGA1);
I915_WRITE(VGA_PD, dev_priv->saveVGA_PD); I915_WRITE(VGA_PD, dev_priv->saveVGA_PD);
DRM_UDELAY(150); POSTING_READ(VGA_PD);
udelay(150);
i915_restore_vga(dev); i915_restore_vga(dev);
} }
...@@ -748,7 +757,7 @@ int i915_save_state(struct drm_device *dev) ...@@ -748,7 +757,7 @@ int i915_save_state(struct drm_device *dev)
i915_save_display(dev); i915_save_display(dev);
/* Interrupt state */ /* Interrupt state */
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
dev_priv->saveDEIER = I915_READ(DEIER); dev_priv->saveDEIER = I915_READ(DEIER);
dev_priv->saveDEIMR = I915_READ(DEIMR); dev_priv->saveDEIMR = I915_READ(DEIMR);
dev_priv->saveGTIER = I915_READ(GTIER); dev_priv->saveGTIER = I915_READ(GTIER);
...@@ -762,7 +771,7 @@ int i915_save_state(struct drm_device *dev) ...@@ -762,7 +771,7 @@ int i915_save_state(struct drm_device *dev)
dev_priv->saveIMR = I915_READ(IMR); dev_priv->saveIMR = I915_READ(IMR);
} }
if (IS_IRONLAKE_M(dev)) if (HAS_PCH_SPLIT(dev))
ironlake_disable_drps(dev); ironlake_disable_drps(dev);
/* Cache mode state */ /* Cache mode state */
...@@ -820,7 +829,7 @@ int i915_restore_state(struct drm_device *dev) ...@@ -820,7 +829,7 @@ int i915_restore_state(struct drm_device *dev)
i915_restore_display(dev); i915_restore_display(dev);
/* Interrupt state */ /* Interrupt state */
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(DEIER, dev_priv->saveDEIER); I915_WRITE(DEIER, dev_priv->saveDEIER);
I915_WRITE(DEIMR, dev_priv->saveDEIMR); I915_WRITE(DEIMR, dev_priv->saveDEIMR);
I915_WRITE(GTIER, dev_priv->saveGTIER); I915_WRITE(GTIER, dev_priv->saveGTIER);
...@@ -835,7 +844,7 @@ int i915_restore_state(struct drm_device *dev) ...@@ -835,7 +844,7 @@ int i915_restore_state(struct drm_device *dev)
/* Clock gating state */ /* Clock gating state */
intel_init_clock_gating(dev); intel_init_clock_gating(dev);
if (IS_IRONLAKE_M(dev)) if (HAS_PCH_SPLIT(dev))
ironlake_enable_drps(dev); ironlake_enable_drps(dev);
/* Cache mode state */ /* Cache mode state */
......
...@@ -160,19 +160,20 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) ...@@ -160,19 +160,20 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 adpa, temp; u32 adpa, temp;
bool ret; bool ret;
bool turn_off_dac = false;
temp = adpa = I915_READ(PCH_ADPA); temp = adpa = I915_READ(PCH_ADPA);
if (HAS_PCH_CPT(dev)) { if (HAS_PCH_SPLIT(dev))
/* Disable DAC before force detect */ turn_off_dac = true;
I915_WRITE(PCH_ADPA, adpa & ~ADPA_DAC_ENABLE);
(void)I915_READ(PCH_ADPA); adpa &= ~ADPA_CRT_HOTPLUG_MASK;
} else { if (turn_off_dac)
adpa &= ~ADPA_CRT_HOTPLUG_MASK; adpa &= ~ADPA_DAC_ENABLE;
/* disable HPD first */
I915_WRITE(PCH_ADPA, adpa); /* disable HPD first */
(void)I915_READ(PCH_ADPA); I915_WRITE(PCH_ADPA, adpa);
} (void)I915_READ(PCH_ADPA);
adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 | adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
ADPA_CRT_HOTPLUG_WARMUP_10MS | ADPA_CRT_HOTPLUG_WARMUP_10MS |
...@@ -185,10 +186,11 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) ...@@ -185,10 +186,11 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa); DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa);
I915_WRITE(PCH_ADPA, adpa); I915_WRITE(PCH_ADPA, adpa);
while ((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) != 0) if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
; 1000, 1))
DRM_ERROR("timed out waiting for FORCE_TRIGGER");
if (HAS_PCH_CPT(dev)) { if (turn_off_dac) {
I915_WRITE(PCH_ADPA, temp); I915_WRITE(PCH_ADPA, temp);
(void)I915_READ(PCH_ADPA); (void)I915_READ(PCH_ADPA);
} }
...@@ -237,17 +239,13 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) ...@@ -237,17 +239,13 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
for (i = 0; i < tries ; i++) { for (i = 0; i < tries ; i++) {
unsigned long timeout;
/* turn on the FORCE_DETECT */ /* turn on the FORCE_DETECT */
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
timeout = jiffies + msecs_to_jiffies(1000);
/* wait for FORCE_DETECT to go off */ /* wait for FORCE_DETECT to go off */
do { if (wait_for((I915_READ(PORT_HOTPLUG_EN) &
if (!(I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0,
CRT_HOTPLUG_FORCE_DETECT)) 1000, 1))
break; DRM_ERROR("timed out waiting for FORCE_DETECT to go off");
msleep(1);
} while (time_after(timeout, jiffies));
} }
stat = I915_READ(PORT_HOTPLUG_STAT); stat = I915_READ(PORT_HOTPLUG_STAT);
...@@ -331,7 +329,7 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder ...@@ -331,7 +329,7 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder
I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER); I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
/* Wait for next Vblank to substitue /* Wait for next Vblank to substitue
* border color for Color info */ * border color for Color info */
intel_wait_for_vblank(dev); intel_wait_for_vblank(dev, pipe);
st00 = I915_READ8(VGA_MSR_WRITE); st00 = I915_READ8(VGA_MSR_WRITE);
status = ((st00 & (1 << 4)) != 0) ? status = ((st00 & (1 << 4)) != 0) ?
connector_status_connected : connector_status_connected :
...@@ -508,17 +506,8 @@ static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs ...@@ -508,17 +506,8 @@ static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs
.best_encoder = intel_attached_encoder, .best_encoder = intel_attached_encoder,
}; };
static void intel_crt_enc_destroy(struct drm_encoder *encoder)
{
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
intel_i2c_destroy(intel_encoder->ddc_bus);
drm_encoder_cleanup(encoder);
kfree(intel_encoder);
}
static const struct drm_encoder_funcs intel_crt_enc_funcs = { static const struct drm_encoder_funcs intel_crt_enc_funcs = {
.destroy = intel_crt_enc_destroy, .destroy = intel_encoder_destroy,
}; };
void intel_crt_init(struct drm_device *dev) void intel_crt_init(struct drm_device *dev)
......
此差异已折叠。
...@@ -32,6 +32,20 @@ ...@@ -32,6 +32,20 @@
#include "drm_crtc.h" #include "drm_crtc.h"
#include "drm_crtc_helper.h" #include "drm_crtc_helper.h"
#define wait_for(COND, MS, W) ({ \
unsigned long timeout__ = jiffies + msecs_to_jiffies(MS); \
int ret__ = 0; \
while (! (COND)) { \
if (time_after(jiffies, timeout__)) { \
ret__ = -ETIMEDOUT; \
break; \
} \
if (W) msleep(W); \
} \
ret__; \
})
/* /*
* Display related stuff * Display related stuff
*/ */
...@@ -102,7 +116,6 @@ struct intel_encoder { ...@@ -102,7 +116,6 @@ struct intel_encoder {
struct i2c_adapter *ddc_bus; struct i2c_adapter *ddc_bus;
bool load_detect_temp; bool load_detect_temp;
bool needs_tv_clock; bool needs_tv_clock;
void *dev_priv;
void (*hot_plug)(struct intel_encoder *); void (*hot_plug)(struct intel_encoder *);
int crtc_mask; int crtc_mask;
int clone_mask; int clone_mask;
...@@ -110,7 +123,6 @@ struct intel_encoder { ...@@ -110,7 +123,6 @@ struct intel_encoder {
struct intel_connector { struct intel_connector {
struct drm_connector base; struct drm_connector base;
void *dev_priv;
}; };
struct intel_crtc; struct intel_crtc;
...@@ -156,7 +168,7 @@ struct intel_crtc { ...@@ -156,7 +168,7 @@ struct intel_crtc {
uint32_t cursor_addr; uint32_t cursor_addr;
int16_t cursor_x, cursor_y; int16_t cursor_x, cursor_y;
int16_t cursor_width, cursor_height; int16_t cursor_width, cursor_height;
bool cursor_visble; bool cursor_visible, cursor_on;
}; };
#define to_intel_crtc(x) container_of(x, struct intel_crtc, base) #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
...@@ -188,10 +200,18 @@ extern bool intel_dpd_is_edp(struct drm_device *dev); ...@@ -188,10 +200,18 @@ extern bool intel_dpd_is_edp(struct drm_device *dev);
extern void intel_edp_link_config (struct intel_encoder *, int *, int *); extern void intel_edp_link_config (struct intel_encoder *, int *, int *);
extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_mode);
extern void intel_pch_panel_fitting(struct drm_device *dev,
int fitting_mode,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
extern int intel_panel_fitter_pipe (struct drm_device *dev); extern int intel_panel_fitter_pipe (struct drm_device *dev);
extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_crtc_load_lut(struct drm_crtc *crtc);
extern void intel_encoder_prepare (struct drm_encoder *encoder); extern void intel_encoder_prepare (struct drm_encoder *encoder);
extern void intel_encoder_commit (struct drm_encoder *encoder); extern void intel_encoder_commit (struct drm_encoder *encoder);
extern void intel_encoder_destroy(struct drm_encoder *encoder);
extern struct drm_encoder *intel_attached_encoder(struct drm_connector *connector); extern struct drm_encoder *intel_attached_encoder(struct drm_connector *connector);
...@@ -199,7 +219,8 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, ...@@ -199,7 +219,8 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
struct drm_crtc *crtc); struct drm_crtc *crtc);
int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
extern void intel_wait_for_vblank(struct drm_device *dev); extern void intel_wait_for_vblank_off(struct drm_device *dev, int pipe);
extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe);
extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder, extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
struct drm_connector *connector, struct drm_connector *connector,
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#define CH7xxx_ADDR 0x76 #define CH7xxx_ADDR 0x76
#define TFP410_ADDR 0x38 #define TFP410_ADDR 0x38
static struct intel_dvo_device intel_dvo_devices[] = { static const struct intel_dvo_device intel_dvo_devices[] = {
{ {
.type = INTEL_DVO_CHIP_TMDS, .type = INTEL_DVO_CHIP_TMDS,
.name = "sil164", .name = "sil164",
...@@ -77,20 +77,33 @@ static struct intel_dvo_device intel_dvo_devices[] = { ...@@ -77,20 +77,33 @@ static struct intel_dvo_device intel_dvo_devices[] = {
} }
}; };
struct intel_dvo {
struct intel_encoder base;
struct intel_dvo_device dev;
struct drm_display_mode *panel_fixed_mode;
bool panel_wants_dither;
};
static struct intel_dvo *enc_to_intel_dvo(struct drm_encoder *encoder)
{
return container_of(enc_to_intel_encoder(encoder), struct intel_dvo, base);
}
static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)
{ {
struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct drm_i915_private *dev_priv = encoder->dev->dev_private;
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
struct intel_dvo_device *dvo = intel_encoder->dev_priv; u32 dvo_reg = intel_dvo->dev.dvo_reg;
u32 dvo_reg = dvo->dvo_reg;
u32 temp = I915_READ(dvo_reg); u32 temp = I915_READ(dvo_reg);
if (mode == DRM_MODE_DPMS_ON) { if (mode == DRM_MODE_DPMS_ON) {
I915_WRITE(dvo_reg, temp | DVO_ENABLE); I915_WRITE(dvo_reg, temp | DVO_ENABLE);
I915_READ(dvo_reg); I915_READ(dvo_reg);
dvo->dev_ops->dpms(dvo, mode); intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, mode);
} else { } else {
dvo->dev_ops->dpms(dvo, mode); intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, mode);
I915_WRITE(dvo_reg, temp & ~DVO_ENABLE); I915_WRITE(dvo_reg, temp & ~DVO_ENABLE);
I915_READ(dvo_reg); I915_READ(dvo_reg);
} }
...@@ -100,38 +113,36 @@ static int intel_dvo_mode_valid(struct drm_connector *connector, ...@@ -100,38 +113,36 @@ static int intel_dvo_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode) struct drm_display_mode *mode)
{ {
struct drm_encoder *encoder = intel_attached_encoder(connector); struct drm_encoder *encoder = intel_attached_encoder(connector);
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
struct intel_dvo_device *dvo = intel_encoder->dev_priv;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN) if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
return MODE_NO_DBLESCAN; return MODE_NO_DBLESCAN;
/* XXX: Validate clock range */ /* XXX: Validate clock range */
if (dvo->panel_fixed_mode) { if (intel_dvo->panel_fixed_mode) {
if (mode->hdisplay > dvo->panel_fixed_mode->hdisplay) if (mode->hdisplay > intel_dvo->panel_fixed_mode->hdisplay)
return MODE_PANEL; return MODE_PANEL;
if (mode->vdisplay > dvo->panel_fixed_mode->vdisplay) if (mode->vdisplay > intel_dvo->panel_fixed_mode->vdisplay)
return MODE_PANEL; return MODE_PANEL;
} }
return dvo->dev_ops->mode_valid(dvo, mode); return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode);
} }
static bool intel_dvo_mode_fixup(struct drm_encoder *encoder, static bool intel_dvo_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
{ {
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
struct intel_dvo_device *dvo = intel_encoder->dev_priv;
/* If we have timings from the BIOS for the panel, put them in /* If we have timings from the BIOS for the panel, put them in
* to the adjusted mode. The CRTC will be set up for this mode, * to the adjusted mode. The CRTC will be set up for this mode,
* with the panel scaling set up to source from the H/VDisplay * with the panel scaling set up to source from the H/VDisplay
* of the original mode. * of the original mode.
*/ */
if (dvo->panel_fixed_mode != NULL) { if (intel_dvo->panel_fixed_mode != NULL) {
#define C(x) adjusted_mode->x = dvo->panel_fixed_mode->x #define C(x) adjusted_mode->x = intel_dvo->panel_fixed_mode->x
C(hdisplay); C(hdisplay);
C(hsync_start); C(hsync_start);
C(hsync_end); C(hsync_end);
...@@ -145,8 +156,8 @@ static bool intel_dvo_mode_fixup(struct drm_encoder *encoder, ...@@ -145,8 +156,8 @@ static bool intel_dvo_mode_fixup(struct drm_encoder *encoder,
#undef C #undef C
} }
if (dvo->dev_ops->mode_fixup) if (intel_dvo->dev.dev_ops->mode_fixup)
return dvo->dev_ops->mode_fixup(dvo, mode, adjusted_mode); return intel_dvo->dev.dev_ops->mode_fixup(&intel_dvo->dev, mode, adjusted_mode);
return true; return true;
} }
...@@ -158,11 +169,10 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, ...@@ -158,11 +169,10 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
struct intel_dvo_device *dvo = intel_encoder->dev_priv;
int pipe = intel_crtc->pipe; int pipe = intel_crtc->pipe;
u32 dvo_val; u32 dvo_val;
u32 dvo_reg = dvo->dvo_reg, dvo_srcdim_reg; u32 dvo_reg = intel_dvo->dev.dvo_reg, dvo_srcdim_reg;
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
switch (dvo_reg) { switch (dvo_reg) {
...@@ -178,7 +188,7 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, ...@@ -178,7 +188,7 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder,
break; break;
} }
dvo->dev_ops->mode_set(dvo, mode, adjusted_mode); intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev, mode, adjusted_mode);
/* Save the data order, since I don't know what it should be set to. */ /* Save the data order, since I don't know what it should be set to. */
dvo_val = I915_READ(dvo_reg) & dvo_val = I915_READ(dvo_reg) &
...@@ -214,40 +224,38 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, ...@@ -214,40 +224,38 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder,
static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector) static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector)
{ {
struct drm_encoder *encoder = intel_attached_encoder(connector); struct drm_encoder *encoder = intel_attached_encoder(connector);
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
struct intel_dvo_device *dvo = intel_encoder->dev_priv;
return dvo->dev_ops->detect(dvo); return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
} }
static int intel_dvo_get_modes(struct drm_connector *connector) static int intel_dvo_get_modes(struct drm_connector *connector)
{ {
struct drm_encoder *encoder = intel_attached_encoder(connector); struct drm_encoder *encoder = intel_attached_encoder(connector);
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
struct intel_dvo_device *dvo = intel_encoder->dev_priv;
/* We should probably have an i2c driver get_modes function for those /* We should probably have an i2c driver get_modes function for those
* devices which will have a fixed set of modes determined by the chip * devices which will have a fixed set of modes determined by the chip
* (TV-out, for example), but for now with just TMDS and LVDS, * (TV-out, for example), but for now with just TMDS and LVDS,
* that's not the case. * that's not the case.
*/ */
intel_ddc_get_modes(connector, intel_encoder->ddc_bus); intel_ddc_get_modes(connector, intel_dvo->base.ddc_bus);
if (!list_empty(&connector->probed_modes)) if (!list_empty(&connector->probed_modes))
return 1; return 1;
if (intel_dvo->panel_fixed_mode != NULL) {
if (dvo->panel_fixed_mode != NULL) {
struct drm_display_mode *mode; struct drm_display_mode *mode;
mode = drm_mode_duplicate(connector->dev, dvo->panel_fixed_mode); mode = drm_mode_duplicate(connector->dev, intel_dvo->panel_fixed_mode);
if (mode) { if (mode) {
drm_mode_probed_add(connector, mode); drm_mode_probed_add(connector, mode);
return 1; return 1;
} }
} }
return 0; return 0;
} }
static void intel_dvo_destroy (struct drm_connector *connector) static void intel_dvo_destroy(struct drm_connector *connector)
{ {
drm_sysfs_connector_remove(connector); drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector); drm_connector_cleanup(connector);
...@@ -277,28 +285,20 @@ static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs ...@@ -277,28 +285,20 @@ static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs
static void intel_dvo_enc_destroy(struct drm_encoder *encoder) static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
{ {
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
struct intel_dvo_device *dvo = intel_encoder->dev_priv;
if (intel_dvo->dev.dev_ops->destroy)
if (dvo) { intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev);
if (dvo->dev_ops->destroy)
dvo->dev_ops->destroy(dvo); kfree(intel_dvo->panel_fixed_mode);
if (dvo->panel_fixed_mode)
kfree(dvo->panel_fixed_mode); intel_encoder_destroy(encoder);
}
if (intel_encoder->i2c_bus)
intel_i2c_destroy(intel_encoder->i2c_bus);
if (intel_encoder->ddc_bus)
intel_i2c_destroy(intel_encoder->ddc_bus);
drm_encoder_cleanup(encoder);
kfree(intel_encoder);
} }
static const struct drm_encoder_funcs intel_dvo_enc_funcs = { static const struct drm_encoder_funcs intel_dvo_enc_funcs = {
.destroy = intel_dvo_enc_destroy, .destroy = intel_dvo_enc_destroy,
}; };
/** /**
* Attempts to get a fixed panel timing for LVDS (currently only the i830). * Attempts to get a fixed panel timing for LVDS (currently only the i830).
* *
...@@ -306,15 +306,13 @@ static const struct drm_encoder_funcs intel_dvo_enc_funcs = { ...@@ -306,15 +306,13 @@ static const struct drm_encoder_funcs intel_dvo_enc_funcs = {
* chip being on DVOB/C and having multiple pipes. * chip being on DVOB/C and having multiple pipes.
*/ */
static struct drm_display_mode * static struct drm_display_mode *
intel_dvo_get_current_mode (struct drm_connector *connector) intel_dvo_get_current_mode(struct drm_connector *connector)
{ {
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_encoder *encoder = intel_attached_encoder(connector); struct drm_encoder *encoder = intel_attached_encoder(connector);
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
struct intel_dvo_device *dvo = intel_encoder->dev_priv; uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg);
uint32_t dvo_reg = dvo->dvo_reg;
uint32_t dvo_val = I915_READ(dvo_reg);
struct drm_display_mode *mode = NULL; struct drm_display_mode *mode = NULL;
/* If the DVO port is active, that'll be the LVDS, so we can pull out /* If the DVO port is active, that'll be the LVDS, so we can pull out
...@@ -327,7 +325,6 @@ intel_dvo_get_current_mode (struct drm_connector *connector) ...@@ -327,7 +325,6 @@ intel_dvo_get_current_mode (struct drm_connector *connector)
crtc = intel_get_crtc_from_pipe(dev, pipe); crtc = intel_get_crtc_from_pipe(dev, pipe);
if (crtc) { if (crtc) {
mode = intel_crtc_mode_get(dev, crtc); mode = intel_crtc_mode_get(dev, crtc);
if (mode) { if (mode) {
mode->type |= DRM_MODE_TYPE_PREFERRED; mode->type |= DRM_MODE_TYPE_PREFERRED;
if (dvo_val & DVO_HSYNC_ACTIVE_HIGH) if (dvo_val & DVO_HSYNC_ACTIVE_HIGH)
...@@ -337,28 +334,32 @@ intel_dvo_get_current_mode (struct drm_connector *connector) ...@@ -337,28 +334,32 @@ intel_dvo_get_current_mode (struct drm_connector *connector)
} }
} }
} }
return mode; return mode;
} }
void intel_dvo_init(struct drm_device *dev) void intel_dvo_init(struct drm_device *dev)
{ {
struct intel_encoder *intel_encoder; struct intel_encoder *intel_encoder;
struct intel_dvo *intel_dvo;
struct intel_connector *intel_connector; struct intel_connector *intel_connector;
struct intel_dvo_device *dvo;
struct i2c_adapter *i2cbus = NULL; struct i2c_adapter *i2cbus = NULL;
int ret = 0; int ret = 0;
int i; int i;
int encoder_type = DRM_MODE_ENCODER_NONE; int encoder_type = DRM_MODE_ENCODER_NONE;
intel_encoder = kzalloc (sizeof(struct intel_encoder), GFP_KERNEL);
if (!intel_encoder) intel_dvo = kzalloc(sizeof(struct intel_dvo), GFP_KERNEL);
if (!intel_dvo)
return; return;
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
if (!intel_connector) { if (!intel_connector) {
kfree(intel_encoder); kfree(intel_dvo);
return; return;
} }
intel_encoder = &intel_dvo->base;
/* Set up the DDC bus */ /* Set up the DDC bus */
intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D"); intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D");
if (!intel_encoder->ddc_bus) if (!intel_encoder->ddc_bus)
...@@ -367,10 +368,9 @@ void intel_dvo_init(struct drm_device *dev) ...@@ -367,10 +368,9 @@ void intel_dvo_init(struct drm_device *dev)
/* Now, try to find a controller */ /* Now, try to find a controller */
for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
struct drm_connector *connector = &intel_connector->base; struct drm_connector *connector = &intel_connector->base;
const struct intel_dvo_device *dvo = &intel_dvo_devices[i];
int gpio; int gpio;
dvo = &intel_dvo_devices[i];
/* Allow the I2C driver info to specify the GPIO to be used in /* Allow the I2C driver info to specify the GPIO to be used in
* special cases, but otherwise default to what's defined * special cases, but otherwise default to what's defined
* in the spec. * in the spec.
...@@ -393,11 +393,8 @@ void intel_dvo_init(struct drm_device *dev) ...@@ -393,11 +393,8 @@ void intel_dvo_init(struct drm_device *dev)
continue; continue;
} }
if (dvo->dev_ops!= NULL) intel_dvo->dev = *dvo;
ret = dvo->dev_ops->init(dvo, i2cbus); ret = dvo->dev_ops->init(&intel_dvo->dev, i2cbus);
else
ret = false;
if (!ret) if (!ret)
continue; continue;
...@@ -429,9 +426,6 @@ void intel_dvo_init(struct drm_device *dev) ...@@ -429,9 +426,6 @@ void intel_dvo_init(struct drm_device *dev)
connector->interlace_allowed = false; connector->interlace_allowed = false;
connector->doublescan_allowed = false; connector->doublescan_allowed = false;
intel_encoder->dev_priv = dvo;
intel_encoder->i2c_bus = i2cbus;
drm_encoder_init(dev, &intel_encoder->enc, drm_encoder_init(dev, &intel_encoder->enc,
&intel_dvo_enc_funcs, encoder_type); &intel_dvo_enc_funcs, encoder_type);
drm_encoder_helper_add(&intel_encoder->enc, drm_encoder_helper_add(&intel_encoder->enc,
...@@ -447,9 +441,9 @@ void intel_dvo_init(struct drm_device *dev) ...@@ -447,9 +441,9 @@ void intel_dvo_init(struct drm_device *dev)
* headers, likely), so for now, just get the current * headers, likely), so for now, just get the current
* mode being output through DVO. * mode being output through DVO.
*/ */
dvo->panel_fixed_mode = intel_dvo->panel_fixed_mode =
intel_dvo_get_current_mode(connector); intel_dvo_get_current_mode(connector);
dvo->panel_wants_dither = true; intel_dvo->panel_wants_dither = true;
} }
drm_sysfs_connector_add(connector); drm_sysfs_connector_add(connector);
...@@ -461,6 +455,6 @@ void intel_dvo_init(struct drm_device *dev) ...@@ -461,6 +455,6 @@ void intel_dvo_init(struct drm_device *dev)
if (i2cbus != NULL) if (i2cbus != NULL)
intel_i2c_destroy(i2cbus); intel_i2c_destroy(i2cbus);
free_intel: free_intel:
kfree(intel_encoder); kfree(intel_dvo);
kfree(intel_connector); kfree(intel_connector);
} }
...@@ -37,11 +37,17 @@ ...@@ -37,11 +37,17 @@
#include "i915_drm.h" #include "i915_drm.h"
#include "i915_drv.h" #include "i915_drv.h"
struct intel_hdmi_priv { struct intel_hdmi {
struct intel_encoder base;
u32 sdvox_reg; u32 sdvox_reg;
bool has_hdmi_sink; bool has_hdmi_sink;
}; };
static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
{
return container_of(enc_to_intel_encoder(encoder), struct intel_hdmi, base);
}
static void intel_hdmi_mode_set(struct drm_encoder *encoder, static void intel_hdmi_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
...@@ -50,8 +56,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, ...@@ -50,8 +56,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = encoder->crtc; struct drm_crtc *crtc = encoder->crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv;
u32 sdvox; u32 sdvox;
sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE; sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE;
...@@ -60,7 +65,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, ...@@ -60,7 +65,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
sdvox |= SDVO_HSYNC_ACTIVE_HIGH; sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
if (hdmi_priv->has_hdmi_sink) { if (intel_hdmi->has_hdmi_sink) {
sdvox |= SDVO_AUDIO_ENABLE; sdvox |= SDVO_AUDIO_ENABLE;
if (HAS_PCH_CPT(dev)) if (HAS_PCH_CPT(dev))
sdvox |= HDMI_MODE_SELECT; sdvox |= HDMI_MODE_SELECT;
...@@ -73,26 +78,25 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, ...@@ -73,26 +78,25 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
sdvox |= SDVO_PIPE_B_SELECT; sdvox |= SDVO_PIPE_B_SELECT;
} }
I915_WRITE(hdmi_priv->sdvox_reg, sdvox); I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
POSTING_READ(hdmi_priv->sdvox_reg); POSTING_READ(intel_hdmi->sdvox_reg);
} }
static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
{ {
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv;
u32 temp; u32 temp;
temp = I915_READ(hdmi_priv->sdvox_reg); temp = I915_READ(intel_hdmi->sdvox_reg);
/* HW workaround, need to toggle enable bit off and on for 12bpc, but /* HW workaround, need to toggle enable bit off and on for 12bpc, but
* we do this anyway which shows more stable in testing. * we do this anyway which shows more stable in testing.
*/ */
if (HAS_PCH_SPLIT(dev)) { if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(hdmi_priv->sdvox_reg, temp & ~SDVO_ENABLE); I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
POSTING_READ(hdmi_priv->sdvox_reg); POSTING_READ(intel_hdmi->sdvox_reg);
} }
if (mode != DRM_MODE_DPMS_ON) { if (mode != DRM_MODE_DPMS_ON) {
...@@ -101,15 +105,15 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) ...@@ -101,15 +105,15 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
temp |= SDVO_ENABLE; temp |= SDVO_ENABLE;
} }
I915_WRITE(hdmi_priv->sdvox_reg, temp); I915_WRITE(intel_hdmi->sdvox_reg, temp);
POSTING_READ(hdmi_priv->sdvox_reg); POSTING_READ(intel_hdmi->sdvox_reg);
/* HW workaround, need to write this twice for issue that may result /* HW workaround, need to write this twice for issue that may result
* in first write getting masked. * in first write getting masked.
*/ */
if (HAS_PCH_SPLIT(dev)) { if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(hdmi_priv->sdvox_reg, temp); I915_WRITE(intel_hdmi->sdvox_reg, temp);
POSTING_READ(hdmi_priv->sdvox_reg); POSTING_READ(intel_hdmi->sdvox_reg);
} }
} }
...@@ -138,19 +142,17 @@ static enum drm_connector_status ...@@ -138,19 +142,17 @@ static enum drm_connector_status
intel_hdmi_detect(struct drm_connector *connector) intel_hdmi_detect(struct drm_connector *connector)
{ {
struct drm_encoder *encoder = intel_attached_encoder(connector); struct drm_encoder *encoder = intel_attached_encoder(connector);
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv;
struct edid *edid = NULL; struct edid *edid = NULL;
enum drm_connector_status status = connector_status_disconnected; enum drm_connector_status status = connector_status_disconnected;
hdmi_priv->has_hdmi_sink = false; intel_hdmi->has_hdmi_sink = false;
edid = drm_get_edid(connector, edid = drm_get_edid(connector, intel_hdmi->base.ddc_bus);
intel_encoder->ddc_bus);
if (edid) { if (edid) {
if (edid->input & DRM_EDID_INPUT_DIGITAL) { if (edid->input & DRM_EDID_INPUT_DIGITAL) {
status = connector_status_connected; status = connector_status_connected;
hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid); intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
} }
connector->display_info.raw_edid = NULL; connector->display_info.raw_edid = NULL;
kfree(edid); kfree(edid);
...@@ -162,13 +164,13 @@ intel_hdmi_detect(struct drm_connector *connector) ...@@ -162,13 +164,13 @@ intel_hdmi_detect(struct drm_connector *connector)
static int intel_hdmi_get_modes(struct drm_connector *connector) static int intel_hdmi_get_modes(struct drm_connector *connector)
{ {
struct drm_encoder *encoder = intel_attached_encoder(connector); struct drm_encoder *encoder = intel_attached_encoder(connector);
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
/* We should parse the EDID data and find out if it's an HDMI sink so /* We should parse the EDID data and find out if it's an HDMI sink so
* we can send audio to it. * we can send audio to it.
*/ */
return intel_ddc_get_modes(connector, intel_encoder->ddc_bus); return intel_ddc_get_modes(connector, intel_hdmi->base.ddc_bus);
} }
static void intel_hdmi_destroy(struct drm_connector *connector) static void intel_hdmi_destroy(struct drm_connector *connector)
...@@ -199,18 +201,8 @@ static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs ...@@ -199,18 +201,8 @@ static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs
.best_encoder = intel_attached_encoder, .best_encoder = intel_attached_encoder,
}; };
static void intel_hdmi_enc_destroy(struct drm_encoder *encoder)
{
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
if (intel_encoder->i2c_bus)
intel_i2c_destroy(intel_encoder->i2c_bus);
drm_encoder_cleanup(encoder);
kfree(intel_encoder);
}
static const struct drm_encoder_funcs intel_hdmi_enc_funcs = { static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
.destroy = intel_hdmi_enc_destroy, .destroy = intel_encoder_destroy,
}; };
void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
...@@ -219,21 +211,19 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) ...@@ -219,21 +211,19 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
struct drm_connector *connector; struct drm_connector *connector;
struct intel_encoder *intel_encoder; struct intel_encoder *intel_encoder;
struct intel_connector *intel_connector; struct intel_connector *intel_connector;
struct intel_hdmi_priv *hdmi_priv; struct intel_hdmi *intel_hdmi;
intel_encoder = kcalloc(sizeof(struct intel_encoder) + intel_hdmi = kzalloc(sizeof(struct intel_hdmi), GFP_KERNEL);
sizeof(struct intel_hdmi_priv), 1, GFP_KERNEL); if (!intel_hdmi)
if (!intel_encoder)
return; return;
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
if (!intel_connector) { if (!intel_connector) {
kfree(intel_encoder); kfree(intel_hdmi);
return; return;
} }
hdmi_priv = (struct intel_hdmi_priv *)(intel_encoder + 1); intel_encoder = &intel_hdmi->base;
connector = &intel_connector->base; connector = &intel_connector->base;
drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA); DRM_MODE_CONNECTOR_HDMIA);
...@@ -274,8 +264,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) ...@@ -274,8 +264,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
if (!intel_encoder->ddc_bus) if (!intel_encoder->ddc_bus)
goto err_connector; goto err_connector;
hdmi_priv->sdvox_reg = sdvox_reg; intel_hdmi->sdvox_reg = sdvox_reg;
intel_encoder->dev_priv = hdmi_priv;
drm_encoder_init(dev, &intel_encoder->enc, &intel_hdmi_enc_funcs, drm_encoder_init(dev, &intel_encoder->enc, &intel_hdmi_enc_funcs,
DRM_MODE_ENCODER_TMDS); DRM_MODE_ENCODER_TMDS);
...@@ -298,7 +287,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) ...@@ -298,7 +287,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
err_connector: err_connector:
drm_connector_cleanup(connector); drm_connector_cleanup(connector);
kfree(intel_encoder); kfree(intel_hdmi);
kfree(intel_connector); kfree(intel_connector);
return; return;
......
...@@ -41,12 +41,18 @@ ...@@ -41,12 +41,18 @@
#include <linux/acpi.h> #include <linux/acpi.h>
/* Private structure for the integrated LVDS support */ /* Private structure for the integrated LVDS support */
struct intel_lvds_priv { struct intel_lvds {
struct intel_encoder base;
int fitting_mode; int fitting_mode;
u32 pfit_control; u32 pfit_control;
u32 pfit_pgm_ratios; u32 pfit_pgm_ratios;
}; };
static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder)
{
return container_of(enc_to_intel_encoder(encoder), struct intel_lvds, base);
}
/** /**
* Sets the backlight level. * Sets the backlight level.
* *
...@@ -90,7 +96,7 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev) ...@@ -90,7 +96,7 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
static void intel_lvds_set_power(struct drm_device *dev, bool on) static void intel_lvds_set_power(struct drm_device *dev, bool on)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp_status, ctl_reg, status_reg, lvds_reg; u32 ctl_reg, status_reg, lvds_reg;
if (HAS_PCH_SPLIT(dev)) { if (HAS_PCH_SPLIT(dev)) {
ctl_reg = PCH_PP_CONTROL; ctl_reg = PCH_PP_CONTROL;
...@@ -108,9 +114,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) ...@@ -108,9 +114,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on)
I915_WRITE(ctl_reg, I915_READ(ctl_reg) | I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
POWER_TARGET_ON); POWER_TARGET_ON);
do { if (wait_for(I915_READ(status_reg) & PP_ON, 1000, 0))
pp_status = I915_READ(status_reg); DRM_ERROR("timed out waiting to enable LVDS pipe");
} while ((pp_status & PP_ON) == 0);
intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
} else { } else {
...@@ -118,9 +123,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) ...@@ -118,9 +123,8 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on)
I915_WRITE(ctl_reg, I915_READ(ctl_reg) & I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
~POWER_TARGET_ON); ~POWER_TARGET_ON);
do { if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000, 0))
pp_status = I915_READ(status_reg); DRM_ERROR("timed out waiting for LVDS pipe to turn off");
} while (pp_status & PP_ON);
I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
POSTING_READ(lvds_reg); POSTING_READ(lvds_reg);
...@@ -219,9 +223,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, ...@@ -219,9 +223,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
struct drm_encoder *tmp_encoder; struct drm_encoder *tmp_encoder;
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv;
u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
/* Should never happen!! */ /* Should never happen!! */
...@@ -241,26 +244,20 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, ...@@ -241,26 +244,20 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
/* If we don't have a panel mode, there is nothing we can do */ /* If we don't have a panel mode, there is nothing we can do */
if (dev_priv->panel_fixed_mode == NULL) if (dev_priv->panel_fixed_mode == NULL)
return true; return true;
/* /*
* We have timings from the BIOS for the panel, put them in * We have timings from the BIOS for the panel, put them in
* to the adjusted mode. The CRTC will be set up for this mode, * to the adjusted mode. The CRTC will be set up for this mode,
* with the panel scaling set up to source from the H/VDisplay * with the panel scaling set up to source from the H/VDisplay
* of the original mode. * of the original mode.
*/ */
adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay; intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
adjusted_mode->hsync_start =
dev_priv->panel_fixed_mode->hsync_start; if (HAS_PCH_SPLIT(dev)) {
adjusted_mode->hsync_end = intel_pch_panel_fitting(dev, intel_lvds->fitting_mode,
dev_priv->panel_fixed_mode->hsync_end; mode, adjusted_mode);
adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal; return true;
adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay; }
adjusted_mode->vsync_start =
dev_priv->panel_fixed_mode->vsync_start;
adjusted_mode->vsync_end =
dev_priv->panel_fixed_mode->vsync_end;
adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal;
adjusted_mode->clock = dev_priv->panel_fixed_mode->clock;
drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
/* Make sure pre-965s set dither correctly */ /* Make sure pre-965s set dither correctly */
if (!IS_I965G(dev)) { if (!IS_I965G(dev)) {
...@@ -273,10 +270,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, ...@@ -273,10 +270,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
adjusted_mode->vdisplay == mode->vdisplay) adjusted_mode->vdisplay == mode->vdisplay)
goto out; goto out;
/* full screen scale for now */
if (HAS_PCH_SPLIT(dev))
goto out;
/* 965+ wants fuzzy fitting */ /* 965+ wants fuzzy fitting */
if (IS_I965G(dev)) if (IS_I965G(dev))
pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
...@@ -288,12 +281,10 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, ...@@ -288,12 +281,10 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
* to register description and PRM. * to register description and PRM.
* Change the value here to see the borders for debugging * Change the value here to see the borders for debugging
*/ */
if (!HAS_PCH_SPLIT(dev)) { I915_WRITE(BCLRPAT_A, 0);
I915_WRITE(BCLRPAT_A, 0); I915_WRITE(BCLRPAT_B, 0);
I915_WRITE(BCLRPAT_B, 0);
}
switch (lvds_priv->fitting_mode) { switch (intel_lvds->fitting_mode) {
case DRM_MODE_SCALE_CENTER: case DRM_MODE_SCALE_CENTER:
/* /*
* For centered modes, we have to calculate border widths & * For centered modes, we have to calculate border widths &
...@@ -378,8 +369,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, ...@@ -378,8 +369,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
} }
out: out:
lvds_priv->pfit_control = pfit_control; intel_lvds->pfit_control = pfit_control;
lvds_priv->pfit_pgm_ratios = pfit_pgm_ratios; intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
dev_priv->lvds_border_bits = border; dev_priv->lvds_border_bits = border;
/* /*
...@@ -427,8 +418,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, ...@@ -427,8 +418,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
{ {
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv;
/* /*
* The LVDS pin pair will already have been turned on in the * The LVDS pin pair will already have been turned on in the
...@@ -444,8 +434,8 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, ...@@ -444,8 +434,8 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
* screen. Should be enabled before the pipe is enabled, according to * screen. Should be enabled before the pipe is enabled, according to
* register description and PRM. * register description and PRM.
*/ */
I915_WRITE(PFIT_PGM_RATIOS, lvds_priv->pfit_pgm_ratios); I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
I915_WRITE(PFIT_CONTROL, lvds_priv->pfit_control); I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
} }
/** /**
...@@ -600,18 +590,17 @@ static int intel_lvds_set_property(struct drm_connector *connector, ...@@ -600,18 +590,17 @@ static int intel_lvds_set_property(struct drm_connector *connector,
connector->encoder) { connector->encoder) {
struct drm_crtc *crtc = connector->encoder->crtc; struct drm_crtc *crtc = connector->encoder->crtc;
struct drm_encoder *encoder = connector->encoder; struct drm_encoder *encoder = connector->encoder;
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv;
if (value == DRM_MODE_SCALE_NONE) { if (value == DRM_MODE_SCALE_NONE) {
DRM_DEBUG_KMS("no scaling not supported\n"); DRM_DEBUG_KMS("no scaling not supported\n");
return 0; return 0;
} }
if (lvds_priv->fitting_mode == value) { if (intel_lvds->fitting_mode == value) {
/* the LVDS scaling property is not changed */ /* the LVDS scaling property is not changed */
return 0; return 0;
} }
lvds_priv->fitting_mode = value; intel_lvds->fitting_mode = value;
if (crtc && crtc->enabled) { if (crtc && crtc->enabled) {
/* /*
* If the CRTC is enabled, the display will be changed * If the CRTC is enabled, the display will be changed
...@@ -647,19 +636,8 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = { ...@@ -647,19 +636,8 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = {
.destroy = intel_lvds_destroy, .destroy = intel_lvds_destroy,
}; };
static void intel_lvds_enc_destroy(struct drm_encoder *encoder)
{
struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
if (intel_encoder->ddc_bus)
intel_i2c_destroy(intel_encoder->ddc_bus);
drm_encoder_cleanup(encoder);
kfree(intel_encoder);
}
static const struct drm_encoder_funcs intel_lvds_enc_funcs = { static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
.destroy = intel_lvds_enc_destroy, .destroy = intel_encoder_destroy,
}; };
static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id) static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
...@@ -843,13 +821,13 @@ static int lvds_is_present_in_vbt(struct drm_device *dev) ...@@ -843,13 +821,13 @@ static int lvds_is_present_in_vbt(struct drm_device *dev)
void intel_lvds_init(struct drm_device *dev) void intel_lvds_init(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_lvds *intel_lvds;
struct intel_encoder *intel_encoder; struct intel_encoder *intel_encoder;
struct intel_connector *intel_connector; struct intel_connector *intel_connector;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_display_mode *scan; /* *modes, *bios_mode; */ struct drm_display_mode *scan; /* *modes, *bios_mode; */
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct intel_lvds_priv *lvds_priv;
u32 lvds; u32 lvds;
int pipe, gpio = GPIOC; int pipe, gpio = GPIOC;
...@@ -872,20 +850,20 @@ void intel_lvds_init(struct drm_device *dev) ...@@ -872,20 +850,20 @@ void intel_lvds_init(struct drm_device *dev)
gpio = PCH_GPIOC; gpio = PCH_GPIOC;
} }
intel_encoder = kzalloc(sizeof(struct intel_encoder) + intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL);
sizeof(struct intel_lvds_priv), GFP_KERNEL); if (!intel_lvds) {
if (!intel_encoder) {
return; return;
} }
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
if (!intel_connector) { if (!intel_connector) {
kfree(intel_encoder); kfree(intel_lvds);
return; return;
} }
connector = &intel_connector->base; intel_encoder = &intel_lvds->base;
encoder = &intel_encoder->enc; encoder = &intel_encoder->enc;
connector = &intel_connector->base;
drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs, drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs,
DRM_MODE_CONNECTOR_LVDS); DRM_MODE_CONNECTOR_LVDS);
...@@ -905,8 +883,6 @@ void intel_lvds_init(struct drm_device *dev) ...@@ -905,8 +883,6 @@ void intel_lvds_init(struct drm_device *dev)
connector->interlace_allowed = false; connector->interlace_allowed = false;
connector->doublescan_allowed = false; connector->doublescan_allowed = false;
lvds_priv = (struct intel_lvds_priv *)(intel_encoder + 1);
intel_encoder->dev_priv = lvds_priv;
/* create the scaling mode property */ /* create the scaling mode property */
drm_mode_create_scaling_mode_property(dev); drm_mode_create_scaling_mode_property(dev);
/* /*
...@@ -916,7 +892,7 @@ void intel_lvds_init(struct drm_device *dev) ...@@ -916,7 +892,7 @@ void intel_lvds_init(struct drm_device *dev)
drm_connector_attach_property(&intel_connector->base, drm_connector_attach_property(&intel_connector->base,
dev->mode_config.scaling_mode_property, dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_ASPECT); DRM_MODE_SCALE_ASPECT);
lvds_priv->fitting_mode = DRM_MODE_SCALE_ASPECT; intel_lvds->fitting_mode = DRM_MODE_SCALE_ASPECT;
/* /*
* LVDS discovery: * LVDS discovery:
* 1) check for EDID on DDC * 1) check for EDID on DDC
...@@ -1024,6 +1000,6 @@ void intel_lvds_init(struct drm_device *dev) ...@@ -1024,6 +1000,6 @@ void intel_lvds_init(struct drm_device *dev)
intel_i2c_destroy(intel_encoder->ddc_bus); intel_i2c_destroy(intel_encoder->ddc_bus);
drm_connector_cleanup(connector); drm_connector_cleanup(connector);
drm_encoder_cleanup(encoder); drm_encoder_cleanup(encoder);
kfree(intel_encoder); kfree(intel_lvds);
kfree(intel_connector); kfree(intel_connector);
} }
...@@ -1367,7 +1367,8 @@ void intel_setup_overlay(struct drm_device *dev) ...@@ -1367,7 +1367,8 @@ void intel_setup_overlay(struct drm_device *dev)
overlay->flip_addr = overlay->reg_bo->gtt_offset; overlay->flip_addr = overlay->reg_bo->gtt_offset;
} else { } else {
ret = i915_gem_attach_phys_object(dev, reg_bo, ret = i915_gem_attach_phys_object(dev, reg_bo,
I915_GEM_PHYS_OVERLAY_REGS); I915_GEM_PHYS_OVERLAY_REGS,
0);
if (ret) { if (ret) {
DRM_ERROR("failed to attach phys overlay regs\n"); DRM_ERROR("failed to attach phys overlay regs\n");
goto out_free_bo; goto out_free_bo;
...@@ -1416,3 +1417,99 @@ void intel_cleanup_overlay(struct drm_device *dev) ...@@ -1416,3 +1417,99 @@ void intel_cleanup_overlay(struct drm_device *dev)
kfree(dev_priv->overlay); kfree(dev_priv->overlay);
} }
} }
struct intel_overlay_error_state {
struct overlay_registers regs;
unsigned long base;
u32 dovsta;
u32 isr;
};
struct intel_overlay_error_state *
intel_overlay_capture_error_state(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_overlay *overlay = dev_priv->overlay;
struct intel_overlay_error_state *error;
struct overlay_registers __iomem *regs;
if (!overlay || !overlay->active)
return NULL;
error = kmalloc(sizeof(*error), GFP_ATOMIC);
if (error == NULL)
return NULL;
error->dovsta = I915_READ(DOVSTA);
error->isr = I915_READ(ISR);
if (OVERLAY_NONPHYSICAL(overlay->dev))
error->base = (long) overlay->reg_bo->gtt_offset;
else
error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr;
regs = intel_overlay_map_regs_atomic(overlay);
if (!regs)
goto err;
memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
intel_overlay_unmap_regs_atomic(overlay);
return error;
err:
kfree(error);
return NULL;
}
void
intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error)
{
seq_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
error->dovsta, error->isr);
seq_printf(m, " Register file at 0x%08lx:\n",
error->base);
#define P(x) seq_printf(m, " " #x ": 0x%08x\n", error->regs.x)
P(OBUF_0Y);
P(OBUF_1Y);
P(OBUF_0U);
P(OBUF_0V);
P(OBUF_1U);
P(OBUF_1V);
P(OSTRIDE);
P(YRGB_VPH);
P(UV_VPH);
P(HORZ_PH);
P(INIT_PHS);
P(DWINPOS);
P(DWINSZ);
P(SWIDTH);
P(SWIDTHSW);
P(SHEIGHT);
P(YRGBSCALE);
P(UVSCALE);
P(OCLRC0);
P(OCLRC1);
P(DCLRKV);
P(DCLRKM);
P(SCLRKVH);
P(SCLRKVL);
P(SCLRKEN);
P(OCONFIG);
P(OCMD);
P(OSTART_0Y);
P(OSTART_1Y);
P(OSTART_0U);
P(OSTART_0V);
P(OSTART_1U);
P(OSTART_1V);
P(OTILEOFF_0Y);
P(OTILEOFF_1Y);
P(OTILEOFF_0U);
P(OTILEOFF_0V);
P(OTILEOFF_1U);
P(OTILEOFF_1V);
P(FASTHSCALE);
P(UVSCALEV);
#undef P
}
/*
* Copyright © 2006-2010 Intel Corporation
* Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Eric Anholt <eric@anholt.net>
* Dave Airlie <airlied@linux.ie>
* Jesse Barnes <jesse.barnes@intel.com>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "intel_drv.h"
void
intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_mode)
{
adjusted_mode->hdisplay = fixed_mode->hdisplay;
adjusted_mode->hsync_start = fixed_mode->hsync_start;
adjusted_mode->hsync_end = fixed_mode->hsync_end;
adjusted_mode->htotal = fixed_mode->htotal;
adjusted_mode->vdisplay = fixed_mode->vdisplay;
adjusted_mode->vsync_start = fixed_mode->vsync_start;
adjusted_mode->vsync_end = fixed_mode->vsync_end;
adjusted_mode->vtotal = fixed_mode->vtotal;
adjusted_mode->clock = fixed_mode->clock;
drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
}
/* adjusted_mode has been preset to be the panel's fixed mode */
void
intel_pch_panel_fitting(struct drm_device *dev,
int fitting_mode,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int x, y, width, height;
x = y = width = height = 0;
/* Native modes don't need fitting */
if (adjusted_mode->hdisplay == mode->hdisplay &&
adjusted_mode->vdisplay == mode->vdisplay)
goto done;
switch (fitting_mode) {
case DRM_MODE_SCALE_CENTER:
width = mode->hdisplay;
height = mode->vdisplay;
x = (adjusted_mode->hdisplay - width + 1)/2;
y = (adjusted_mode->vdisplay - height + 1)/2;
break;
case DRM_MODE_SCALE_ASPECT:
/* Scale but preserve the aspect ratio */
{
u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
if (scaled_width > scaled_height) { /* pillar */
width = scaled_height / mode->vdisplay;
x = (adjusted_mode->hdisplay - width + 1) / 2;
y = 0;
height = adjusted_mode->vdisplay;
} else if (scaled_width < scaled_height) { /* letter */
height = scaled_width / mode->hdisplay;
y = (adjusted_mode->vdisplay - height + 1) / 2;
x = 0;
width = adjusted_mode->hdisplay;
} else {
x = y = 0;
width = adjusted_mode->hdisplay;
height = adjusted_mode->vdisplay;
}
}
break;
default:
case DRM_MODE_SCALE_FULLSCREEN:
x = y = 0;
width = adjusted_mode->hdisplay;
height = adjusted_mode->vdisplay;
break;
}
done:
dev_priv->pch_pf_pos = (x << 16) | y;
dev_priv->pch_pf_size = (width << 16) | height;
}
...@@ -26,7 +26,6 @@ struct intel_ring_buffer { ...@@ -26,7 +26,6 @@ struct intel_ring_buffer {
unsigned int head; unsigned int head;
unsigned int tail; unsigned int tail;
unsigned int space; unsigned int space;
u32 next_seqno;
struct intel_hw_status_page status_page; struct intel_hw_status_page status_page;
u32 irq_gem_seqno; /* last seq seem at irq time */ u32 irq_gem_seqno; /* last seq seem at irq time */
...@@ -106,8 +105,16 @@ int intel_wrap_ring_buffer(struct drm_device *dev, ...@@ -106,8 +105,16 @@ int intel_wrap_ring_buffer(struct drm_device *dev,
struct intel_ring_buffer *ring); struct intel_ring_buffer *ring);
void intel_ring_begin(struct drm_device *dev, void intel_ring_begin(struct drm_device *dev,
struct intel_ring_buffer *ring, int n); struct intel_ring_buffer *ring, int n);
void intel_ring_emit(struct drm_device *dev,
struct intel_ring_buffer *ring, u32 data); static inline void intel_ring_emit(struct drm_device *dev,
struct intel_ring_buffer *ring,
unsigned int data)
{
unsigned int *virt = ring->virtual_start + ring->tail;
*virt = data;
ring->tail += 4;
}
void intel_fill_struct(struct drm_device *dev, void intel_fill_struct(struct drm_device *dev,
struct intel_ring_buffer *ring, struct intel_ring_buffer *ring,
void *data, void *data,
......
此差异已折叠。
...@@ -312,7 +312,7 @@ struct intel_sdvo_set_target_input_args { ...@@ -312,7 +312,7 @@ struct intel_sdvo_set_target_input_args {
# define SDVO_CLOCK_RATE_MULT_4X (1 << 3) # define SDVO_CLOCK_RATE_MULT_4X (1 << 3)
#define SDVO_CMD_GET_SUPPORTED_TV_FORMATS 0x27 #define SDVO_CMD_GET_SUPPORTED_TV_FORMATS 0x27
/** 5 bytes of bit flags for TV formats shared by all TV format functions */ /** 6 bytes of bit flags for TV formats shared by all TV format functions */
struct intel_sdvo_tv_format { struct intel_sdvo_tv_format {
unsigned int ntsc_m:1; unsigned int ntsc_m:1;
unsigned int ntsc_j:1; unsigned int ntsc_j:1;
...@@ -596,32 +596,32 @@ struct intel_sdvo_enhancements_reply { ...@@ -596,32 +596,32 @@ struct intel_sdvo_enhancements_reply {
unsigned int overscan_h:1; unsigned int overscan_h:1;
unsigned int overscan_v:1; unsigned int overscan_v:1;
unsigned int position_h:1; unsigned int hpos:1;
unsigned int position_v:1; unsigned int vpos:1;
unsigned int sharpness:1; unsigned int sharpness:1;
unsigned int dot_crawl:1; unsigned int dot_crawl:1;
unsigned int dither:1; unsigned int dither:1;
unsigned int max_tv_chroma_filter:1; unsigned int tv_chroma_filter:1;
unsigned int max_tv_luma_filter:1; unsigned int tv_luma_filter:1;
} __attribute__((packed)); } __attribute__((packed));
/* Picture enhancement limits below are dependent on the current TV format, /* Picture enhancement limits below are dependent on the current TV format,
* and thus need to be queried and set after it. * and thus need to be queried and set after it.
*/ */
#define SDVO_CMD_GET_MAX_FLICKER_FITER 0x4d #define SDVO_CMD_GET_MAX_FLICKER_FILTER 0x4d
#define SDVO_CMD_GET_MAX_ADAPTIVE_FLICKER_FITER 0x7b #define SDVO_CMD_GET_MAX_FLICKER_FILTER_ADAPTIVE 0x7b
#define SDVO_CMD_GET_MAX_2D_FLICKER_FITER 0x52 #define SDVO_CMD_GET_MAX_FLICKER_FILTER_2D 0x52
#define SDVO_CMD_GET_MAX_SATURATION 0x55 #define SDVO_CMD_GET_MAX_SATURATION 0x55
#define SDVO_CMD_GET_MAX_HUE 0x58 #define SDVO_CMD_GET_MAX_HUE 0x58
#define SDVO_CMD_GET_MAX_BRIGHTNESS 0x5b #define SDVO_CMD_GET_MAX_BRIGHTNESS 0x5b
#define SDVO_CMD_GET_MAX_CONTRAST 0x5e #define SDVO_CMD_GET_MAX_CONTRAST 0x5e
#define SDVO_CMD_GET_MAX_OVERSCAN_H 0x61 #define SDVO_CMD_GET_MAX_OVERSCAN_H 0x61
#define SDVO_CMD_GET_MAX_OVERSCAN_V 0x64 #define SDVO_CMD_GET_MAX_OVERSCAN_V 0x64
#define SDVO_CMD_GET_MAX_POSITION_H 0x67 #define SDVO_CMD_GET_MAX_HPOS 0x67
#define SDVO_CMD_GET_MAX_POSITION_V 0x6a #define SDVO_CMD_GET_MAX_VPOS 0x6a
#define SDVO_CMD_GET_MAX_SHARPNESS_V 0x6d #define SDVO_CMD_GET_MAX_SHARPNESS 0x6d
#define SDVO_CMD_GET_MAX_TV_CHROMA 0x74 #define SDVO_CMD_GET_MAX_TV_CHROMA_FILTER 0x74
#define SDVO_CMD_GET_MAX_TV_LUMA 0x77 #define SDVO_CMD_GET_MAX_TV_LUMA_FILTER 0x77
struct intel_sdvo_enhancement_limits_reply { struct intel_sdvo_enhancement_limits_reply {
u16 max_value; u16 max_value;
u16 default_value; u16 default_value;
...@@ -638,10 +638,10 @@ struct intel_sdvo_enhancement_limits_reply { ...@@ -638,10 +638,10 @@ struct intel_sdvo_enhancement_limits_reply {
#define SDVO_CMD_GET_FLICKER_FILTER 0x4e #define SDVO_CMD_GET_FLICKER_FILTER 0x4e
#define SDVO_CMD_SET_FLICKER_FILTER 0x4f #define SDVO_CMD_SET_FLICKER_FILTER 0x4f
#define SDVO_CMD_GET_ADAPTIVE_FLICKER_FITER 0x50 #define SDVO_CMD_GET_FLICKER_FILTER_ADAPTIVE 0x50
#define SDVO_CMD_SET_ADAPTIVE_FLICKER_FITER 0x51 #define SDVO_CMD_SET_FLICKER_FILTER_ADAPTIVE 0x51
#define SDVO_CMD_GET_2D_FLICKER_FITER 0x53 #define SDVO_CMD_GET_FLICKER_FILTER_2D 0x53
#define SDVO_CMD_SET_2D_FLICKER_FITER 0x54 #define SDVO_CMD_SET_FLICKER_FILTER_2D 0x54
#define SDVO_CMD_GET_SATURATION 0x56 #define SDVO_CMD_GET_SATURATION 0x56
#define SDVO_CMD_SET_SATURATION 0x57 #define SDVO_CMD_SET_SATURATION 0x57
#define SDVO_CMD_GET_HUE 0x59 #define SDVO_CMD_GET_HUE 0x59
...@@ -654,16 +654,16 @@ struct intel_sdvo_enhancement_limits_reply { ...@@ -654,16 +654,16 @@ struct intel_sdvo_enhancement_limits_reply {
#define SDVO_CMD_SET_OVERSCAN_H 0x63 #define SDVO_CMD_SET_OVERSCAN_H 0x63
#define SDVO_CMD_GET_OVERSCAN_V 0x65 #define SDVO_CMD_GET_OVERSCAN_V 0x65
#define SDVO_CMD_SET_OVERSCAN_V 0x66 #define SDVO_CMD_SET_OVERSCAN_V 0x66
#define SDVO_CMD_GET_POSITION_H 0x68 #define SDVO_CMD_GET_HPOS 0x68
#define SDVO_CMD_SET_POSITION_H 0x69 #define SDVO_CMD_SET_HPOS 0x69
#define SDVO_CMD_GET_POSITION_V 0x6b #define SDVO_CMD_GET_VPOS 0x6b
#define SDVO_CMD_SET_POSITION_V 0x6c #define SDVO_CMD_SET_VPOS 0x6c
#define SDVO_CMD_GET_SHARPNESS 0x6e #define SDVO_CMD_GET_SHARPNESS 0x6e
#define SDVO_CMD_SET_SHARPNESS 0x6f #define SDVO_CMD_SET_SHARPNESS 0x6f
#define SDVO_CMD_GET_TV_CHROMA 0x75 #define SDVO_CMD_GET_TV_CHROMA_FILTER 0x75
#define SDVO_CMD_SET_TV_CHROMA 0x76 #define SDVO_CMD_SET_TV_CHROMA_FILTER 0x76
#define SDVO_CMD_GET_TV_LUMA 0x78 #define SDVO_CMD_GET_TV_LUMA_FILTER 0x78
#define SDVO_CMD_SET_TV_LUMA 0x79 #define SDVO_CMD_SET_TV_LUMA_FILTER 0x79
struct intel_sdvo_enhancements_arg { struct intel_sdvo_enhancements_arg {
u16 value; u16 value;
}__attribute__((packed)); }__attribute__((packed));
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册