diff options
author | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-09-10 18:28:06 -0400 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2009-09-10 22:46:07 -0400 |
commit | 8082400327d8d2ca54254b593644942bed0edd25 (patch) | |
tree | 43a32ac4e56e985341e2109d2c4d545d3d6df6cb /drivers/gpu | |
parent | 06324194eee97a51b5f172270df49ec39192d6cc (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.c | 161 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 222 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 5 |
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 | */ |
923 | static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size, | 923 | static 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 | */ | ||
1035 | static 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 | |||
1097 | static 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 | |||
1103 | static 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 | |||
1015 | static int i915_load_modeset_init(struct drm_device *dev, | 1152 | static 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 | ||
51 | enum 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 */ |
769 | extern void intel_modeset_init(struct drm_device *dev); | 779 | extern void intel_modeset_init(struct drm_device *dev); |
770 | extern void intel_modeset_cleanup(struct drm_device *dev); | 780 | extern void intel_modeset_cleanup(struct drm_device *dev); |
781 | extern 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 */ | ||
958 | static 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 | |||
1003 | void 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 | |||
1022 | static 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 | */ | ||
1050 | static 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 | |||
1118 | out_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 | |||
957 | static int | 1125 | static int |
958 | intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, | 1126 | intel_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 | ||
111 | struct intel_crtc { | 112 | struct 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]; |