aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_dma.c
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/drm/i915/i915_dma.c
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/drm/i915/i915_dma.c')
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c161
1 files changed, 157 insertions, 4 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 9909505d070..5a6b731c552 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;