aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2009-09-10 18:28:06 -0400
committerEric Anholt <eric@anholt.net>2009-09-10 22:46:07 -0400
commit8082400327d8d2ca54254b593644942bed0edd25 (patch)
tree43a32ac4e56e985341e2109d2c4d545d3d6df6cb /drivers/gpu
parent06324194eee97a51b5f172270df49ec39192d6cc (diff)
drm/i915: framebuffer compression for pre-GM45
This patch adds framebuffer compression (good for about ~0.5W power savings in the best case) support for pre-GM45 chips. GM45+ have a new, more flexible FBC scheme that will be added in a separate patch. FBC can't always be enabled: the compressed buffer must be physically contiguous and reside in stolen space. So if you have a large display and a small amount of stolen memory, you may not be able to take advantage of FBC. In some cases, a BIOS setting controls how much stolen space is available. Increasing this to 8 or 16M can help. Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c161
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h12
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h1
-rw-r--r--drivers/gpu/drm/i915/intel_display.c222
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h5
5 files changed, 382 insertions, 19 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 9909505d070a..5a6b731c5529 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -921,7 +921,8 @@ static int i915_get_bridge_dev(struct drm_device *dev)
921 * how much was set aside so we can use it for our own purposes. 921 * how much was set aside so we can use it for our own purposes.
922 */ 922 */
923static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size, 923static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
924 uint32_t *preallocated_size) 924 uint32_t *preallocated_size,
925 uint32_t *start)
925{ 926{
926 struct drm_i915_private *dev_priv = dev->dev_private; 927 struct drm_i915_private *dev_priv = dev->dev_private;
927 u16 tmp = 0; 928 u16 tmp = 0;
@@ -1008,11 +1009,148 @@ static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
1008 return -1; 1009 return -1;
1009 } 1010 }
1010 *preallocated_size = stolen - overhead; 1011 *preallocated_size = stolen - overhead;
1012 *start = overhead;
1011 1013
1012 return 0; 1014 return 0;
1013} 1015}
1014 1016
1017#define PTE_ADDRESS_MASK 0xfffff000
1018#define PTE_ADDRESS_MASK_HIGH 0x000000f0 /* i915+ */
1019#define PTE_MAPPING_TYPE_UNCACHED (0 << 1)
1020#define PTE_MAPPING_TYPE_DCACHE (1 << 1) /* i830 only */
1021#define PTE_MAPPING_TYPE_CACHED (3 << 1)
1022#define PTE_MAPPING_TYPE_MASK (3 << 1)
1023#define PTE_VALID (1 << 0)
1024
1025/**
1026 * i915_gtt_to_phys - take a GTT address and turn it into a physical one
1027 * @dev: drm device
1028 * @gtt_addr: address to translate
1029 *
1030 * Some chip functions require allocations from stolen space but need the
1031 * physical address of the memory in question. We use this routine
1032 * to get a physical address suitable for register programming from a given
1033 * GTT address.
1034 */
1035static unsigned long i915_gtt_to_phys(struct drm_device *dev,
1036 unsigned long gtt_addr)
1037{
1038 unsigned long *gtt;
1039 unsigned long entry, phys;
1040 int gtt_bar = IS_I9XX(dev) ? 0 : 1;
1041 int gtt_offset, gtt_size;
1042
1043 if (IS_I965G(dev)) {
1044 if (IS_G4X(dev) || IS_IGDNG(dev)) {
1045 gtt_offset = 2*1024*1024;
1046 gtt_size = 2*1024*1024;
1047 } else {
1048 gtt_offset = 512*1024;
1049 gtt_size = 512*1024;
1050 }
1051 } else {
1052 gtt_bar = 3;
1053 gtt_offset = 0;
1054 gtt_size = pci_resource_len(dev->pdev, gtt_bar);
1055 }
1056
1057 gtt = ioremap_wc(pci_resource_start(dev->pdev, gtt_bar) + gtt_offset,
1058 gtt_size);
1059 if (!gtt) {
1060 DRM_ERROR("ioremap of GTT failed\n");
1061 return 0;
1062 }
1063
1064 entry = *(volatile u32 *)(gtt + (gtt_addr / 1024));
1065
1066 DRM_DEBUG("GTT addr: 0x%08lx, PTE: 0x%08lx\n", gtt_addr, entry);
1067
1068 /* Mask out these reserved bits on this hardware. */
1069 if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev) ||
1070 IS_I945G(dev) || IS_I945GM(dev)) {
1071 entry &= ~PTE_ADDRESS_MASK_HIGH;
1072 }
1073
1074 /* If it's not a mapping type we know, then bail. */
1075 if ((entry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_UNCACHED &&
1076 (entry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_CACHED) {
1077 iounmap(gtt);
1078 return 0;
1079 }
1080
1081 if (!(entry & PTE_VALID)) {
1082 DRM_ERROR("bad GTT entry in stolen space\n");
1083 iounmap(gtt);
1084 return 0;
1085 }
1086
1087 iounmap(gtt);
1088
1089 phys =(entry & PTE_ADDRESS_MASK) |
1090 ((uint64_t)(entry & PTE_ADDRESS_MASK_HIGH) << (32 - 4));
1091
1092 DRM_DEBUG("GTT addr: 0x%08lx, phys addr: 0x%08lx\n", gtt_addr, phys);
1093
1094 return phys;
1095}
1096
1097static void i915_warn_stolen(struct drm_device *dev)
1098{
1099 DRM_ERROR("not enough stolen space for compressed buffer, disabling\n");
1100 DRM_ERROR("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n");
1101}
1102
1103static void i915_setup_compression(struct drm_device *dev, int size)
1104{
1105 struct drm_i915_private *dev_priv = dev->dev_private;
1106 struct drm_mm_node *compressed_fb, *compressed_llb;
1107 unsigned long cfb_base, ll_base;
1108
1109 /* Leave 1M for line length buffer & misc. */
1110 compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0);
1111 if (!compressed_fb) {
1112 i915_warn_stolen(dev);
1113 return;
1114 }
1115
1116 compressed_fb = drm_mm_get_block(compressed_fb, size, 4096);
1117 if (!compressed_fb) {
1118 i915_warn_stolen(dev);
1119 return;
1120 }
1121
1122 compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096, 4096, 0);
1123 if (!compressed_llb) {
1124 i915_warn_stolen(dev);
1125 return;
1126 }
1127
1128 compressed_llb = drm_mm_get_block(compressed_fb, 4096, 4096);
1129 if (!compressed_llb) {
1130 i915_warn_stolen(dev);
1131 return;
1132 }
1133
1134 dev_priv->cfb_size = size;
1135
1136 cfb_base = i915_gtt_to_phys(dev, compressed_fb->start);
1137 ll_base = i915_gtt_to_phys(dev, compressed_llb->start);
1138 if (!cfb_base || !ll_base) {
1139 DRM_ERROR("failed to get stolen phys addr, disabling FBC\n");
1140 drm_mm_put_block(compressed_fb);
1141 drm_mm_put_block(compressed_llb);
1142 }
1143
1144 i8xx_disable_fbc(dev);
1145
1146 DRM_DEBUG("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base,
1147 ll_base, size >> 20);
1148 I915_WRITE(FBC_CFB_BASE, cfb_base);
1149 I915_WRITE(FBC_LL_BASE, ll_base);
1150}
1151
1015static int i915_load_modeset_init(struct drm_device *dev, 1152static int i915_load_modeset_init(struct drm_device *dev,
1153 unsigned long prealloc_start,
1016 unsigned long prealloc_size, 1154 unsigned long prealloc_size,
1017 unsigned long agp_size) 1155 unsigned long agp_size)
1018{ 1156{
@@ -1033,6 +1171,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
1033 1171
1034 /* Basic memrange allocator for stolen space (aka vram) */ 1172 /* Basic memrange allocator for stolen space (aka vram) */
1035 drm_mm_init(&dev_priv->vram, 0, prealloc_size); 1173 drm_mm_init(&dev_priv->vram, 0, prealloc_size);
1174 DRM_INFO("set up %ldM of stolen space\n", prealloc_size / (1024*1024));
1036 1175
1037 /* Let GEM Manage from end of prealloc space to end of aperture. 1176 /* Let GEM Manage from end of prealloc space to end of aperture.
1038 * 1177 *
@@ -1049,6 +1188,19 @@ static int i915_load_modeset_init(struct drm_device *dev,
1049 if (ret) 1188 if (ret)
1050 goto out; 1189 goto out;
1051 1190
1191 /* Try to set up FBC with a reasonable compressed buffer size */
1192 if (IS_MOBILE(dev) && (IS_I9XX(dev) || IS_I965G(dev)) &&
1193 i915_powersave) {
1194 int cfb_size;
1195
1196 /* Try to get an 8M buffer... */
1197 if (prealloc_size > (9*1024*1024))
1198 cfb_size = 8*1024*1024;
1199 else /* fall back to 7/8 of the stolen space */
1200 cfb_size = prealloc_size * 7 / 8;
1201 i915_setup_compression(dev, cfb_size);
1202 }
1203
1052 /* Allow hardware batchbuffers unless told otherwise. 1204 /* Allow hardware batchbuffers unless told otherwise.
1053 */ 1205 */
1054 dev_priv->allow_batchbuffer = 1; 1206 dev_priv->allow_batchbuffer = 1;
@@ -1161,7 +1313,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
1161 struct drm_i915_private *dev_priv = dev->dev_private; 1313 struct drm_i915_private *dev_priv = dev->dev_private;
1162 resource_size_t base, size; 1314 resource_size_t base, size;
1163 int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1; 1315 int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;
1164 uint32_t agp_size, prealloc_size; 1316 uint32_t agp_size, prealloc_size, prealloc_start;
1165 1317
1166 /* i915 has 4 more counters */ 1318 /* i915 has 4 more counters */
1167 dev->counters += 4; 1319 dev->counters += 4;
@@ -1215,7 +1367,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
1215 "performance may suffer.\n"); 1367 "performance may suffer.\n");
1216 } 1368 }
1217 1369
1218 ret = i915_probe_agp(dev, &agp_size, &prealloc_size); 1370 ret = i915_probe_agp(dev, &agp_size, &prealloc_size, &prealloc_start);
1219 if (ret) 1371 if (ret)
1220 goto out_iomapfree; 1372 goto out_iomapfree;
1221 1373
@@ -1282,7 +1434,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
1282 } 1434 }
1283 1435
1284 if (drm_core_check_feature(dev, DRIVER_MODESET)) { 1436 if (drm_core_check_feature(dev, DRIVER_MODESET)) {
1285 ret = i915_load_modeset_init(dev, prealloc_size, agp_size); 1437 ret = i915_load_modeset_init(dev, prealloc_start,
1438 prealloc_size, agp_size);
1286 if (ret < 0) { 1439 if (ret < 0) {
1287 DRM_ERROR("failed to init modeset\n"); 1440 DRM_ERROR("failed to init modeset\n");
1288 goto out_workqueue_free; 1441 goto out_workqueue_free;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f2b8d27aef2a..0344afd841c4 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -48,6 +48,11 @@ enum pipe {
48 PIPE_B, 48 PIPE_B,
49}; 49};
50 50
51enum plane {
52 PLANE_A = 0,
53 PLANE_B,
54};
55
51#define I915_NUM_PIPE 2 56#define I915_NUM_PIPE 2
52 57
53/* Interface history: 58/* Interface history:
@@ -202,6 +207,11 @@ typedef struct drm_i915_private {
202 207
203 struct drm_mm vram; 208 struct drm_mm vram;
204 209
210 unsigned long cfb_size;
211 unsigned long cfb_pitch;
212 int cfb_fence;
213 int cfb_plane;
214
205 int irq_enabled; 215 int irq_enabled;
206 216
207 struct intel_opregion opregion; 217 struct intel_opregion opregion;
@@ -768,6 +778,7 @@ static inline void opregion_enable_asle(struct drm_device *dev) { return; }
768/* modesetting */ 778/* modesetting */
769extern void intel_modeset_init(struct drm_device *dev); 779extern void intel_modeset_init(struct drm_device *dev);
770extern void intel_modeset_cleanup(struct drm_device *dev); 780extern void intel_modeset_cleanup(struct drm_device *dev);
781extern void i8xx_disable_fbc(struct drm_device *dev);
771 782
772/** 783/**
773 * Lock test for when it's just for synchronization of ring access. 784 * Lock test for when it's just for synchronization of ring access.
@@ -918,6 +929,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
918 929
919#define HAS_FW_BLC(dev) (IS_I9XX(dev) || IS_G4X(dev) || IS_IGDNG(dev)) 930#define HAS_FW_BLC(dev) (IS_I9XX(dev) || IS_G4X(dev) || IS_IGDNG(dev))
920#define HAS_PIPE_CXSR(dev) (IS_G4X(dev) || IS_IGDNG(dev)) 931#define HAS_PIPE_CXSR(dev) (IS_G4X(dev) || IS_IGDNG(dev))
932#define I915_HAS_FBC(dev) (IS_I9XX(dev) || IS_I965G(dev))
921 933
922#define PRIMARY_RINGBUFFER_SIZE (128*1024) 934#define PRIMARY_RINGBUFFER_SIZE (128*1024)
923 935
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index e38cd21161c8..f7c2de8fdf09 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -343,6 +343,7 @@
343#define FBC_CTL_PLANEA (0<<0) 343#define FBC_CTL_PLANEA (0<<0)
344#define FBC_CTL_PLANEB (1<<0) 344#define FBC_CTL_PLANEB (1<<0)
345#define FBC_FENCE_OFF 0x0321b 345#define FBC_FENCE_OFF 0x0321b
346#define FBC_TAG 0x03300
346 347
347#define FBC_LL_SIZE (1536) 348#define FBC_LL_SIZE (1536)
348 349
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 92e0aae7070a..cadb9efdfb1b 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -954,6 +954,174 @@ intel_wait_for_vblank(struct drm_device *dev)
954 mdelay(20); 954 mdelay(20);
955} 955}
956 956
957/* Parameters have changed, update FBC info */
958static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
959{
960 struct drm_device *dev = crtc->dev;
961 struct drm_i915_private *dev_priv = dev->dev_private;
962 struct drm_framebuffer *fb = crtc->fb;
963 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
964 struct drm_i915_gem_object *obj_priv = intel_fb->obj->driver_private;
965 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
966 int plane, i;
967 u32 fbc_ctl, fbc_ctl2;
968
969 dev_priv->cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
970
971 if (fb->pitch < dev_priv->cfb_pitch)
972 dev_priv->cfb_pitch = fb->pitch;
973
974 /* FBC_CTL wants 64B units */
975 dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
976 dev_priv->cfb_fence = obj_priv->fence_reg;
977 dev_priv->cfb_plane = intel_crtc->plane;
978 plane = dev_priv->cfb_plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB;
979
980 /* Clear old tags */
981 for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
982 I915_WRITE(FBC_TAG + (i * 4), 0);
983
984 /* Set it up... */
985 fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | plane;
986 if (obj_priv->tiling_mode != I915_TILING_NONE)
987 fbc_ctl2 |= FBC_CTL_CPU_FENCE;
988 I915_WRITE(FBC_CONTROL2, fbc_ctl2);
989 I915_WRITE(FBC_FENCE_OFF, crtc->y);
990
991 /* enable it... */
992 fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC;
993 fbc_ctl |= (dev_priv->cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
994 fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
995 if (obj_priv->tiling_mode != I915_TILING_NONE)
996 fbc_ctl |= dev_priv->cfb_fence;
997 I915_WRITE(FBC_CONTROL, fbc_ctl);
998
999 DRM_DEBUG("enabled FBC, pitch %ld, yoff %d, plane %d, ",
1000 dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
1001}
1002
1003void i8xx_disable_fbc(struct drm_device *dev)
1004{
1005 struct drm_i915_private *dev_priv = dev->dev_private;
1006 u32 fbc_ctl;
1007
1008 /* Disable compression */
1009 fbc_ctl = I915_READ(FBC_CONTROL);
1010 fbc_ctl &= ~FBC_CTL_EN;
1011 I915_WRITE(FBC_CONTROL, fbc_ctl);
1012
1013 /* Wait for compressing bit to clear */
1014 while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING)
1015 ; /* nothing */
1016
1017 intel_wait_for_vblank(dev);
1018
1019 DRM_DEBUG("disabled FBC\n");
1020}
1021
1022static bool i8xx_fbc_enabled(struct drm_crtc *crtc)
1023{
1024 struct drm_device *dev = crtc->dev;
1025 struct drm_i915_private *dev_priv = dev->dev_private;
1026
1027 return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
1028}
1029
1030/**
1031 * intel_update_fbc - enable/disable FBC as needed
1032 * @crtc: CRTC to point the compressor at
1033 * @mode: mode in use
1034 *
1035 * Set up the framebuffer compression hardware at mode set time. We
1036 * enable it if possible:
1037 * - plane A only (on pre-965)
1038 * - no pixel mulitply/line duplication
1039 * - no alpha buffer discard
1040 * - no dual wide
1041 * - framebuffer <= 2048 in width, 1536 in height
1042 *
1043 * We can't assume that any compression will take place (worst case),
1044 * so the compressed buffer has to be the same size as the uncompressed
1045 * one. It also must reside (along with the line length buffer) in
1046 * stolen memory.
1047 *
1048 * We need to enable/disable FBC on a global basis.
1049 */
1050static void intel_update_fbc(struct drm_crtc *crtc,
1051 struct drm_display_mode *mode)
1052{
1053 struct drm_device *dev = crtc->dev;
1054 struct drm_i915_private *dev_priv = dev->dev_private;
1055 struct drm_framebuffer *fb = crtc->fb;
1056 struct intel_framebuffer *intel_fb;
1057 struct drm_i915_gem_object *obj_priv;
1058 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1059 int plane = intel_crtc->plane;
1060
1061 if (!i915_powersave)
1062 return;
1063
1064 if (!crtc->fb)
1065 return;
1066
1067 intel_fb = to_intel_framebuffer(fb);
1068 obj_priv = intel_fb->obj->driver_private;
1069
1070 /*
1071 * If FBC is already on, we just have to verify that we can
1072 * keep it that way...
1073 * Need to disable if:
1074 * - changing FBC params (stride, fence, mode)
1075 * - new fb is too large to fit in compressed buffer
1076 * - going to an unsupported config (interlace, pixel multiply, etc.)
1077 */
1078 if (intel_fb->obj->size > dev_priv->cfb_size) {
1079 DRM_DEBUG("framebuffer too large, disabling compression\n");
1080 goto out_disable;
1081 }
1082 if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
1083 (mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
1084 DRM_DEBUG("mode incompatible with compression, disabling\n");
1085 goto out_disable;
1086 }
1087 if ((mode->hdisplay > 2048) ||
1088 (mode->vdisplay > 1536)) {
1089 DRM_DEBUG("mode too large for compression, disabling\n");
1090 goto out_disable;
1091 }
1092 if (IS_I9XX(dev) && plane != 0) {
1093 DRM_DEBUG("plane not 0, disabling compression\n");
1094 goto out_disable;
1095 }
1096 if (obj_priv->tiling_mode != I915_TILING_X) {
1097 DRM_DEBUG("framebuffer not tiled, disabling compression\n");
1098 goto out_disable;
1099 }
1100
1101 if (i8xx_fbc_enabled(crtc)) {
1102 /* We can re-enable it in this case, but need to update pitch */
1103 if (fb->pitch > dev_priv->cfb_pitch)
1104 i8xx_disable_fbc(dev);
1105 if (obj_priv->fence_reg != dev_priv->cfb_fence)
1106 i8xx_disable_fbc(dev);
1107 if (plane != dev_priv->cfb_plane)
1108 i8xx_disable_fbc(dev);
1109 }
1110
1111 if (!i8xx_fbc_enabled(crtc)) {
1112 /* Now try to turn it back on if possible */
1113 i8xx_enable_fbc(crtc, 500);
1114 }
1115
1116 return;
1117
1118out_disable:
1119 DRM_DEBUG("unsupported config, disabling FBC\n");
1120 /* Multiple disables should be harmless */
1121 if (i8xx_fbc_enabled(crtc))
1122 i8xx_disable_fbc(dev);
1123}
1124
957static int 1125static int
958intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, 1126intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
959 struct drm_framebuffer *old_fb) 1127 struct drm_framebuffer *old_fb)
@@ -966,12 +1134,13 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
966 struct drm_i915_gem_object *obj_priv; 1134 struct drm_i915_gem_object *obj_priv;
967 struct drm_gem_object *obj; 1135 struct drm_gem_object *obj;
968 int pipe = intel_crtc->pipe; 1136 int pipe = intel_crtc->pipe;
1137 int plane = intel_crtc->plane;
969 unsigned long Start, Offset; 1138 unsigned long Start, Offset;
970 int dspbase = (pipe == 0 ? DSPAADDR : DSPBADDR); 1139 int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR);
971 int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); 1140 int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF);
972 int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE; 1141 int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
973 int dsptileoff = (pipe == 0 ? DSPATILEOFF : DSPBTILEOFF); 1142 int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF);
974 int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; 1143 int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
975 u32 dspcntr, alignment; 1144 u32 dspcntr, alignment;
976 int ret; 1145 int ret;
977 1146
@@ -981,12 +1150,12 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
981 return 0; 1150 return 0;
982 } 1151 }
983 1152
984 switch (pipe) { 1153 switch (plane) {
985 case 0: 1154 case 0:
986 case 1: 1155 case 1:
987 break; 1156 break;
988 default: 1157 default:
989 DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); 1158 DRM_ERROR("Can't update plane %d in SAREA\n", plane);
990 return -EINVAL; 1159 return -EINVAL;
991 } 1160 }
992 1161
@@ -1114,6 +1283,9 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
1114 master_priv->sarea_priv->pipeA_y = y; 1283 master_priv->sarea_priv->pipeA_y = y;
1115 } 1284 }
1116 1285
1286 if (I915_HAS_FBC(dev) && (IS_I965G(dev) || plane == 0))
1287 intel_update_fbc(crtc, &crtc->mode);
1288
1117 return 0; 1289 return 0;
1118} 1290}
1119 1291
@@ -1534,9 +1706,10 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
1534 struct drm_i915_private *dev_priv = dev->dev_private; 1706 struct drm_i915_private *dev_priv = dev->dev_private;
1535 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 1707 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1536 int pipe = intel_crtc->pipe; 1708 int pipe = intel_crtc->pipe;
1709 int plane = intel_crtc->plane;
1537 int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; 1710 int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
1538 int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; 1711 int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
1539 int dspbase_reg = (pipe == 0) ? DSPAADDR : DSPBADDR; 1712 int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
1540 int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; 1713 int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
1541 u32 temp; 1714 u32 temp;
1542 1715
@@ -1579,6 +1752,9 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
1579 1752
1580 intel_crtc_load_lut(crtc); 1753 intel_crtc_load_lut(crtc);
1581 1754
1755 if (I915_HAS_FBC(dev) && (IS_I965G(dev) || plane == 0))
1756 intel_update_fbc(crtc, &crtc->mode);
1757
1582 /* Give the overlay scaler a chance to enable if it's on this pipe */ 1758 /* Give the overlay scaler a chance to enable if it's on this pipe */
1583 //intel_crtc_dpms_video(crtc, true); TODO 1759 //intel_crtc_dpms_video(crtc, true); TODO
1584 intel_update_watermarks(dev); 1760 intel_update_watermarks(dev);
@@ -1588,6 +1764,9 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
1588 /* Give the overlay scaler a chance to disable if it's on this pipe */ 1764 /* Give the overlay scaler a chance to disable if it's on this pipe */
1589 //intel_crtc_dpms_video(crtc, FALSE); TODO 1765 //intel_crtc_dpms_video(crtc, FALSE); TODO
1590 1766
1767 if (dev_priv->cfb_plane == plane)
1768 i8xx_disable_fbc(dev);
1769
1591 /* Disable the VGA plane that we never use */ 1770 /* Disable the VGA plane that we never use */
1592 i915_disable_vga(dev); 1771 i915_disable_vga(dev);
1593 1772
@@ -2325,10 +2504,11 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
2325 struct drm_i915_private *dev_priv = dev->dev_private; 2504 struct drm_i915_private *dev_priv = dev->dev_private;
2326 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 2505 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
2327 int pipe = intel_crtc->pipe; 2506 int pipe = intel_crtc->pipe;
2507 int plane = intel_crtc->plane;
2328 int fp_reg = (pipe == 0) ? FPA0 : FPB0; 2508 int fp_reg = (pipe == 0) ? FPA0 : FPB0;
2329 int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; 2509 int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
2330 int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD; 2510 int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
2331 int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; 2511 int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
2332 int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; 2512 int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
2333 int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; 2513 int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
2334 int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; 2514 int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
@@ -2336,8 +2516,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
2336 int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; 2516 int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
2337 int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; 2517 int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
2338 int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; 2518 int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
2339 int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE; 2519 int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE;
2340 int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS; 2520 int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS;
2341 int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; 2521 int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
2342 int refclk, num_outputs = 0; 2522 int refclk, num_outputs = 0;
2343 intel_clock_t clock, reduced_clock; 2523 intel_clock_t clock, reduced_clock;
@@ -2570,7 +2750,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
2570 enable color space conversion */ 2750 enable color space conversion */
2571 if (!IS_IGDNG(dev)) { 2751 if (!IS_IGDNG(dev)) {
2572 if (pipe == 0) 2752 if (pipe == 0)
2573 dspcntr |= DISPPLANE_SEL_PIPE_A; 2753 dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
2574 else 2754 else
2575 dspcntr |= DISPPLANE_SEL_PIPE_B; 2755 dspcntr |= DISPPLANE_SEL_PIPE_B;
2576 } 2756 }
@@ -2739,6 +2919,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
2739 /* Flush the plane changes */ 2919 /* Flush the plane changes */
2740 ret = intel_pipe_set_base(crtc, x, y, old_fb); 2920 ret = intel_pipe_set_base(crtc, x, y, old_fb);
2741 2921
2922 if (I915_HAS_FBC(dev) && (IS_I965G(dev) || plane == 0))
2923 intel_update_fbc(crtc, &crtc->mode);
2742 intel_update_watermarks(dev); 2924 intel_update_watermarks(dev);
2743 2925
2744 drm_vblank_post_modeset(dev, pipe); 2926 drm_vblank_post_modeset(dev, pipe);
@@ -2783,6 +2965,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
2783 struct drm_gem_object *bo; 2965 struct drm_gem_object *bo;
2784 struct drm_i915_gem_object *obj_priv; 2966 struct drm_i915_gem_object *obj_priv;
2785 int pipe = intel_crtc->pipe; 2967 int pipe = intel_crtc->pipe;
2968 int plane = intel_crtc->plane;
2786 uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; 2969 uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR;
2787 uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; 2970 uint32_t base = (pipe == 0) ? CURABASE : CURBBASE;
2788 uint32_t temp = I915_READ(control); 2971 uint32_t temp = I915_READ(control);
@@ -2868,6 +3051,10 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
2868 i915_gem_object_unpin(intel_crtc->cursor_bo); 3051 i915_gem_object_unpin(intel_crtc->cursor_bo);
2869 drm_gem_object_unreference(intel_crtc->cursor_bo); 3052 drm_gem_object_unreference(intel_crtc->cursor_bo);
2870 } 3053 }
3054
3055 if (I915_HAS_FBC(dev) && (IS_I965G(dev) || plane == 0))
3056 intel_update_fbc(crtc, &crtc->mode);
3057
2871 mutex_unlock(&dev->struct_mutex); 3058 mutex_unlock(&dev->struct_mutex);
2872 3059
2873 intel_crtc->cursor_addr = addr; 3060 intel_crtc->cursor_addr = addr;
@@ -3549,6 +3736,14 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
3549 intel_crtc->lut_b[i] = i; 3736 intel_crtc->lut_b[i] = i;
3550 } 3737 }
3551 3738
3739 /* Swap pipes & planes for FBC on pre-965 */
3740 intel_crtc->pipe = pipe;
3741 intel_crtc->plane = pipe;
3742 if (IS_MOBILE(dev) && (IS_I9XX(dev) && !IS_I965G(dev))) {
3743 DRM_DEBUG("swapping pipes & planes for FBC\n");
3744 intel_crtc->plane = ((pipe == 0) ? 1 : 0);
3745 }
3746
3552 intel_crtc->cursor_addr = 0; 3747 intel_crtc->cursor_addr = 0;
3553 intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF; 3748 intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF;
3554 drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); 3749 drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
@@ -3909,6 +4104,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
3909 4104
3910 mutex_unlock(&dev->struct_mutex); 4105 mutex_unlock(&dev->struct_mutex);
3911 4106
4107 i8xx_disable_fbc(dev);
3912 drm_mode_config_cleanup(dev); 4108 drm_mode_config_cleanup(dev);
3913} 4109}
3914 4110
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index b9e47f1e1cc0..7478196390b4 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -28,6 +28,7 @@
28#include <linux/i2c.h> 28#include <linux/i2c.h>
29#include <linux/i2c-id.h> 29#include <linux/i2c-id.h>
30#include <linux/i2c-algo-bit.h> 30#include <linux/i2c-algo-bit.h>
31#include "i915_drv.h"
31#include "drm_crtc.h" 32#include "drm_crtc.h"
32 33
33#include "drm_crtc_helper.h" 34#include "drm_crtc_helper.h"
@@ -110,8 +111,8 @@ struct intel_output {
110 111
111struct intel_crtc { 112struct intel_crtc {
112 struct drm_crtc base; 113 struct drm_crtc base;
113 int pipe; 114 enum pipe pipe;
114 int plane; 115 enum plane plane;
115 struct drm_gem_object *cursor_bo; 116 struct drm_gem_object *cursor_bo;
116 uint32_t cursor_addr; 117 uint32_t cursor_addr;
117 u8 lut_r[256], lut_g[256], lut_b[256]; 118 u8 lut_r[256], lut_g[256], lut_b[256];