diff options
67 files changed, 18476 insertions, 472 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index a8b33c2ec8d2..5130b72d593c 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | menuconfig DRM | 7 | menuconfig DRM |
| 8 | tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" | 8 | tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" |
| 9 | depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU | 9 | depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU |
| 10 | select I2C | ||
| 11 | select I2C_ALGOBIT | ||
| 10 | help | 12 | help |
| 11 | Kernel-level support for the Direct Rendering Infrastructure (DRI) | 13 | Kernel-level support for the Direct Rendering Infrastructure (DRI) |
| 12 | introduced in XFree86 4.0. If you say Y here, you need to select | 14 | introduced in XFree86 4.0. If you say Y here, you need to select |
| @@ -65,6 +67,10 @@ config DRM_I830 | |||
| 65 | will load the correct one. | 67 | will load the correct one. |
| 66 | 68 | ||
| 67 | config DRM_I915 | 69 | config DRM_I915 |
| 70 | select FB_CFB_FILLRECT | ||
| 71 | select FB_CFB_COPYAREA | ||
| 72 | select FB_CFB_IMAGEBLIT | ||
| 73 | depends on FB | ||
| 68 | tristate "i915 driver" | 74 | tristate "i915 driver" |
| 69 | help | 75 | help |
| 70 | Choose this option if you have a system that has Intel 830M, 845G, | 76 | Choose this option if you have a system that has Intel 830M, 845G, |
| @@ -76,6 +82,17 @@ config DRM_I915 | |||
| 76 | 82 | ||
| 77 | endchoice | 83 | endchoice |
| 78 | 84 | ||
| 85 | config DRM_I915_KMS | ||
| 86 | bool "Enable modesetting on intel by default" | ||
| 87 | depends on DRM_I915 | ||
| 88 | help | ||
| 89 | Choose this option if you want kernel modesetting enabled by default, | ||
| 90 | and you have a new enough userspace to support this. Running old | ||
| 91 | userspaces with this enabled will cause pain. Note that this causes | ||
| 92 | the driver to bind to PCI devices, which precludes loading things | ||
| 93 | like intelfb. | ||
| 94 | |||
| 95 | |||
| 79 | config DRM_MGA | 96 | config DRM_MGA |
| 80 | tristate "Matrox g200/g400" | 97 | tristate "Matrox g200/g400" |
| 81 | depends on DRM | 98 | depends on DRM |
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 74da99495e21..30022c4a5c12 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
| @@ -9,7 +9,8 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ | |||
| 9 | drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \ | 9 | drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \ |
| 10 | drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ | 10 | drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ |
| 11 | drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ | 11 | drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ |
| 12 | drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o | 12 | drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \ |
| 13 | drm_crtc.o drm_crtc_helper.o drm_modes.o drm_edid.o | ||
| 13 | 14 | ||
| 14 | drm-$(CONFIG_COMPAT) += drm_ioc32.o | 15 | drm-$(CONFIG_COMPAT) += drm_ioc32.o |
| 15 | 16 | ||
diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index a73462723d2d..ca7a9ef5007b 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c | |||
| @@ -45,14 +45,15 @@ | |||
| 45 | * the one with matching magic number, while holding the drm_device::struct_mutex | 45 | * the one with matching magic number, while holding the drm_device::struct_mutex |
| 46 | * lock. | 46 | * lock. |
| 47 | */ | 47 | */ |
| 48 | static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic) | 48 | static struct drm_file *drm_find_file(struct drm_master *master, drm_magic_t magic) |
| 49 | { | 49 | { |
| 50 | struct drm_file *retval = NULL; | 50 | struct drm_file *retval = NULL; |
| 51 | struct drm_magic_entry *pt; | 51 | struct drm_magic_entry *pt; |
| 52 | struct drm_hash_item *hash; | 52 | struct drm_hash_item *hash; |
| 53 | struct drm_device *dev = master->minor->dev; | ||
| 53 | 54 | ||
| 54 | mutex_lock(&dev->struct_mutex); | 55 | mutex_lock(&dev->struct_mutex); |
| 55 | if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) { | 56 | if (!drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) { |
| 56 | pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); | 57 | pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); |
| 57 | retval = pt->priv; | 58 | retval = pt->priv; |
| 58 | } | 59 | } |
| @@ -71,11 +72,11 @@ static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic | |||
| 71 | * associated the magic number hash key in drm_device::magiclist, while holding | 72 | * associated the magic number hash key in drm_device::magiclist, while holding |
| 72 | * the drm_device::struct_mutex lock. | 73 | * the drm_device::struct_mutex lock. |
| 73 | */ | 74 | */ |
| 74 | static int drm_add_magic(struct drm_device * dev, struct drm_file * priv, | 75 | static int drm_add_magic(struct drm_master *master, struct drm_file *priv, |
| 75 | drm_magic_t magic) | 76 | drm_magic_t magic) |
| 76 | { | 77 | { |
| 77 | struct drm_magic_entry *entry; | 78 | struct drm_magic_entry *entry; |
| 78 | 79 | struct drm_device *dev = master->minor->dev; | |
| 79 | DRM_DEBUG("%d\n", magic); | 80 | DRM_DEBUG("%d\n", magic); |
| 80 | 81 | ||
| 81 | entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC); | 82 | entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC); |
| @@ -83,11 +84,10 @@ static int drm_add_magic(struct drm_device * dev, struct drm_file * priv, | |||
| 83 | return -ENOMEM; | 84 | return -ENOMEM; |
| 84 | memset(entry, 0, sizeof(*entry)); | 85 | memset(entry, 0, sizeof(*entry)); |
| 85 | entry->priv = priv; | 86 | entry->priv = priv; |
| 86 | |||
| 87 | entry->hash_item.key = (unsigned long)magic; | 87 | entry->hash_item.key = (unsigned long)magic; |
| 88 | mutex_lock(&dev->struct_mutex); | 88 | mutex_lock(&dev->struct_mutex); |
| 89 | drm_ht_insert_item(&dev->magiclist, &entry->hash_item); | 89 | drm_ht_insert_item(&master->magiclist, &entry->hash_item); |
| 90 | list_add_tail(&entry->head, &dev->magicfree); | 90 | list_add_tail(&entry->head, &master->magicfree); |
| 91 | mutex_unlock(&dev->struct_mutex); | 91 | mutex_unlock(&dev->struct_mutex); |
| 92 | 92 | ||
| 93 | return 0; | 93 | return 0; |
| @@ -102,20 +102,21 @@ static int drm_add_magic(struct drm_device * dev, struct drm_file * priv, | |||
| 102 | * Searches and unlinks the entry in drm_device::magiclist with the magic | 102 | * Searches and unlinks the entry in drm_device::magiclist with the magic |
| 103 | * number hash key, while holding the drm_device::struct_mutex lock. | 103 | * number hash key, while holding the drm_device::struct_mutex lock. |
| 104 | */ | 104 | */ |
| 105 | static int drm_remove_magic(struct drm_device * dev, drm_magic_t magic) | 105 | static int drm_remove_magic(struct drm_master *master, drm_magic_t magic) |
| 106 | { | 106 | { |
| 107 | struct drm_magic_entry *pt; | 107 | struct drm_magic_entry *pt; |
| 108 | struct drm_hash_item *hash; | 108 | struct drm_hash_item *hash; |
| 109 | struct drm_device *dev = master->minor->dev; | ||
| 109 | 110 | ||
| 110 | DRM_DEBUG("%d\n", magic); | 111 | DRM_DEBUG("%d\n", magic); |
| 111 | 112 | ||
| 112 | mutex_lock(&dev->struct_mutex); | 113 | mutex_lock(&dev->struct_mutex); |
| 113 | if (drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) { | 114 | if (drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) { |
| 114 | mutex_unlock(&dev->struct_mutex); | 115 | mutex_unlock(&dev->struct_mutex); |
| 115 | return -EINVAL; | 116 | return -EINVAL; |
| 116 | } | 117 | } |
| 117 | pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); | 118 | pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); |
| 118 | drm_ht_remove_item(&dev->magiclist, hash); | 119 | drm_ht_remove_item(&master->magiclist, hash); |
| 119 | list_del(&pt->head); | 120 | list_del(&pt->head); |
| 120 | mutex_unlock(&dev->struct_mutex); | 121 | mutex_unlock(&dev->struct_mutex); |
| 121 | 122 | ||
| @@ -153,9 +154,9 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
| 153 | ++sequence; /* reserve 0 */ | 154 | ++sequence; /* reserve 0 */ |
| 154 | auth->magic = sequence++; | 155 | auth->magic = sequence++; |
| 155 | spin_unlock(&lock); | 156 | spin_unlock(&lock); |
| 156 | } while (drm_find_file(dev, auth->magic)); | 157 | } while (drm_find_file(file_priv->master, auth->magic)); |
| 157 | file_priv->magic = auth->magic; | 158 | file_priv->magic = auth->magic; |
| 158 | drm_add_magic(dev, file_priv, auth->magic); | 159 | drm_add_magic(file_priv->master, file_priv, auth->magic); |
| 159 | } | 160 | } |
| 160 | 161 | ||
| 161 | DRM_DEBUG("%u\n", auth->magic); | 162 | DRM_DEBUG("%u\n", auth->magic); |
| @@ -181,9 +182,9 @@ int drm_authmagic(struct drm_device *dev, void *data, | |||
| 181 | struct drm_file *file; | 182 | struct drm_file *file; |
| 182 | 183 | ||
| 183 | DRM_DEBUG("%u\n", auth->magic); | 184 | DRM_DEBUG("%u\n", auth->magic); |
| 184 | if ((file = drm_find_file(dev, auth->magic))) { | 185 | if ((file = drm_find_file(file_priv->master, auth->magic))) { |
| 185 | file->authenticated = 1; | 186 | file->authenticated = 1; |
| 186 | drm_remove_magic(dev, auth->magic); | 187 | drm_remove_magic(file_priv->master, auth->magic); |
| 187 | return 0; | 188 | return 0; |
| 188 | } | 189 | } |
| 189 | return -EINVAL; | 190 | return -EINVAL; |
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index bde64b84166e..72c667f9bee1 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c | |||
| @@ -54,9 +54,9 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, | |||
| 54 | { | 54 | { |
| 55 | struct drm_map_list *entry; | 55 | struct drm_map_list *entry; |
| 56 | list_for_each_entry(entry, &dev->maplist, head) { | 56 | list_for_each_entry(entry, &dev->maplist, head) { |
| 57 | if (entry->map && map->type == entry->map->type && | 57 | if (entry->map && (entry->master == dev->primary->master) && (map->type == entry->map->type) && |
| 58 | ((entry->map->offset == map->offset) || | 58 | ((entry->map->offset == map->offset) || |
| 59 | (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) { | 59 | ((map->type == _DRM_SHM) && (map->flags&_DRM_CONTAINS_LOCK)))) { |
| 60 | return entry; | 60 | return entry; |
| 61 | } | 61 | } |
| 62 | } | 62 | } |
| @@ -210,12 +210,12 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset, | |||
| 210 | map->offset = (unsigned long)map->handle; | 210 | map->offset = (unsigned long)map->handle; |
| 211 | if (map->flags & _DRM_CONTAINS_LOCK) { | 211 | if (map->flags & _DRM_CONTAINS_LOCK) { |
| 212 | /* Prevent a 2nd X Server from creating a 2nd lock */ | 212 | /* Prevent a 2nd X Server from creating a 2nd lock */ |
| 213 | if (dev->lock.hw_lock != NULL) { | 213 | if (dev->primary->master->lock.hw_lock != NULL) { |
| 214 | vfree(map->handle); | 214 | vfree(map->handle); |
| 215 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | 215 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); |
| 216 | return -EBUSY; | 216 | return -EBUSY; |
| 217 | } | 217 | } |
| 218 | dev->sigdata.lock = dev->lock.hw_lock = map->handle; /* Pointer to lock */ | 218 | dev->sigdata.lock = dev->primary->master->lock.hw_lock = map->handle; /* Pointer to lock */ |
| 219 | } | 219 | } |
| 220 | break; | 220 | break; |
| 221 | case _DRM_AGP: { | 221 | case _DRM_AGP: { |
| @@ -262,6 +262,9 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset, | |||
| 262 | DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size); | 262 | DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size); |
| 263 | 263 | ||
| 264 | break; | 264 | break; |
| 265 | case _DRM_GEM: | ||
| 266 | DRM_ERROR("tried to rmmap GEM object\n"); | ||
| 267 | break; | ||
| 265 | } | 268 | } |
| 266 | case _DRM_SCATTER_GATHER: | 269 | case _DRM_SCATTER_GATHER: |
| 267 | if (!dev->sg) { | 270 | if (!dev->sg) { |
| @@ -319,6 +322,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset, | |||
| 319 | list->user_token = list->hash.key << PAGE_SHIFT; | 322 | list->user_token = list->hash.key << PAGE_SHIFT; |
| 320 | mutex_unlock(&dev->struct_mutex); | 323 | mutex_unlock(&dev->struct_mutex); |
| 321 | 324 | ||
| 325 | list->master = dev->primary->master; | ||
| 322 | *maplist = list; | 326 | *maplist = list; |
| 323 | return 0; | 327 | return 0; |
| 324 | } | 328 | } |
| @@ -345,7 +349,7 @@ int drm_addmap_ioctl(struct drm_device *dev, void *data, | |||
| 345 | struct drm_map_list *maplist; | 349 | struct drm_map_list *maplist; |
| 346 | int err; | 350 | int err; |
| 347 | 351 | ||
| 348 | if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP)) | 352 | if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP || map->type == _DRM_SHM)) |
| 349 | return -EPERM; | 353 | return -EPERM; |
| 350 | 354 | ||
| 351 | err = drm_addmap_core(dev, map->offset, map->size, map->type, | 355 | err = drm_addmap_core(dev, map->offset, map->size, map->type, |
| @@ -380,10 +384,12 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map) | |||
| 380 | struct drm_map_list *r_list = NULL, *list_t; | 384 | struct drm_map_list *r_list = NULL, *list_t; |
| 381 | drm_dma_handle_t dmah; | 385 | drm_dma_handle_t dmah; |
| 382 | int found = 0; | 386 | int found = 0; |
| 387 | struct drm_master *master; | ||
| 383 | 388 | ||
| 384 | /* Find the list entry for the map and remove it */ | 389 | /* Find the list entry for the map and remove it */ |
| 385 | list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) { | 390 | list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) { |
| 386 | if (r_list->map == map) { | 391 | if (r_list->map == map) { |
| 392 | master = r_list->master; | ||
| 387 | list_del(&r_list->head); | 393 | list_del(&r_list->head); |
| 388 | drm_ht_remove_key(&dev->map_hash, | 394 | drm_ht_remove_key(&dev->map_hash, |
| 389 | r_list->user_token >> PAGE_SHIFT); | 395 | r_list->user_token >> PAGE_SHIFT); |
| @@ -409,6 +415,13 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map) | |||
| 409 | break; | 415 | break; |
| 410 | case _DRM_SHM: | 416 | case _DRM_SHM: |
| 411 | vfree(map->handle); | 417 | vfree(map->handle); |
| 418 | if (master) { | ||
| 419 | if (dev->sigdata.lock == master->lock.hw_lock) | ||
| 420 | dev->sigdata.lock = NULL; | ||
| 421 | master->lock.hw_lock = NULL; /* SHM removed */ | ||
| 422 | master->lock.file_priv = NULL; | ||
| 423 | wake_up_interruptible(&master->lock.lock_queue); | ||
| 424 | } | ||
| 412 | break; | 425 | break; |
| 413 | case _DRM_AGP: | 426 | case _DRM_AGP: |
| 414 | case _DRM_SCATTER_GATHER: | 427 | case _DRM_SCATTER_GATHER: |
| @@ -419,11 +432,15 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map) | |||
| 419 | dmah.size = map->size; | 432 | dmah.size = map->size; |
| 420 | __drm_pci_free(dev, &dmah); | 433 | __drm_pci_free(dev, &dmah); |
| 421 | break; | 434 | break; |
| 435 | case _DRM_GEM: | ||
| 436 | DRM_ERROR("tried to rmmap GEM object\n"); | ||
| 437 | break; | ||
| 422 | } | 438 | } |
| 423 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | 439 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); |
| 424 | 440 | ||
| 425 | return 0; | 441 | return 0; |
| 426 | } | 442 | } |
| 443 | EXPORT_SYMBOL(drm_rmmap_locked); | ||
| 427 | 444 | ||
| 428 | int drm_rmmap(struct drm_device *dev, drm_local_map_t *map) | 445 | int drm_rmmap(struct drm_device *dev, drm_local_map_t *map) |
| 429 | { | 446 | { |
diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c index d505f695421f..809ec0f03452 100644 --- a/drivers/gpu/drm/drm_context.c +++ b/drivers/gpu/drm/drm_context.c | |||
| @@ -256,12 +256,13 @@ static int drm_context_switch(struct drm_device * dev, int old, int new) | |||
| 256 | * hardware lock is held, clears the drm_device::context_flag and wakes up | 256 | * hardware lock is held, clears the drm_device::context_flag and wakes up |
| 257 | * drm_device::context_wait. | 257 | * drm_device::context_wait. |
| 258 | */ | 258 | */ |
| 259 | static int drm_context_switch_complete(struct drm_device * dev, int new) | 259 | static int drm_context_switch_complete(struct drm_device *dev, |
| 260 | struct drm_file *file_priv, int new) | ||
| 260 | { | 261 | { |
| 261 | dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ | 262 | dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ |
| 262 | dev->last_switch = jiffies; | 263 | dev->last_switch = jiffies; |
| 263 | 264 | ||
| 264 | if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { | 265 | if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) { |
| 265 | DRM_ERROR("Lock isn't held after context switch\n"); | 266 | DRM_ERROR("Lock isn't held after context switch\n"); |
| 266 | } | 267 | } |
| 267 | 268 | ||
| @@ -420,7 +421,7 @@ int drm_newctx(struct drm_device *dev, void *data, | |||
| 420 | struct drm_ctx *ctx = data; | 421 | struct drm_ctx *ctx = data; |
| 421 | 422 | ||
| 422 | DRM_DEBUG("%d\n", ctx->handle); | 423 | DRM_DEBUG("%d\n", ctx->handle); |
| 423 | drm_context_switch_complete(dev, ctx->handle); | 424 | drm_context_switch_complete(dev, file_priv, ctx->handle); |
| 424 | 425 | ||
| 425 | return 0; | 426 | return 0; |
| 426 | } | 427 | } |
| @@ -442,9 +443,6 @@ int drm_rmctx(struct drm_device *dev, void *data, | |||
| 442 | struct drm_ctx *ctx = data; | 443 | struct drm_ctx *ctx = data; |
| 443 | 444 | ||
| 444 | DRM_DEBUG("%d\n", ctx->handle); | 445 | DRM_DEBUG("%d\n", ctx->handle); |
| 445 | if (ctx->handle == DRM_KERNEL_CONTEXT + 1) { | ||
| 446 | file_priv->remove_auth_on_close = 1; | ||
| 447 | } | ||
| 448 | if (ctx->handle != DRM_KERNEL_CONTEXT) { | 446 | if (ctx->handle != DRM_KERNEL_CONTEXT) { |
| 449 | if (dev->driver->context_dtor) | 447 | if (dev->driver->context_dtor) |
| 450 | dev->driver->context_dtor(dev, ctx->handle); | 448 | dev->driver->context_dtor(dev, ctx->handle); |
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c new file mode 100644 index 000000000000..53c87254be4c --- /dev/null +++ b/drivers/gpu/drm/drm_crtc.c | |||
| @@ -0,0 +1,2446 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2006-2008 Intel Corporation | ||
| 3 | * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> | ||
| 4 | * Copyright (c) 2008 Red Hat Inc. | ||
| 5 | * | ||
| 6 | * DRM core CRTC related functions | ||
| 7 | * | ||
| 8 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
| 9 | * documentation for any purpose is hereby granted without fee, provided that | ||
| 10 | * the above copyright notice appear in all copies and that both that copyright | ||
| 11 | * notice and this permission notice appear in supporting documentation, and | ||
| 12 | * that the name of the copyright holders not be used in advertising or | ||
| 13 | * publicity pertaining to distribution of the software without specific, | ||
| 14 | * written prior permission. The copyright holders make no representations | ||
| 15 | * about the suitability of this software for any purpose. It is provided "as | ||
| 16 | * is" without express or implied warranty. | ||
| 17 | * | ||
| 18 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
| 19 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
| 20 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
| 21 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
| 22 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
| 23 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
| 24 | * OF THIS SOFTWARE. | ||
| 25 | * | ||
| 26 | * Authors: | ||
| 27 | * Keith Packard | ||
| 28 | * Eric Anholt <eric@anholt.net> | ||
| 29 | * Dave Airlie <airlied@linux.ie> | ||
| 30 | * Jesse Barnes <jesse.barnes@intel.com> | ||
| 31 | */ | ||
| 32 | #include <linux/list.h> | ||
| 33 | #include "drm.h" | ||
| 34 | #include "drmP.h" | ||
| 35 | #include "drm_crtc.h" | ||
| 36 | |||
| 37 | struct drm_prop_enum_list { | ||
| 38 | int type; | ||
| 39 | char *name; | ||
| 40 | }; | ||
| 41 | |||
| 42 | /* Avoid boilerplate. I'm tired of typing. */ | ||
| 43 | #define DRM_ENUM_NAME_FN(fnname, list) \ | ||
| 44 | char *fnname(int val) \ | ||
| 45 | { \ | ||
| 46 | int i; \ | ||
| 47 | for (i = 0; i < ARRAY_SIZE(list); i++) { \ | ||
| 48 | if (list[i].type == val) \ | ||
| 49 | return list[i].name; \ | ||
| 50 | } \ | ||
| 51 | return "(unknown)"; \ | ||
| 52 | } | ||
| 53 | |||
| 54 | /* | ||
| 55 | * Global properties | ||
| 56 | */ | ||
| 57 | static struct drm_prop_enum_list drm_dpms_enum_list[] = | ||
| 58 | { { DRM_MODE_DPMS_ON, "On" }, | ||
| 59 | { DRM_MODE_DPMS_STANDBY, "Standby" }, | ||
| 60 | { DRM_MODE_DPMS_SUSPEND, "Suspend" }, | ||
| 61 | { DRM_MODE_DPMS_OFF, "Off" } | ||
| 62 | }; | ||
| 63 | |||
| 64 | DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) | ||
| 65 | |||
| 66 | /* | ||
| 67 | * Optional properties | ||
| 68 | */ | ||
| 69 | static struct drm_prop_enum_list drm_scaling_mode_enum_list[] = | ||
| 70 | { | ||
| 71 | { DRM_MODE_SCALE_NON_GPU, "Non-GPU" }, | ||
| 72 | { DRM_MODE_SCALE_FULLSCREEN, "Fullscreen" }, | ||
| 73 | { DRM_MODE_SCALE_NO_SCALE, "No scale" }, | ||
| 74 | { DRM_MODE_SCALE_ASPECT, "Aspect" }, | ||
| 75 | }; | ||
| 76 | |||
| 77 | static struct drm_prop_enum_list drm_dithering_mode_enum_list[] = | ||
| 78 | { | ||
| 79 | { DRM_MODE_DITHERING_OFF, "Off" }, | ||
| 80 | { DRM_MODE_DITHERING_ON, "On" }, | ||
| 81 | }; | ||
| 82 | |||
| 83 | /* | ||
| 84 | * Non-global properties, but "required" for certain connectors. | ||
| 85 | */ | ||
| 86 | static struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = | ||
| 87 | { | ||
| 88 | { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ | ||
| 89 | { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ | ||
| 90 | { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ | ||
| 91 | }; | ||
| 92 | |||
| 93 | DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list) | ||
| 94 | |||
| 95 | static struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = | ||
| 96 | { | ||
| 97 | { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ | ||
| 98 | { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ | ||
| 99 | { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ | ||
| 100 | }; | ||
| 101 | |||
| 102 | DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name, | ||
| 103 | drm_dvi_i_subconnector_enum_list) | ||
| 104 | |||
| 105 | static struct drm_prop_enum_list drm_tv_select_enum_list[] = | ||
| 106 | { | ||
| 107 | { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ | ||
| 108 | { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ | ||
| 109 | { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ | ||
| 110 | { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ | ||
| 111 | }; | ||
| 112 | |||
| 113 | DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list) | ||
| 114 | |||
| 115 | static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = | ||
| 116 | { | ||
| 117 | { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ | ||
| 118 | { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ | ||
| 119 | { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ | ||
| 120 | { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ | ||
| 121 | }; | ||
| 122 | |||
| 123 | DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name, | ||
| 124 | drm_tv_subconnector_enum_list) | ||
| 125 | |||
| 126 | struct drm_conn_prop_enum_list { | ||
| 127 | int type; | ||
| 128 | char *name; | ||
| 129 | int count; | ||
| 130 | }; | ||
| 131 | |||
| 132 | /* | ||
| 133 | * Connector and encoder types. | ||
| 134 | */ | ||
| 135 | static struct drm_conn_prop_enum_list drm_connector_enum_list[] = | ||
| 136 | { { DRM_MODE_CONNECTOR_Unknown, "Unknown", 0 }, | ||
| 137 | { DRM_MODE_CONNECTOR_VGA, "VGA", 0 }, | ||
| 138 | { DRM_MODE_CONNECTOR_DVII, "DVI-I", 0 }, | ||
| 139 | { DRM_MODE_CONNECTOR_DVID, "DVI-D", 0 }, | ||
| 140 | { DRM_MODE_CONNECTOR_DVIA, "DVI-A", 0 }, | ||
| 141 | { DRM_MODE_CONNECTOR_Composite, "Composite", 0 }, | ||
| 142 | { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO", 0 }, | ||
| 143 | { DRM_MODE_CONNECTOR_LVDS, "LVDS", 0 }, | ||
| 144 | { DRM_MODE_CONNECTOR_Component, "Component", 0 }, | ||
| 145 | { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN", 0 }, | ||
| 146 | { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort", 0 }, | ||
| 147 | { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A", 0 }, | ||
| 148 | { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B", 0 }, | ||
| 149 | }; | ||
| 150 | |||
| 151 | static struct drm_prop_enum_list drm_encoder_enum_list[] = | ||
| 152 | { { DRM_MODE_ENCODER_NONE, "None" }, | ||
| 153 | { DRM_MODE_ENCODER_DAC, "DAC" }, | ||
| 154 | { DRM_MODE_ENCODER_TMDS, "TMDS" }, | ||
| 155 | { DRM_MODE_ENCODER_LVDS, "LVDS" }, | ||
| 156 | { DRM_MODE_ENCODER_TVDAC, "TV" }, | ||
| 157 | }; | ||
| 158 | |||
| 159 | char *drm_get_encoder_name(struct drm_encoder *encoder) | ||
| 160 | { | ||
| 161 | static char buf[32]; | ||
| 162 | |||
| 163 | snprintf(buf, 32, "%s-%d", | ||
| 164 | drm_encoder_enum_list[encoder->encoder_type].name, | ||
| 165 | encoder->base.id); | ||
| 166 | return buf; | ||
| 167 | } | ||
| 168 | |||
| 169 | char *drm_get_connector_name(struct drm_connector *connector) | ||
| 170 | { | ||
| 171 | static char buf[32]; | ||
| 172 | |||
| 173 | snprintf(buf, 32, "%s-%d", | ||
| 174 | drm_connector_enum_list[connector->connector_type].name, | ||
| 175 | connector->connector_type_id); | ||
| 176 | return buf; | ||
| 177 | } | ||
| 178 | EXPORT_SYMBOL(drm_get_connector_name); | ||
| 179 | |||
| 180 | char *drm_get_connector_status_name(enum drm_connector_status status) | ||
| 181 | { | ||
| 182 | if (status == connector_status_connected) | ||
| 183 | return "connected"; | ||
| 184 | else if (status == connector_status_disconnected) | ||
| 185 | return "disconnected"; | ||
| 186 | else | ||
| 187 | return "unknown"; | ||
| 188 | } | ||
| 189 | |||
| 190 | /** | ||
| 191 | * drm_mode_object_get - allocate a new identifier | ||
| 192 | * @dev: DRM device | ||
| 193 | * @ptr: object pointer, used to generate unique ID | ||
| 194 | * @type: object type | ||
| 195 | * | ||
| 196 | * LOCKING: | ||
| 197 | * Caller must hold DRM mode_config lock. | ||
| 198 | * | ||
| 199 | * Create a unique identifier based on @ptr in @dev's identifier space. Used | ||
| 200 | * for tracking modes, CRTCs and connectors. | ||
| 201 | * | ||
| 202 | * RETURNS: | ||
| 203 | * New unique (relative to other objects in @dev) integer identifier for the | ||
| 204 | * object. | ||
| 205 | */ | ||
| 206 | static int drm_mode_object_get(struct drm_device *dev, | ||
| 207 | struct drm_mode_object *obj, uint32_t obj_type) | ||
| 208 | { | ||
| 209 | int new_id = 0; | ||
| 210 | int ret; | ||
| 211 | |||
| 212 | WARN(!mutex_is_locked(&dev->mode_config.mutex), | ||
| 213 | "%s called w/o mode_config lock\n", __FUNCTION__); | ||
| 214 | again: | ||
| 215 | if (idr_pre_get(&dev->mode_config.crtc_idr, GFP_KERNEL) == 0) { | ||
| 216 | DRM_ERROR("Ran out memory getting a mode number\n"); | ||
| 217 | return -EINVAL; | ||
| 218 | } | ||
| 219 | |||
| 220 | ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id); | ||
| 221 | if (ret == -EAGAIN) | ||
| 222 | goto again; | ||
| 223 | |||
| 224 | obj->id = new_id; | ||
| 225 | obj->type = obj_type; | ||
| 226 | return 0; | ||
| 227 | } | ||
| 228 | |||
| 229 | /** | ||
| 230 | * drm_mode_object_put - free an identifer | ||
| 231 | * @dev: DRM device | ||
| 232 | * @id: ID to free | ||
| 233 | * | ||
| 234 | * LOCKING: | ||
| 235 | * Caller must hold DRM mode_config lock. | ||
| 236 | * | ||
| 237 | * Free @id from @dev's unique identifier pool. | ||
| 238 | */ | ||
| 239 | static void drm_mode_object_put(struct drm_device *dev, | ||
| 240 | struct drm_mode_object *object) | ||
| 241 | { | ||
| 242 | idr_remove(&dev->mode_config.crtc_idr, object->id); | ||
| 243 | } | ||
| 244 | |||
| 245 | void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type) | ||
| 246 | { | ||
| 247 | struct drm_mode_object *obj; | ||
| 248 | |||
| 249 | obj = idr_find(&dev->mode_config.crtc_idr, id); | ||
| 250 | if (!obj || (obj->type != type) || (obj->id != id)) | ||
| 251 | return NULL; | ||
| 252 | |||
| 253 | return obj; | ||
| 254 | } | ||
| 255 | EXPORT_SYMBOL(drm_mode_object_find); | ||
| 256 | |||
| 257 | /** | ||
| 258 | * drm_crtc_from_fb - find the CRTC structure associated with an fb | ||
| 259 | * @dev: DRM device | ||
| 260 | * @fb: framebuffer in question | ||
| 261 | * | ||
| 262 | * LOCKING: | ||
| 263 | * Caller must hold mode_config lock. | ||
| 264 | * | ||
| 265 | * Find CRTC in the mode_config structure that matches @fb. | ||
| 266 | * | ||
| 267 | * RETURNS: | ||
| 268 | * Pointer to the CRTC or NULL if it wasn't found. | ||
| 269 | */ | ||
| 270 | struct drm_crtc *drm_crtc_from_fb(struct drm_device *dev, | ||
| 271 | struct drm_framebuffer *fb) | ||
| 272 | { | ||
| 273 | struct drm_crtc *crtc; | ||
| 274 | |||
| 275 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
| 276 | if (crtc->fb == fb) | ||
| 277 | return crtc; | ||
| 278 | } | ||
| 279 | return NULL; | ||
| 280 | } | ||
| 281 | |||
| 282 | /** | ||
| 283 | * drm_framebuffer_init - initialize a framebuffer | ||
| 284 | * @dev: DRM device | ||
| 285 | * | ||
| 286 | * LOCKING: | ||
| 287 | * Caller must hold mode config lock. | ||
| 288 | * | ||
| 289 | * Allocates an ID for the framebuffer's parent mode object, sets its mode | ||
| 290 | * functions & device file and adds it to the master fd list. | ||
| 291 | * | ||
| 292 | * RETURNS: | ||
| 293 | * Zero on success, error code on falure. | ||
| 294 | */ | ||
| 295 | int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, | ||
| 296 | const struct drm_framebuffer_funcs *funcs) | ||
| 297 | { | ||
| 298 | int ret; | ||
| 299 | |||
| 300 | ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); | ||
| 301 | if (ret) { | ||
| 302 | return ret; | ||
| 303 | } | ||
| 304 | |||
| 305 | fb->dev = dev; | ||
| 306 | fb->funcs = funcs; | ||
| 307 | dev->mode_config.num_fb++; | ||
| 308 | list_add(&fb->head, &dev->mode_config.fb_list); | ||
| 309 | |||
| 310 | return 0; | ||
| 311 | } | ||
| 312 | EXPORT_SYMBOL(drm_framebuffer_init); | ||
| 313 | |||
| 314 | /** | ||
| 315 | * drm_framebuffer_cleanup - remove a framebuffer object | ||
| 316 | * @fb: framebuffer to remove | ||
| 317 | * | ||
| 318 | * LOCKING: | ||
| 319 | * Caller must hold mode config lock. | ||
| 320 | * | ||
| 321 | * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes | ||
| 322 | * it, setting it to NULL. | ||
| 323 | */ | ||
| 324 | void drm_framebuffer_cleanup(struct drm_framebuffer *fb) | ||
| 325 | { | ||
| 326 | struct drm_device *dev = fb->dev; | ||
| 327 | struct drm_crtc *crtc; | ||
| 328 | |||
| 329 | /* remove from any CRTC */ | ||
| 330 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
| 331 | if (crtc->fb == fb) | ||
| 332 | crtc->fb = NULL; | ||
| 333 | } | ||
| 334 | |||
| 335 | drm_mode_object_put(dev, &fb->base); | ||
| 336 | list_del(&fb->head); | ||
| 337 | dev->mode_config.num_fb--; | ||
| 338 | } | ||
| 339 | EXPORT_SYMBOL(drm_framebuffer_cleanup); | ||
| 340 | |||
| 341 | /** | ||
| 342 | * drm_crtc_init - Initialise a new CRTC object | ||
| 343 | * @dev: DRM device | ||
| 344 | * @crtc: CRTC object to init | ||
| 345 | * @funcs: callbacks for the new CRTC | ||
| 346 | * | ||
| 347 | * LOCKING: | ||
| 348 | * Caller must hold mode config lock. | ||
| 349 | * | ||
| 350 | * Inits a new object created as base part of an driver crtc object. | ||
| 351 | */ | ||
| 352 | void drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, | ||
| 353 | const struct drm_crtc_funcs *funcs) | ||
| 354 | { | ||
| 355 | crtc->dev = dev; | ||
| 356 | crtc->funcs = funcs; | ||
| 357 | |||
| 358 | mutex_lock(&dev->mode_config.mutex); | ||
| 359 | drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); | ||
| 360 | |||
| 361 | list_add_tail(&crtc->head, &dev->mode_config.crtc_list); | ||
| 362 | dev->mode_config.num_crtc++; | ||
| 363 | mutex_unlock(&dev->mode_config.mutex); | ||
| 364 | } | ||
| 365 | EXPORT_SYMBOL(drm_crtc_init); | ||
| 366 | |||
| 367 | /** | ||
| 368 | * drm_crtc_cleanup - Cleans up the core crtc usage. | ||
| 369 | * @crtc: CRTC to cleanup | ||
| 370 | * | ||
| 371 | * LOCKING: | ||
| 372 | * Caller must hold mode config lock. | ||
| 373 | * | ||
| 374 | * Cleanup @crtc. Removes from drm modesetting space | ||
| 375 | * does NOT free object, caller does that. | ||
| 376 | */ | ||
| 377 | void drm_crtc_cleanup(struct drm_crtc *crtc) | ||
| 378 | { | ||
| 379 | struct drm_device *dev = crtc->dev; | ||
| 380 | |||
| 381 | if (crtc->gamma_store) { | ||
| 382 | kfree(crtc->gamma_store); | ||
| 383 | crtc->gamma_store = NULL; | ||
| 384 | } | ||
| 385 | |||
| 386 | drm_mode_object_put(dev, &crtc->base); | ||
| 387 | list_del(&crtc->head); | ||
| 388 | dev->mode_config.num_crtc--; | ||
| 389 | } | ||
| 390 | EXPORT_SYMBOL(drm_crtc_cleanup); | ||
| 391 | |||
| 392 | /** | ||
| 393 | * drm_mode_probed_add - add a mode to a connector's probed mode list | ||
| 394 | * @connector: connector the new mode | ||
| 395 | * @mode: mode data | ||
| 396 | * | ||
| 397 | * LOCKING: | ||
| 398 | * Caller must hold mode config lock. | ||
| 399 | * | ||
| 400 | * Add @mode to @connector's mode list for later use. | ||
| 401 | */ | ||
| 402 | void drm_mode_probed_add(struct drm_connector *connector, | ||
| 403 | struct drm_display_mode *mode) | ||
| 404 | { | ||
| 405 | list_add(&mode->head, &connector->probed_modes); | ||
| 406 | } | ||
| 407 | EXPORT_SYMBOL(drm_mode_probed_add); | ||
| 408 | |||
| 409 | /** | ||
| 410 | * drm_mode_remove - remove and free a mode | ||
| 411 | * @connector: connector list to modify | ||
| 412 | * @mode: mode to remove | ||
| 413 | * | ||
| 414 | * LOCKING: | ||
| 415 | * Caller must hold mode config lock. | ||
| 416 | * | ||
| 417 | * Remove @mode from @connector's mode list, then free it. | ||
| 418 | */ | ||
| 419 | void drm_mode_remove(struct drm_connector *connector, | ||
| 420 | struct drm_display_mode *mode) | ||
| 421 | { | ||
| 422 | list_del(&mode->head); | ||
| 423 | kfree(mode); | ||
| 424 | } | ||
| 425 | EXPORT_SYMBOL(drm_mode_remove); | ||
| 426 | |||
| 427 | /** | ||
| 428 | * drm_connector_init - Init a preallocated connector | ||
| 429 | * @dev: DRM device | ||
| 430 | * @connector: the connector to init | ||
| 431 | * @funcs: callbacks for this connector | ||
| 432 | * @name: user visible name of the connector | ||
| 433 | * | ||
| 434 | * LOCKING: | ||
| 435 | * Caller must hold @dev's mode_config lock. | ||
| 436 | * | ||
| 437 | * Initialises a preallocated connector. Connectors should be | ||
| 438 | * subclassed as part of driver connector objects. | ||
| 439 | */ | ||
| 440 | void drm_connector_init(struct drm_device *dev, | ||
| 441 | struct drm_connector *connector, | ||
| 442 | const struct drm_connector_funcs *funcs, | ||
| 443 | int connector_type) | ||
| 444 | { | ||
| 445 | mutex_lock(&dev->mode_config.mutex); | ||
| 446 | |||
| 447 | connector->dev = dev; | ||
| 448 | connector->funcs = funcs; | ||
| 449 | drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR); | ||
| 450 | connector->connector_type = connector_type; | ||
| 451 | connector->connector_type_id = | ||
| 452 | ++drm_connector_enum_list[connector_type].count; /* TODO */ | ||
| 453 | INIT_LIST_HEAD(&connector->user_modes); | ||
| 454 | INIT_LIST_HEAD(&connector->probed_modes); | ||
| 455 | INIT_LIST_HEAD(&connector->modes); | ||
| 456 | connector->edid_blob_ptr = NULL; | ||
| 457 | |||
| 458 | list_add_tail(&connector->head, &dev->mode_config.connector_list); | ||
| 459 | dev->mode_config.num_connector++; | ||
| 460 | |||
| 461 | drm_connector_attach_property(connector, | ||
| 462 | dev->mode_config.edid_property, 0); | ||
| 463 | |||
| 464 | drm_connector_attach_property(connector, | ||
| 465 | dev->mode_config.dpms_property, 0); | ||
| 466 | |||
| 467 | mutex_unlock(&dev->mode_config.mutex); | ||
| 468 | } | ||
| 469 | EXPORT_SYMBOL(drm_connector_init); | ||
| 470 | |||
| 471 | /** | ||
| 472 | * drm_connector_cleanup - cleans up an initialised connector | ||
| 473 | * @connector: connector to cleanup | ||
| 474 | * | ||
| 475 | * LOCKING: | ||
| 476 | * Caller must hold @dev's mode_config lock. | ||
| 477 | * | ||
| 478 | * Cleans up the connector but doesn't free the object. | ||
| 479 | */ | ||
| 480 | void drm_connector_cleanup(struct drm_connector *connector) | ||
| 481 | { | ||
| 482 | struct drm_device *dev = connector->dev; | ||
| 483 | struct drm_display_mode *mode, *t; | ||
| 484 | |||
| 485 | list_for_each_entry_safe(mode, t, &connector->probed_modes, head) | ||
| 486 | drm_mode_remove(connector, mode); | ||
| 487 | |||
| 488 | list_for_each_entry_safe(mode, t, &connector->modes, head) | ||
| 489 | drm_mode_remove(connector, mode); | ||
| 490 | |||
| 491 | list_for_each_entry_safe(mode, t, &connector->user_modes, head) | ||
| 492 | drm_mode_remove(connector, mode); | ||
| 493 | |||
| 494 | mutex_lock(&dev->mode_config.mutex); | ||
| 495 | drm_mode_object_put(dev, &connector->base); | ||
| 496 | list_del(&connector->head); | ||
| 497 | mutex_unlock(&dev->mode_config.mutex); | ||
| 498 | } | ||
| 499 | EXPORT_SYMBOL(drm_connector_cleanup); | ||
| 500 | |||
| 501 | void drm_encoder_init(struct drm_device *dev, | ||
| 502 | struct drm_encoder *encoder, | ||
| 503 | const struct drm_encoder_funcs *funcs, | ||
| 504 | int encoder_type) | ||
| 505 | { | ||
| 506 | mutex_lock(&dev->mode_config.mutex); | ||
| 507 | |||
| 508 | encoder->dev = dev; | ||
| 509 | |||
| 510 | drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); | ||
| 511 | encoder->encoder_type = encoder_type; | ||
| 512 | encoder->funcs = funcs; | ||
| 513 | |||
| 514 | list_add_tail(&encoder->head, &dev->mode_config.encoder_list); | ||
| 515 | dev->mode_config.num_encoder++; | ||
| 516 | |||
| 517 | mutex_unlock(&dev->mode_config.mutex); | ||
| 518 | } | ||
| 519 | EXPORT_SYMBOL(drm_encoder_init); | ||
| 520 | |||
| 521 | void drm_encoder_cleanup(struct drm_encoder *encoder) | ||
| 522 | { | ||
| 523 | struct drm_device *dev = encoder->dev; | ||
| 524 | mutex_lock(&dev->mode_config.mutex); | ||
| 525 | drm_mode_object_put(dev, &encoder->base); | ||
| 526 | list_del(&encoder->head); | ||
| 527 | mutex_unlock(&dev->mode_config.mutex); | ||
| 528 | } | ||
| 529 | EXPORT_SYMBOL(drm_encoder_cleanup); | ||
| 530 | |||
| 531 | /** | ||
| 532 | * drm_mode_create - create a new display mode | ||
| 533 | * @dev: DRM device | ||
| 534 | * | ||
| 535 | * LOCKING: | ||
| 536 | * Caller must hold DRM mode_config lock. | ||
| 537 | * | ||
| 538 | * Create a new drm_display_mode, give it an ID, and return it. | ||
| 539 | * | ||
| 540 | * RETURNS: | ||
| 541 | * Pointer to new mode on success, NULL on error. | ||
| 542 | */ | ||
| 543 | struct drm_display_mode *drm_mode_create(struct drm_device *dev) | ||
| 544 | { | ||
| 545 | struct drm_display_mode *nmode; | ||
| 546 | |||
| 547 | nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL); | ||
| 548 | if (!nmode) | ||
| 549 | return NULL; | ||
| 550 | |||
| 551 | drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE); | ||
| 552 | return nmode; | ||
| 553 | } | ||
| 554 | EXPORT_SYMBOL(drm_mode_create); | ||
| 555 | |||
| 556 | /** | ||
| 557 | * drm_mode_destroy - remove a mode | ||
| 558 | * @dev: DRM device | ||
| 559 | * @mode: mode to remove | ||
| 560 | * | ||
| 561 | * LOCKING: | ||
| 562 | * Caller must hold mode config lock. | ||
| 563 | * | ||
| 564 | * Free @mode's unique identifier, then free it. | ||
| 565 | */ | ||
| 566 | void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) | ||
| 567 | { | ||
| 568 | drm_mode_object_put(dev, &mode->base); | ||
| 569 | |||
| 570 | kfree(mode); | ||
| 571 | } | ||
| 572 | EXPORT_SYMBOL(drm_mode_destroy); | ||
| 573 | |||
| 574 | static int drm_mode_create_standard_connector_properties(struct drm_device *dev) | ||
| 575 | { | ||
| 576 | struct drm_property *edid; | ||
| 577 | struct drm_property *dpms; | ||
| 578 | int i; | ||
| 579 | |||
| 580 | /* | ||
| 581 | * Standard properties (apply to all connectors) | ||
| 582 | */ | ||
| 583 | edid = drm_property_create(dev, DRM_MODE_PROP_BLOB | | ||
| 584 | DRM_MODE_PROP_IMMUTABLE, | ||
| 585 | "EDID", 0); | ||
| 586 | dev->mode_config.edid_property = edid; | ||
| 587 | |||
| 588 | dpms = drm_property_create(dev, DRM_MODE_PROP_ENUM, | ||
| 589 | "DPMS", ARRAY_SIZE(drm_dpms_enum_list)); | ||
| 590 | for (i = 0; i < ARRAY_SIZE(drm_dpms_enum_list); i++) | ||
| 591 | drm_property_add_enum(dpms, i, drm_dpms_enum_list[i].type, | ||
| 592 | drm_dpms_enum_list[i].name); | ||
| 593 | dev->mode_config.dpms_property = dpms; | ||
| 594 | |||
| 595 | return 0; | ||
| 596 | } | ||
| 597 | |||
| 598 | /** | ||
| 599 | * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties | ||
| 600 | * @dev: DRM device | ||
| 601 | * | ||
| 602 | * Called by a driver the first time a DVI-I connector is made. | ||
| 603 | */ | ||
| 604 | int drm_mode_create_dvi_i_properties(struct drm_device *dev) | ||
| 605 | { | ||
| 606 | struct drm_property *dvi_i_selector; | ||
| 607 | struct drm_property *dvi_i_subconnector; | ||
| 608 | int i; | ||
| 609 | |||
| 610 | if (dev->mode_config.dvi_i_select_subconnector_property) | ||
| 611 | return 0; | ||
| 612 | |||
| 613 | dvi_i_selector = | ||
| 614 | drm_property_create(dev, DRM_MODE_PROP_ENUM, | ||
| 615 | "select subconnector", | ||
| 616 | ARRAY_SIZE(drm_dvi_i_select_enum_list)); | ||
| 617 | for (i = 0; i < ARRAY_SIZE(drm_dvi_i_select_enum_list); i++) | ||
| 618 | drm_property_add_enum(dvi_i_selector, i, | ||
| 619 | drm_dvi_i_select_enum_list[i].type, | ||
| 620 | drm_dvi_i_select_enum_list[i].name); | ||
| 621 | dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; | ||
| 622 | |||
| 623 | dvi_i_subconnector = | ||
| 624 | drm_property_create(dev, DRM_MODE_PROP_ENUM | | ||
| 625 | DRM_MODE_PROP_IMMUTABLE, | ||
| 626 | "subconnector", | ||
| 627 | ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); | ||
| 628 | for (i = 0; i < ARRAY_SIZE(drm_dvi_i_subconnector_enum_list); i++) | ||
| 629 | drm_property_add_enum(dvi_i_subconnector, i, | ||
| 630 | drm_dvi_i_subconnector_enum_list[i].type, | ||
| 631 | drm_dvi_i_subconnector_enum_list[i].name); | ||
| 632 | dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; | ||
| 633 | |||
| 634 | return 0; | ||
| 635 | } | ||
| 636 | EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); | ||
| 637 | |||
| 638 | /** | ||
| 639 | * drm_create_tv_properties - create TV specific connector properties | ||
| 640 | * @dev: DRM device | ||
| 641 | * @num_modes: number of different TV formats (modes) supported | ||
| 642 | * @modes: array of pointers to strings containing name of each format | ||
| 643 | * | ||
| 644 | * Called by a driver's TV initialization routine, this function creates | ||
| 645 | * the TV specific connector properties for a given device. Caller is | ||
| 646 | * responsible for allocating a list of format names and passing them to | ||
| 647 | * this routine. | ||
| 648 | */ | ||
| 649 | int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, | ||
| 650 | char *modes[]) | ||
| 651 | { | ||
| 652 | struct drm_property *tv_selector; | ||
| 653 | struct drm_property *tv_subconnector; | ||
| 654 | int i; | ||
| 655 | |||
| 656 | if (dev->mode_config.tv_select_subconnector_property) | ||
| 657 | return 0; | ||
| 658 | |||
| 659 | /* | ||
| 660 | * Basic connector properties | ||
| 661 | */ | ||
| 662 | tv_selector = drm_property_create(dev, DRM_MODE_PROP_ENUM, | ||
| 663 | "select subconnector", | ||
| 664 | ARRAY_SIZE(drm_tv_select_enum_list)); | ||
| 665 | for (i = 0; i < ARRAY_SIZE(drm_tv_select_enum_list); i++) | ||
| 666 | drm_property_add_enum(tv_selector, i, | ||
| 667 | drm_tv_select_enum_list[i].type, | ||
| 668 | drm_tv_select_enum_list[i].name); | ||
| 669 | dev->mode_config.tv_select_subconnector_property = tv_selector; | ||
| 670 | |||
| 671 | tv_subconnector = | ||
| 672 | drm_property_create(dev, DRM_MODE_PROP_ENUM | | ||
| 673 | DRM_MODE_PROP_IMMUTABLE, "subconnector", | ||
| 674 | ARRAY_SIZE(drm_tv_subconnector_enum_list)); | ||
| 675 | for (i = 0; i < ARRAY_SIZE(drm_tv_subconnector_enum_list); i++) | ||
| 676 | drm_property_add_enum(tv_subconnector, i, | ||
| 677 | drm_tv_subconnector_enum_list[i].type, | ||
| 678 | drm_tv_subconnector_enum_list[i].name); | ||
| 679 | dev->mode_config.tv_subconnector_property = tv_subconnector; | ||
| 680 | |||
| 681 | /* | ||
| 682 | * Other, TV specific properties: margins & TV modes. | ||
| 683 | */ | ||
| 684 | dev->mode_config.tv_left_margin_property = | ||
| 685 | drm_property_create(dev, DRM_MODE_PROP_RANGE, | ||
| 686 | "left margin", 2); | ||
| 687 | dev->mode_config.tv_left_margin_property->values[0] = 0; | ||
| 688 | dev->mode_config.tv_left_margin_property->values[1] = 100; | ||
| 689 | |||
| 690 | dev->mode_config.tv_right_margin_property = | ||
| 691 | drm_property_create(dev, DRM_MODE_PROP_RANGE, | ||
| 692 | "right margin", 2); | ||
| 693 | dev->mode_config.tv_right_margin_property->values[0] = 0; | ||
| 694 | dev->mode_config.tv_right_margin_property->values[1] = 100; | ||
| 695 | |||
| 696 | dev->mode_config.tv_top_margin_property = | ||
| 697 | drm_property_create(dev, DRM_MODE_PROP_RANGE, | ||
| 698 | "top margin", 2); | ||
| 699 | dev->mode_config.tv_top_margin_property->values[0] = 0; | ||
| 700 | dev->mode_config.tv_top_margin_property->values[1] = 100; | ||
| 701 | |||
| 702 | dev->mode_config.tv_bottom_margin_property = | ||
| 703 | drm_property_create(dev, DRM_MODE_PROP_RANGE, | ||
| 704 | "bottom margin", 2); | ||
| 705 | dev->mode_config.tv_bottom_margin_property->values[0] = 0; | ||
| 706 | dev->mode_config.tv_bottom_margin_property->values[1] = 100; | ||
| 707 | |||
| 708 | dev->mode_config.tv_mode_property = | ||
| 709 | drm_property_create(dev, DRM_MODE_PROP_ENUM, | ||
| 710 | "mode", num_modes); | ||
| 711 | for (i = 0; i < num_modes; i++) | ||
| 712 | drm_property_add_enum(dev->mode_config.tv_mode_property, i, | ||
| 713 | i, modes[i]); | ||
| 714 | |||
| 715 | return 0; | ||
| 716 | } | ||
| 717 | EXPORT_SYMBOL(drm_mode_create_tv_properties); | ||
| 718 | |||
| 719 | /** | ||
| 720 | * drm_mode_create_scaling_mode_property - create scaling mode property | ||
| 721 | * @dev: DRM device | ||
| 722 | * | ||
| 723 | * Called by a driver the first time it's needed, must be attached to desired | ||
| 724 | * connectors. | ||
| 725 | */ | ||
| 726 | int drm_mode_create_scaling_mode_property(struct drm_device *dev) | ||
| 727 | { | ||
| 728 | struct drm_property *scaling_mode; | ||
| 729 | int i; | ||
| 730 | |||
| 731 | if (dev->mode_config.scaling_mode_property) | ||
| 732 | return 0; | ||
| 733 | |||
| 734 | scaling_mode = | ||
| 735 | drm_property_create(dev, DRM_MODE_PROP_ENUM, "scaling mode", | ||
| 736 | ARRAY_SIZE(drm_scaling_mode_enum_list)); | ||
| 737 | for (i = 0; i < ARRAY_SIZE(drm_scaling_mode_enum_list); i++) | ||
| 738 | drm_property_add_enum(scaling_mode, i, | ||
| 739 | drm_scaling_mode_enum_list[i].type, | ||
| 740 | drm_scaling_mode_enum_list[i].name); | ||
| 741 | |||
| 742 | dev->mode_config.scaling_mode_property = scaling_mode; | ||
| 743 | |||
| 744 | return 0; | ||
| 745 | } | ||
| 746 | EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); | ||
| 747 | |||
| 748 | /** | ||
| 749 | * drm_mode_create_dithering_property - create dithering property | ||
| 750 | * @dev: DRM device | ||
| 751 | * | ||
| 752 | * Called by a driver the first time it's needed, must be attached to desired | ||
| 753 | * connectors. | ||
| 754 | */ | ||
| 755 | int drm_mode_create_dithering_property(struct drm_device *dev) | ||
| 756 | { | ||
| 757 | struct drm_property *dithering_mode; | ||
| 758 | int i; | ||
| 759 | |||
| 760 | if (dev->mode_config.dithering_mode_property) | ||
| 761 | return 0; | ||
| 762 | |||
| 763 | dithering_mode = | ||
| 764 | drm_property_create(dev, DRM_MODE_PROP_ENUM, "dithering", | ||
| 765 | ARRAY_SIZE(drm_dithering_mode_enum_list)); | ||
| 766 | for (i = 0; i < ARRAY_SIZE(drm_dithering_mode_enum_list); i++) | ||
| 767 | drm_property_add_enum(dithering_mode, i, | ||
| 768 | drm_dithering_mode_enum_list[i].type, | ||
| 769 | drm_dithering_mode_enum_list[i].name); | ||
| 770 | dev->mode_config.dithering_mode_property = dithering_mode; | ||
| 771 | |||
| 772 | return 0; | ||
| 773 | } | ||
| 774 | EXPORT_SYMBOL(drm_mode_create_dithering_property); | ||
| 775 | |||
| 776 | /** | ||
| 777 | * drm_mode_config_init - initialize DRM mode_configuration structure | ||
| 778 | * @dev: DRM device | ||
| 779 | * | ||
| 780 | * LOCKING: | ||
| 781 | * None, should happen single threaded at init time. | ||
| 782 | * | ||
| 783 | * Initialize @dev's mode_config structure, used for tracking the graphics | ||
| 784 | * configuration of @dev. | ||
| 785 | */ | ||
| 786 | void drm_mode_config_init(struct drm_device *dev) | ||
| 787 | { | ||
| 788 | mutex_init(&dev->mode_config.mutex); | ||
| 789 | INIT_LIST_HEAD(&dev->mode_config.fb_list); | ||
| 790 | INIT_LIST_HEAD(&dev->mode_config.fb_kernel_list); | ||
| 791 | INIT_LIST_HEAD(&dev->mode_config.crtc_list); | ||
| 792 | INIT_LIST_HEAD(&dev->mode_config.connector_list); | ||
| 793 | INIT_LIST_HEAD(&dev->mode_config.encoder_list); | ||
| 794 | INIT_LIST_HEAD(&dev->mode_config.property_list); | ||
| 795 | INIT_LIST_HEAD(&dev->mode_config.property_blob_list); | ||
| 796 | idr_init(&dev->mode_config.crtc_idr); | ||
| 797 | |||
| 798 | mutex_lock(&dev->mode_config.mutex); | ||
| 799 | drm_mode_create_standard_connector_properties(dev); | ||
| 800 | mutex_unlock(&dev->mode_config.mutex); | ||
| 801 | |||
| 802 | /* Just to be sure */ | ||
| 803 | dev->mode_config.num_fb = 0; | ||
| 804 | dev->mode_config.num_connector = 0; | ||
| 805 | dev->mode_config.num_crtc = 0; | ||
| 806 | dev->mode_config.num_encoder = 0; | ||
| 807 | } | ||
| 808 | EXPORT_SYMBOL(drm_mode_config_init); | ||
| 809 | |||
| 810 | int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) | ||
| 811 | { | ||
| 812 | uint32_t total_objects = 0; | ||
| 813 | |||
| 814 | total_objects += dev->mode_config.num_crtc; | ||
| 815 | total_objects += dev->mode_config.num_connector; | ||
| 816 | total_objects += dev->mode_config.num_encoder; | ||
| 817 | |||
| 818 | if (total_objects == 0) | ||
| 819 | return -EINVAL; | ||
| 820 | |||
| 821 | group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL); | ||
| 822 | if (!group->id_list) | ||
| 823 | return -ENOMEM; | ||
| 824 | |||
| 825 | group->num_crtcs = 0; | ||
| 826 | group->num_connectors = 0; | ||
| 827 | group->num_encoders = 0; | ||
| 828 | return 0; | ||
| 829 | } | ||
| 830 | |||
| 831 | int drm_mode_group_init_legacy_group(struct drm_device *dev, | ||
| 832 | struct drm_mode_group *group) | ||
| 833 | { | ||
| 834 | struct drm_crtc *crtc; | ||
| 835 | struct drm_encoder *encoder; | ||
| 836 | struct drm_connector *connector; | ||
| 837 | int ret; | ||
| 838 | |||
| 839 | if ((ret = drm_mode_group_init(dev, group))) | ||
| 840 | return ret; | ||
| 841 | |||
| 842 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) | ||
| 843 | group->id_list[group->num_crtcs++] = crtc->base.id; | ||
| 844 | |||
| 845 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) | ||
| 846 | group->id_list[group->num_crtcs + group->num_encoders++] = | ||
| 847 | encoder->base.id; | ||
| 848 | |||
| 849 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) | ||
| 850 | group->id_list[group->num_crtcs + group->num_encoders + | ||
| 851 | group->num_connectors++] = connector->base.id; | ||
| 852 | |||
| 853 | return 0; | ||
| 854 | } | ||
| 855 | |||
| 856 | /** | ||
| 857 | * drm_mode_config_cleanup - free up DRM mode_config info | ||
| 858 | * @dev: DRM device | ||
| 859 | * | ||
| 860 | * LOCKING: | ||
| 861 | * Caller must hold mode config lock. | ||
| 862 | * | ||
| 863 | * Free up all the connectors and CRTCs associated with this DRM device, then | ||
| 864 | * free up the framebuffers and associated buffer objects. | ||
| 865 | * | ||
| 866 | * FIXME: cleanup any dangling user buffer objects too | ||
| 867 | */ | ||
| 868 | void drm_mode_config_cleanup(struct drm_device *dev) | ||
| 869 | { | ||
| 870 | struct drm_connector *connector, *ot; | ||
| 871 | struct drm_crtc *crtc, *ct; | ||
| 872 | struct drm_encoder *encoder, *enct; | ||
| 873 | struct drm_framebuffer *fb, *fbt; | ||
| 874 | struct drm_property *property, *pt; | ||
| 875 | |||
| 876 | list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, | ||
| 877 | head) { | ||
| 878 | encoder->funcs->destroy(encoder); | ||
| 879 | } | ||
| 880 | |||
| 881 | list_for_each_entry_safe(connector, ot, | ||
| 882 | &dev->mode_config.connector_list, head) { | ||
| 883 | connector->funcs->destroy(connector); | ||
| 884 | } | ||
| 885 | |||
| 886 | list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, | ||
| 887 | head) { | ||
| 888 | drm_property_destroy(dev, property); | ||
| 889 | } | ||
| 890 | |||
| 891 | list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { | ||
| 892 | fb->funcs->destroy(fb); | ||
| 893 | } | ||
| 894 | |||
| 895 | list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { | ||
| 896 | crtc->funcs->destroy(crtc); | ||
| 897 | } | ||
| 898 | |||
| 899 | } | ||
| 900 | EXPORT_SYMBOL(drm_mode_config_cleanup); | ||
| 901 | |||
| 902 | /** | ||
| 903 | * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo | ||
| 904 | * @out: drm_mode_modeinfo struct to return to the user | ||
| 905 | * @in: drm_display_mode to use | ||
| 906 | * | ||
| 907 | * LOCKING: | ||
| 908 | * None. | ||
| 909 | * | ||
| 910 | * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to | ||
| 911 | * the user. | ||
| 912 | */ | ||
| 913 | void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, | ||
| 914 | struct drm_display_mode *in) | ||
| 915 | { | ||
| 916 | out->clock = in->clock; | ||
| 917 | out->hdisplay = in->hdisplay; | ||
| 918 | out->hsync_start = in->hsync_start; | ||
| 919 | out->hsync_end = in->hsync_end; | ||
| 920 | out->htotal = in->htotal; | ||
| 921 | out->hskew = in->hskew; | ||
| 922 | out->vdisplay = in->vdisplay; | ||
| 923 | out->vsync_start = in->vsync_start; | ||
| 924 | out->vsync_end = in->vsync_end; | ||
| 925 | out->vtotal = in->vtotal; | ||
| 926 | out->vscan = in->vscan; | ||
| 927 | out->vrefresh = in->vrefresh; | ||
| 928 | out->flags = in->flags; | ||
| 929 | out->type = in->type; | ||
| 930 | strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); | ||
| 931 | out->name[DRM_DISPLAY_MODE_LEN-1] = 0; | ||
| 932 | } | ||
| 933 | |||
| 934 | /** | ||
| 935 | * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode | ||
| 936 | * @out: drm_display_mode to return to the user | ||
| 937 | * @in: drm_mode_modeinfo to use | ||
| 938 | * | ||
| 939 | * LOCKING: | ||
| 940 | * None. | ||
| 941 | * | ||
| 942 | * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to | ||
| 943 | * the caller. | ||
| 944 | */ | ||
| 945 | void drm_crtc_convert_umode(struct drm_display_mode *out, | ||
| 946 | struct drm_mode_modeinfo *in) | ||
| 947 | { | ||
| 948 | out->clock = in->clock; | ||
| 949 | out->hdisplay = in->hdisplay; | ||
| 950 | out->hsync_start = in->hsync_start; | ||
| 951 | out->hsync_end = in->hsync_end; | ||
| 952 | out->htotal = in->htotal; | ||
| 953 | out->hskew = in->hskew; | ||
| 954 | out->vdisplay = in->vdisplay; | ||
| 955 | out->vsync_start = in->vsync_start; | ||
| 956 | out->vsync_end = in->vsync_end; | ||
| 957 | out->vtotal = in->vtotal; | ||
| 958 | out->vscan = in->vscan; | ||
| 959 | out->vrefresh = in->vrefresh; | ||
| 960 | out->flags = in->flags; | ||
| 961 | out->type = in->type; | ||
| 962 | strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); | ||
| 963 | out->name[DRM_DISPLAY_MODE_LEN-1] = 0; | ||
| 964 | } | ||
| 965 | |||
| 966 | /** | ||
| 967 | * drm_mode_getresources - get graphics configuration | ||
| 968 | * @inode: inode from the ioctl | ||
| 969 | * @filp: file * from the ioctl | ||
| 970 | * @cmd: cmd from ioctl | ||
| 971 | * @arg: arg from ioctl | ||
| 972 | * | ||
| 973 | * LOCKING: | ||
| 974 | * Takes mode config lock. | ||
| 975 | * | ||
| 976 | * Construct a set of configuration description structures and return | ||
| 977 | * them to the user, including CRTC, connector and framebuffer configuration. | ||
| 978 | * | ||
| 979 | * Called by the user via ioctl. | ||
| 980 | * | ||
| 981 | * RETURNS: | ||
| 982 | * Zero on success, errno on failure. | ||
| 983 | */ | ||
| 984 | int drm_mode_getresources(struct drm_device *dev, void *data, | ||
| 985 | struct drm_file *file_priv) | ||
| 986 | { | ||
| 987 | struct drm_mode_card_res *card_res = data; | ||
| 988 | struct list_head *lh; | ||
| 989 | struct drm_framebuffer *fb; | ||
| 990 | struct drm_connector *connector; | ||
| 991 | struct drm_crtc *crtc; | ||
| 992 | struct drm_encoder *encoder; | ||
| 993 | int ret = 0; | ||
| 994 | int connector_count = 0; | ||
| 995 | int crtc_count = 0; | ||
| 996 | int fb_count = 0; | ||
| 997 | int encoder_count = 0; | ||
| 998 | int copied = 0, i; | ||
| 999 | uint32_t __user *fb_id; | ||
| 1000 | uint32_t __user *crtc_id; | ||
| 1001 | uint32_t __user *connector_id; | ||
| 1002 | uint32_t __user *encoder_id; | ||
| 1003 | struct drm_mode_group *mode_group; | ||
| 1004 | |||
| 1005 | mutex_lock(&dev->mode_config.mutex); | ||
| 1006 | |||
| 1007 | /* | ||
| 1008 | * For the non-control nodes we need to limit the list of resources | ||
| 1009 | * by IDs in the group list for this node | ||
| 1010 | */ | ||
| 1011 | list_for_each(lh, &file_priv->fbs) | ||
| 1012 | fb_count++; | ||
| 1013 | |||
| 1014 | mode_group = &file_priv->master->minor->mode_group; | ||
| 1015 | if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { | ||
| 1016 | |||
| 1017 | list_for_each(lh, &dev->mode_config.crtc_list) | ||
| 1018 | crtc_count++; | ||
| 1019 | |||
| 1020 | list_for_each(lh, &dev->mode_config.connector_list) | ||
| 1021 | connector_count++; | ||
| 1022 | |||
| 1023 | list_for_each(lh, &dev->mode_config.encoder_list) | ||
| 1024 | encoder_count++; | ||
| 1025 | } else { | ||
| 1026 | |||
| 1027 | crtc_count = mode_group->num_crtcs; | ||
| 1028 | connector_count = mode_group->num_connectors; | ||
| 1029 | encoder_count = mode_group->num_encoders; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | card_res->max_height = dev->mode_config.max_height; | ||
| 1033 | card_res->min_height = dev->mode_config.min_height; | ||
| 1034 | card_res->max_width = dev->mode_config.max_width; | ||
| 1035 | card_res->min_width = dev->mode_config.min_width; | ||
| 1036 | |||
| 1037 | /* handle this in 4 parts */ | ||
| 1038 | /* FBs */ | ||
| 1039 | if (card_res->count_fbs >= fb_count) { | ||
| 1040 | copied = 0; | ||
| 1041 | fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; | ||
| 1042 | list_for_each_entry(fb, &file_priv->fbs, head) { | ||
| 1043 | if (put_user(fb->base.id, fb_id + copied)) { | ||
| 1044 | ret = -EFAULT; | ||
| 1045 | goto out; | ||
| 1046 | } | ||
| 1047 | copied++; | ||
| 1048 | } | ||
| 1049 | } | ||
| 1050 | card_res->count_fbs = fb_count; | ||
| 1051 | |||
| 1052 | /* CRTCs */ | ||
| 1053 | if (card_res->count_crtcs >= crtc_count) { | ||
| 1054 | copied = 0; | ||
| 1055 | crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; | ||
| 1056 | if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { | ||
| 1057 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, | ||
| 1058 | head) { | ||
| 1059 | DRM_DEBUG("CRTC ID is %d\n", crtc->base.id); | ||
| 1060 | if (put_user(crtc->base.id, crtc_id + copied)) { | ||
| 1061 | ret = -EFAULT; | ||
| 1062 | goto out; | ||
| 1063 | } | ||
| 1064 | copied++; | ||
| 1065 | } | ||
| 1066 | } else { | ||
| 1067 | for (i = 0; i < mode_group->num_crtcs; i++) { | ||
| 1068 | if (put_user(mode_group->id_list[i], | ||
| 1069 | crtc_id + copied)) { | ||
| 1070 | ret = -EFAULT; | ||
| 1071 | goto out; | ||
| 1072 | } | ||
| 1073 | copied++; | ||
| 1074 | } | ||
| 1075 | } | ||
| 1076 | } | ||
| 1077 | card_res->count_crtcs = crtc_count; | ||
| 1078 | |||
| 1079 | /* Encoders */ | ||
| 1080 | if (card_res->count_encoders >= encoder_count) { | ||
| 1081 | copied = 0; | ||
| 1082 | encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; | ||
| 1083 | if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { | ||
| 1084 | list_for_each_entry(encoder, | ||
| 1085 | &dev->mode_config.encoder_list, | ||
| 1086 | head) { | ||
| 1087 | DRM_DEBUG("ENCODER ID is %d\n", | ||
| 1088 | encoder->base.id); | ||
| 1089 | if (put_user(encoder->base.id, encoder_id + | ||
| 1090 | copied)) { | ||
| 1091 | ret = -EFAULT; | ||
| 1092 | goto out; | ||
| 1093 | } | ||
| 1094 | copied++; | ||
| 1095 | } | ||
| 1096 | } else { | ||
| 1097 | for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) { | ||
| 1098 | if (put_user(mode_group->id_list[i], | ||
| 1099 | encoder_id + copied)) { | ||
| 1100 | ret = -EFAULT; | ||
| 1101 | goto out; | ||
| 1102 | } | ||
| 1103 | copied++; | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | } | ||
| 1107 | } | ||
| 1108 | card_res->count_encoders = encoder_count; | ||
| 1109 | |||
| 1110 | /* Connectors */ | ||
| 1111 | if (card_res->count_connectors >= connector_count) { | ||
| 1112 | copied = 0; | ||
| 1113 | connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; | ||
| 1114 | if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { | ||
| 1115 | list_for_each_entry(connector, | ||
| 1116 | &dev->mode_config.connector_list, | ||
| 1117 | head) { | ||
| 1118 | DRM_DEBUG("CONNECTOR ID is %d\n", | ||
| 1119 | connector->base.id); | ||
| 1120 | if (put_user(connector->base.id, | ||
| 1121 | connector_id + copied)) { | ||
| 1122 | ret = -EFAULT; | ||
| 1123 | goto out; | ||
| 1124 | } | ||
| 1125 | copied++; | ||
| 1126 | } | ||
| 1127 | } else { | ||
| 1128 | int start = mode_group->num_crtcs + | ||
| 1129 | mode_group->num_encoders; | ||
| 1130 | for (i = start; i < start + mode_group->num_connectors; i++) { | ||
| 1131 | if (put_user(mode_group->id_list[i], | ||
| 1132 | connector_id + copied)) { | ||
| 1133 | ret = -EFAULT; | ||
| 1134 | goto out; | ||
| 1135 | } | ||
| 1136 | copied++; | ||
| 1137 | } | ||
| 1138 | } | ||
| 1139 | } | ||
| 1140 | card_res->count_connectors = connector_count; | ||
| 1141 | |||
| 1142 | DRM_DEBUG("Counted %d %d %d\n", card_res->count_crtcs, | ||
| 1143 | card_res->count_connectors, card_res->count_encoders); | ||
| 1144 | |||
| 1145 | out: | ||
| 1146 | mutex_unlock(&dev->mode_config.mutex); | ||
| 1147 | return ret; | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | /** | ||
| 1151 | * drm_mode_getcrtc - get CRTC configuration | ||
| 1152 | * @inode: inode from the ioctl | ||
| 1153 | * @filp: file * from the ioctl | ||
| 1154 | * @cmd: cmd from ioctl | ||
| 1155 | * @arg: arg from ioctl | ||
| 1156 | * | ||
| 1157 | * LOCKING: | ||
| 1158 | * Caller? (FIXME) | ||
| 1159 | * | ||
| 1160 | * Construct a CRTC configuration structure to return to the user. | ||
| 1161 | * | ||
| 1162 | * Called by the user via ioctl. | ||
| 1163 | * | ||
| 1164 | * RETURNS: | ||
| 1165 | * Zero on success, errno on failure. | ||
| 1166 | */ | ||
| 1167 | int drm_mode_getcrtc(struct drm_device *dev, | ||
| 1168 | void *data, struct drm_file *file_priv) | ||
| 1169 | { | ||
| 1170 | struct drm_mode_crtc *crtc_resp = data; | ||
| 1171 | struct drm_crtc *crtc; | ||
| 1172 | struct drm_mode_object *obj; | ||
| 1173 | int ret = 0; | ||
| 1174 | |||
| 1175 | mutex_lock(&dev->mode_config.mutex); | ||
| 1176 | |||
| 1177 | obj = drm_mode_object_find(dev, crtc_resp->crtc_id, | ||
| 1178 | DRM_MODE_OBJECT_CRTC); | ||
| 1179 | if (!obj) { | ||
| 1180 | ret = -EINVAL; | ||
| 1181 | goto out; | ||
| 1182 | } | ||
| 1183 | crtc = obj_to_crtc(obj); | ||
| 1184 | |||
| 1185 | crtc_resp->x = crtc->x; | ||
| 1186 | crtc_resp->y = crtc->y; | ||
| 1187 | crtc_resp->gamma_size = crtc->gamma_size; | ||
| 1188 | if (crtc->fb) | ||
| 1189 | crtc_resp->fb_id = crtc->fb->base.id; | ||
| 1190 | else | ||
| 1191 | crtc_resp->fb_id = 0; | ||
| 1192 | |||
| 1193 | if (crtc->enabled) { | ||
| 1194 | |||
| 1195 | drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); | ||
| 1196 | crtc_resp->mode_valid = 1; | ||
| 1197 | |||
| 1198 | } else { | ||
| 1199 | crtc_resp->mode_valid = 0; | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | out: | ||
| 1203 | mutex_unlock(&dev->mode_config.mutex); | ||
| 1204 | return ret; | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | /** | ||
| 1208 | * drm_mode_getconnector - get connector configuration | ||
| 1209 | * @inode: inode from the ioctl | ||
| 1210 | * @filp: file * from the ioctl | ||
| 1211 | * @cmd: cmd from ioctl | ||
| 1212 | * @arg: arg from ioctl | ||
| 1213 | * | ||
| 1214 | * LOCKING: | ||
| 1215 | * Caller? (FIXME) | ||
| 1216 | * | ||
| 1217 | * Construct a connector configuration structure to return to the user. | ||
| 1218 | * | ||
| 1219 | * Called by the user via ioctl. | ||
| 1220 | * | ||
| 1221 | * RETURNS: | ||
| 1222 | * Zero on success, errno on failure. | ||
| 1223 | */ | ||
| 1224 | int drm_mode_getconnector(struct drm_device *dev, void *data, | ||
| 1225 | struct drm_file *file_priv) | ||
| 1226 | { | ||
| 1227 | struct drm_mode_get_connector *out_resp = data; | ||
| 1228 | struct drm_mode_object *obj; | ||
| 1229 | struct drm_connector *connector; | ||
| 1230 | struct drm_display_mode *mode; | ||
| 1231 | int mode_count = 0; | ||
| 1232 | int props_count = 0; | ||
| 1233 | int encoders_count = 0; | ||
| 1234 | int ret = 0; | ||
| 1235 | int copied = 0; | ||
| 1236 | int i; | ||
| 1237 | struct drm_mode_modeinfo u_mode; | ||
| 1238 | struct drm_mode_modeinfo __user *mode_ptr; | ||
| 1239 | uint32_t __user *prop_ptr; | ||
| 1240 | uint64_t __user *prop_values; | ||
| 1241 | uint32_t __user *encoder_ptr; | ||
| 1242 | |||
| 1243 | memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); | ||
| 1244 | |||
| 1245 | DRM_DEBUG("connector id %d:\n", out_resp->connector_id); | ||
| 1246 | |||
| 1247 | mutex_lock(&dev->mode_config.mutex); | ||
| 1248 | |||
| 1249 | obj = drm_mode_object_find(dev, out_resp->connector_id, | ||
| 1250 | DRM_MODE_OBJECT_CONNECTOR); | ||
| 1251 | if (!obj) { | ||
| 1252 | ret = -EINVAL; | ||
| 1253 | goto out; | ||
| 1254 | } | ||
| 1255 | connector = obj_to_connector(obj); | ||
| 1256 | |||
| 1257 | for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { | ||
| 1258 | if (connector->property_ids[i] != 0) { | ||
| 1259 | props_count++; | ||
| 1260 | } | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { | ||
| 1264 | if (connector->encoder_ids[i] != 0) { | ||
| 1265 | encoders_count++; | ||
| 1266 | } | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | if (out_resp->count_modes == 0) { | ||
| 1270 | connector->funcs->fill_modes(connector, | ||
| 1271 | dev->mode_config.max_width, | ||
| 1272 | dev->mode_config.max_height); | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | /* delayed so we get modes regardless of pre-fill_modes state */ | ||
| 1276 | list_for_each_entry(mode, &connector->modes, head) | ||
| 1277 | mode_count++; | ||
| 1278 | |||
| 1279 | out_resp->connector_id = connector->base.id; | ||
| 1280 | out_resp->connector_type = connector->connector_type; | ||
| 1281 | out_resp->connector_type_id = connector->connector_type_id; | ||
| 1282 | out_resp->mm_width = connector->display_info.width_mm; | ||
| 1283 | out_resp->mm_height = connector->display_info.height_mm; | ||
| 1284 | out_resp->subpixel = connector->display_info.subpixel_order; | ||
| 1285 | out_resp->connection = connector->status; | ||
| 1286 | if (connector->encoder) | ||
| 1287 | out_resp->encoder_id = connector->encoder->base.id; | ||
| 1288 | else | ||
| 1289 | out_resp->encoder_id = 0; | ||
| 1290 | |||
| 1291 | /* | ||
| 1292 | * This ioctl is called twice, once to determine how much space is | ||
| 1293 | * needed, and the 2nd time to fill it. | ||
| 1294 | */ | ||
| 1295 | if ((out_resp->count_modes >= mode_count) && mode_count) { | ||
| 1296 | copied = 0; | ||
| 1297 | mode_ptr = (struct drm_mode_modeinfo *)(unsigned long)out_resp->modes_ptr; | ||
| 1298 | list_for_each_entry(mode, &connector->modes, head) { | ||
| 1299 | drm_crtc_convert_to_umode(&u_mode, mode); | ||
| 1300 | if (copy_to_user(mode_ptr + copied, | ||
| 1301 | &u_mode, sizeof(u_mode))) { | ||
| 1302 | ret = -EFAULT; | ||
| 1303 | goto out; | ||
| 1304 | } | ||
| 1305 | copied++; | ||
| 1306 | } | ||
| 1307 | } | ||
| 1308 | out_resp->count_modes = mode_count; | ||
| 1309 | |||
| 1310 | if ((out_resp->count_props >= props_count) && props_count) { | ||
| 1311 | copied = 0; | ||
| 1312 | prop_ptr = (uint32_t *)(unsigned long)(out_resp->props_ptr); | ||
| 1313 | prop_values = (uint64_t *)(unsigned long)(out_resp->prop_values_ptr); | ||
| 1314 | for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { | ||
| 1315 | if (connector->property_ids[i] != 0) { | ||
| 1316 | if (put_user(connector->property_ids[i], | ||
| 1317 | prop_ptr + copied)) { | ||
| 1318 | ret = -EFAULT; | ||
| 1319 | goto out; | ||
| 1320 | } | ||
| 1321 | |||
| 1322 | if (put_user(connector->property_values[i], | ||
| 1323 | prop_values + copied)) { | ||
| 1324 | ret = -EFAULT; | ||
| 1325 | goto out; | ||
| 1326 | } | ||
| 1327 | copied++; | ||
| 1328 | } | ||
| 1329 | } | ||
| 1330 | } | ||
| 1331 | out_resp->count_props = props_count; | ||
| 1332 | |||
| 1333 | if ((out_resp->count_encoders >= encoders_count) && encoders_count) { | ||
| 1334 | copied = 0; | ||
| 1335 | encoder_ptr = (uint32_t *)(unsigned long)(out_resp->encoders_ptr); | ||
| 1336 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { | ||
| 1337 | if (connector->encoder_ids[i] != 0) { | ||
| 1338 | if (put_user(connector->encoder_ids[i], | ||
| 1339 | encoder_ptr + copied)) { | ||
| 1340 | ret = -EFAULT; | ||
| 1341 | goto out; | ||
| 1342 | } | ||
| 1343 | copied++; | ||
| 1344 | } | ||
| 1345 | } | ||
| 1346 | } | ||
| 1347 | out_resp->count_encoders = encoders_count; | ||
| 1348 | |||
| 1349 | out: | ||
| 1350 | mutex_unlock(&dev->mode_config.mutex); | ||
| 1351 | return ret; | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | int drm_mode_getencoder(struct drm_device *dev, void *data, | ||
| 1355 | struct drm_file *file_priv) | ||
| 1356 | { | ||
| 1357 | struct drm_mode_get_encoder *enc_resp = data; | ||
| 1358 | struct drm_mode_object *obj; | ||
| 1359 | struct drm_encoder *encoder; | ||
| 1360 | int ret = 0; | ||
| 1361 | |||
| 1362 | mutex_lock(&dev->mode_config.mutex); | ||
| 1363 | obj = drm_mode_object_find(dev, enc_resp->encoder_id, | ||
| 1364 | DRM_MODE_OBJECT_ENCODER); | ||
| 1365 | if (!obj) { | ||
| 1366 | ret = -EINVAL; | ||
| 1367 | goto out; | ||
| 1368 | } | ||
| 1369 | encoder = obj_to_encoder(obj); | ||
| 1370 | |||
| 1371 | if (encoder->crtc) | ||
| 1372 | enc_resp->crtc_id = encoder->crtc->base.id; | ||
| 1373 | else | ||
| 1374 | enc_resp->crtc_id = 0; | ||
| 1375 | enc_resp->encoder_type = encoder->encoder_type; | ||
| 1376 | enc_resp->encoder_id = encoder->base.id; | ||
| 1377 | enc_resp->possible_crtcs = encoder->possible_crtcs; | ||
| 1378 | enc_resp->possible_clones = encoder->possible_clones; | ||
| 1379 | |||
| 1380 | out: | ||
| 1381 | mutex_unlock(&dev->mode_config.mutex); | ||
| 1382 | return ret; | ||
| 1383 | } | ||
| 1384 | |||
| 1385 | /** | ||
| 1386 | * drm_mode_setcrtc - set CRTC configuration | ||
| 1387 | * @inode: inode from the ioctl | ||
| 1388 | * @filp: file * from the ioctl | ||
| 1389 | * @cmd: cmd from ioctl | ||
| 1390 | * @arg: arg from ioctl | ||
| 1391 | * | ||
| 1392 | * LOCKING: | ||
| 1393 | * Caller? (FIXME) | ||
| 1394 | * | ||
| 1395 | * Build a new CRTC configuration based on user request. | ||
| 1396 | * | ||
| 1397 | * Called by the user via ioctl. | ||
| 1398 | * | ||
| 1399 | * RETURNS: | ||
| 1400 | * Zero on success, errno on failure. | ||
| 1401 | */ | ||
| 1402 | int drm_mode_setcrtc(struct drm_device *dev, void *data, | ||
| 1403 | struct drm_file *file_priv) | ||
| 1404 | { | ||
| 1405 | struct drm_mode_config *config = &dev->mode_config; | ||
| 1406 | struct drm_mode_crtc *crtc_req = data; | ||
| 1407 | struct drm_mode_object *obj; | ||
| 1408 | struct drm_crtc *crtc, *crtcfb; | ||
| 1409 | struct drm_connector **connector_set = NULL, *connector; | ||
| 1410 | struct drm_framebuffer *fb = NULL; | ||
| 1411 | struct drm_display_mode *mode = NULL; | ||
| 1412 | struct drm_mode_set set; | ||
| 1413 | uint32_t __user *set_connectors_ptr; | ||
| 1414 | int ret = 0; | ||
| 1415 | int i; | ||
| 1416 | |||
| 1417 | mutex_lock(&dev->mode_config.mutex); | ||
| 1418 | obj = drm_mode_object_find(dev, crtc_req->crtc_id, | ||
| 1419 | DRM_MODE_OBJECT_CRTC); | ||
| 1420 | if (!obj) { | ||
| 1421 | DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req->crtc_id); | ||
| 1422 | ret = -EINVAL; | ||
| 1423 | goto out; | ||
| 1424 | } | ||
| 1425 | crtc = obj_to_crtc(obj); | ||
| 1426 | |||
| 1427 | if (crtc_req->mode_valid) { | ||
| 1428 | /* If we have a mode we need a framebuffer. */ | ||
| 1429 | /* If we pass -1, set the mode with the currently bound fb */ | ||
| 1430 | if (crtc_req->fb_id == -1) { | ||
| 1431 | list_for_each_entry(crtcfb, | ||
| 1432 | &dev->mode_config.crtc_list, head) { | ||
| 1433 | if (crtcfb == crtc) { | ||
| 1434 | DRM_DEBUG("Using current fb for setmode\n"); | ||
| 1435 | fb = crtc->fb; | ||
| 1436 | } | ||
| 1437 | } | ||
| 1438 | } else { | ||
| 1439 | obj = drm_mode_object_find(dev, crtc_req->fb_id, | ||
| 1440 | DRM_MODE_OBJECT_FB); | ||
| 1441 | if (!obj) { | ||
| 1442 | DRM_DEBUG("Unknown FB ID%d\n", crtc_req->fb_id); | ||
| 1443 | ret = -EINVAL; | ||
| 1444 | goto out; | ||
| 1445 | } | ||
| 1446 | fb = obj_to_fb(obj); | ||
| 1447 | } | ||
| 1448 | |||
| 1449 | mode = drm_mode_create(dev); | ||
| 1450 | drm_crtc_convert_umode(mode, &crtc_req->mode); | ||
| 1451 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); | ||
| 1452 | } | ||
| 1453 | |||
| 1454 | if (crtc_req->count_connectors == 0 && mode) { | ||
| 1455 | DRM_DEBUG("Count connectors is 0 but mode set\n"); | ||
| 1456 | ret = -EINVAL; | ||
| 1457 | goto out; | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | if (crtc_req->count_connectors > 0 && !mode && !fb) { | ||
| 1461 | DRM_DEBUG("Count connectors is %d but no mode or fb set\n", | ||
| 1462 | crtc_req->count_connectors); | ||
| 1463 | ret = -EINVAL; | ||
| 1464 | goto out; | ||
| 1465 | } | ||
| 1466 | |||
| 1467 | if (crtc_req->count_connectors > 0) { | ||
| 1468 | u32 out_id; | ||
| 1469 | |||
| 1470 | /* Avoid unbounded kernel memory allocation */ | ||
| 1471 | if (crtc_req->count_connectors > config->num_connector) { | ||
| 1472 | ret = -EINVAL; | ||
| 1473 | goto out; | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | connector_set = kmalloc(crtc_req->count_connectors * | ||
| 1477 | sizeof(struct drm_connector *), | ||
| 1478 | GFP_KERNEL); | ||
| 1479 | if (!connector_set) { | ||
| 1480 | ret = -ENOMEM; | ||
| 1481 | goto out; | ||
| 1482 | } | ||
| 1483 | |||
| 1484 | for (i = 0; i < crtc_req->count_connectors; i++) { | ||
| 1485 | set_connectors_ptr = (uint32_t *)(unsigned long)crtc_req->set_connectors_ptr; | ||
| 1486 | if (get_user(out_id, &set_connectors_ptr[i])) { | ||
| 1487 | ret = -EFAULT; | ||
| 1488 | goto out; | ||
| 1489 | } | ||
| 1490 | |||
| 1491 | obj = drm_mode_object_find(dev, out_id, | ||
| 1492 | DRM_MODE_OBJECT_CONNECTOR); | ||
| 1493 | if (!obj) { | ||
| 1494 | DRM_DEBUG("Connector id %d unknown\n", out_id); | ||
| 1495 | ret = -EINVAL; | ||
| 1496 | goto out; | ||
| 1497 | } | ||
| 1498 | connector = obj_to_connector(obj); | ||
| 1499 | |||
| 1500 | connector_set[i] = connector; | ||
| 1501 | } | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | set.crtc = crtc; | ||
| 1505 | set.x = crtc_req->x; | ||
| 1506 | set.y = crtc_req->y; | ||
| 1507 | set.mode = mode; | ||
| 1508 | set.connectors = connector_set; | ||
| 1509 | set.num_connectors = crtc_req->count_connectors; | ||
| 1510 | set.fb =fb; | ||
| 1511 | ret = crtc->funcs->set_config(&set); | ||
| 1512 | |||
| 1513 | out: | ||
| 1514 | kfree(connector_set); | ||
| 1515 | mutex_unlock(&dev->mode_config.mutex); | ||
| 1516 | return ret; | ||
| 1517 | } | ||
| 1518 | |||
| 1519 | int drm_mode_cursor_ioctl(struct drm_device *dev, | ||
| 1520 | void *data, struct drm_file *file_priv) | ||
| 1521 | { | ||
| 1522 | struct drm_mode_cursor *req = data; | ||
| 1523 | struct drm_mode_object *obj; | ||
| 1524 | struct drm_crtc *crtc; | ||
| 1525 | int ret = 0; | ||
| 1526 | |||
| 1527 | DRM_DEBUG("\n"); | ||
| 1528 | |||
| 1529 | if (!req->flags) { | ||
| 1530 | DRM_ERROR("no operation set\n"); | ||
| 1531 | return -EINVAL; | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | mutex_lock(&dev->mode_config.mutex); | ||
| 1535 | obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC); | ||
| 1536 | if (!obj) { | ||
| 1537 | DRM_DEBUG("Unknown CRTC ID %d\n", req->crtc_id); | ||
| 1538 | ret = -EINVAL; | ||
| 1539 | goto out; | ||
| 1540 | } | ||
| 1541 | crtc = obj_to_crtc(obj); | ||
| 1542 | |||
| 1543 | if (req->flags & DRM_MODE_CURSOR_BO) { | ||
| 1544 | if (!crtc->funcs->cursor_set) { | ||
| 1545 | DRM_ERROR("crtc does not support cursor\n"); | ||
| 1546 | ret = -ENXIO; | ||
| 1547 | goto out; | ||
| 1548 | } | ||
| 1549 | /* Turns off the cursor if handle is 0 */ | ||
| 1550 | ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, | ||
| 1551 | req->width, req->height); | ||
| 1552 | } | ||
| 1553 | |||
| 1554 | if (req->flags & DRM_MODE_CURSOR_MOVE) { | ||
| 1555 | if (crtc->funcs->cursor_move) { | ||
| 1556 | ret = crtc->funcs->cursor_move(crtc, req->x, req->y); | ||
| 1557 | } else { | ||
| 1558 | DRM_ERROR("crtc does not support cursor\n"); | ||
| 1559 | ret = -EFAULT; | ||
| 1560 | goto out; | ||
| 1561 | } | ||
| 1562 | } | ||
| 1563 | out: | ||
| 1564 | mutex_unlock(&dev->mode_config.mutex); | ||
| 1565 | return ret; | ||
| 1566 | } | ||
| 1567 | |||
| 1568 | /** | ||
| 1569 | * drm_mode_addfb - add an FB to the graphics configuration | ||
| 1570 | * @inode: inode from the ioctl | ||
| 1571 | * @filp: file * from the ioctl | ||
| 1572 | * @cmd: cmd from ioctl | ||
| 1573 | * @arg: arg from ioctl | ||
| 1574 | * | ||
| 1575 | * LOCKING: | ||
| 1576 | * Takes mode config lock. | ||
| 1577 | * | ||
| 1578 | * Add a new FB to the specified CRTC, given a user request. | ||
| 1579 | * | ||
| 1580 | * Called by the user via ioctl. | ||
| 1581 | * | ||
| 1582 | * RETURNS: | ||
| 1583 | * Zero on success, errno on failure. | ||
| 1584 | */ | ||
| 1585 | int drm_mode_addfb(struct drm_device *dev, | ||
| 1586 | void *data, struct drm_file *file_priv) | ||
| 1587 | { | ||
| 1588 | struct drm_mode_fb_cmd *r = data; | ||
| 1589 | struct drm_mode_config *config = &dev->mode_config; | ||
| 1590 | struct drm_framebuffer *fb; | ||
| 1591 | int ret = 0; | ||
| 1592 | |||
| 1593 | if ((config->min_width > r->width) || (r->width > config->max_width)) { | ||
| 1594 | DRM_ERROR("mode new framebuffer width not within limits\n"); | ||
| 1595 | return -EINVAL; | ||
| 1596 | } | ||
| 1597 | if ((config->min_height > r->height) || (r->height > config->max_height)) { | ||
| 1598 | DRM_ERROR("mode new framebuffer height not within limits\n"); | ||
| 1599 | return -EINVAL; | ||
| 1600 | } | ||
| 1601 | |||
| 1602 | mutex_lock(&dev->mode_config.mutex); | ||
| 1603 | |||
| 1604 | /* TODO check buffer is sufficently large */ | ||
| 1605 | /* TODO setup destructor callback */ | ||
| 1606 | |||
| 1607 | fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); | ||
| 1608 | if (!fb) { | ||
| 1609 | DRM_ERROR("could not create framebuffer\n"); | ||
| 1610 | ret = -EINVAL; | ||
| 1611 | goto out; | ||
| 1612 | } | ||
| 1613 | |||
| 1614 | r->fb_id = fb->base.id; | ||
| 1615 | list_add(&fb->filp_head, &file_priv->fbs); | ||
| 1616 | |||
| 1617 | out: | ||
| 1618 | mutex_unlock(&dev->mode_config.mutex); | ||
| 1619 | return ret; | ||
| 1620 | } | ||
| 1621 | |||
| 1622 | /** | ||
| 1623 | * drm_mode_rmfb - remove an FB from the configuration | ||
| 1624 | * @inode: inode from the ioctl | ||
| 1625 | * @filp: file * from the ioctl | ||
| 1626 | * @cmd: cmd from ioctl | ||
| 1627 | * @arg: arg from ioctl | ||
| 1628 | * | ||
| 1629 | * LOCKING: | ||
| 1630 | * Takes mode config lock. | ||
| 1631 | * | ||
| 1632 | * Remove the FB specified by the user. | ||
| 1633 | * | ||
| 1634 | * Called by the user via ioctl. | ||
| 1635 | * | ||
| 1636 | * RETURNS: | ||
| 1637 | * Zero on success, errno on failure. | ||
| 1638 | */ | ||
| 1639 | int drm_mode_rmfb(struct drm_device *dev, | ||
| 1640 | void *data, struct drm_file *file_priv) | ||
| 1641 | { | ||
| 1642 | struct drm_mode_object *obj; | ||
| 1643 | struct drm_framebuffer *fb = NULL; | ||
| 1644 | struct drm_framebuffer *fbl = NULL; | ||
| 1645 | uint32_t *id = data; | ||
| 1646 | int ret = 0; | ||
| 1647 | int found = 0; | ||
| 1648 | |||
| 1649 | mutex_lock(&dev->mode_config.mutex); | ||
| 1650 | obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB); | ||
| 1651 | /* TODO check that we realy get a framebuffer back. */ | ||
| 1652 | if (!obj) { | ||
| 1653 | DRM_ERROR("mode invalid framebuffer id\n"); | ||
| 1654 | ret = -EINVAL; | ||
| 1655 | goto out; | ||
| 1656 | } | ||
| 1657 | fb = obj_to_fb(obj); | ||
| 1658 | |||
| 1659 | list_for_each_entry(fbl, &file_priv->fbs, filp_head) | ||
| 1660 | if (fb == fbl) | ||
| 1661 | found = 1; | ||
| 1662 | |||
| 1663 | if (!found) { | ||
| 1664 | DRM_ERROR("tried to remove a fb that we didn't own\n"); | ||
| 1665 | ret = -EINVAL; | ||
| 1666 | goto out; | ||
| 1667 | } | ||
| 1668 | |||
| 1669 | /* TODO release all crtc connected to the framebuffer */ | ||
| 1670 | /* TODO unhock the destructor from the buffer object */ | ||
| 1671 | |||
| 1672 | list_del(&fb->filp_head); | ||
| 1673 | fb->funcs->destroy(fb); | ||
| 1674 | |||
| 1675 | out: | ||
| 1676 | mutex_unlock(&dev->mode_config.mutex); | ||
| 1677 | return ret; | ||
| 1678 | } | ||
| 1679 | |||
| 1680 | /** | ||
| 1681 | * drm_mode_getfb - get FB info | ||
| 1682 | * @inode: inode from the ioctl | ||
| 1683 | * @filp: file * from the ioctl | ||
| 1684 | * @cmd: cmd from ioctl | ||
| 1685 | * @arg: arg from ioctl | ||
| 1686 | * | ||
| 1687 | * LOCKING: | ||
| 1688 | * Caller? (FIXME) | ||
| 1689 | * | ||
| 1690 | * Lookup the FB given its ID and return info about it. | ||
| 1691 | * | ||
| 1692 | * Called by the user via ioctl. | ||
| 1693 | * | ||
| 1694 | * RETURNS: | ||
| 1695 | * Zero on success, errno on failure. | ||
| 1696 | */ | ||
| 1697 | int drm_mode_getfb(struct drm_device *dev, | ||
| 1698 | void *data, struct drm_file *file_priv) | ||
| 1699 | { | ||
| 1700 | struct drm_mode_fb_cmd *r = data; | ||
| 1701 | struct drm_mode_object *obj; | ||
| 1702 | struct drm_framebuffer *fb; | ||
| 1703 | int ret = 0; | ||
| 1704 | |||
| 1705 | mutex_lock(&dev->mode_config.mutex); | ||
| 1706 | obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); | ||
| 1707 | if (!obj) { | ||
| 1708 | DRM_ERROR("invalid framebuffer id\n"); | ||
| 1709 | ret = -EINVAL; | ||
| 1710 | goto out; | ||
| 1711 | } | ||
| 1712 | fb = obj_to_fb(obj); | ||
| 1713 | |||
| 1714 | r->height = fb->height; | ||
| 1715 | r->width = fb->width; | ||
| 1716 | r->depth = fb->depth; | ||
| 1717 | r->bpp = fb->bits_per_pixel; | ||
| 1718 | r->pitch = fb->pitch; | ||
| 1719 | fb->funcs->create_handle(fb, file_priv, &r->handle); | ||
| 1720 | |||
| 1721 | out: | ||
| 1722 | mutex_unlock(&dev->mode_config.mutex); | ||
| 1723 | return ret; | ||
| 1724 | } | ||
| 1725 | |||
| 1726 | /** | ||
| 1727 | * drm_fb_release - remove and free the FBs on this file | ||
| 1728 | * @filp: file * from the ioctl | ||
| 1729 | * | ||
| 1730 | * LOCKING: | ||
| 1731 | * Takes mode config lock. | ||
| 1732 | * | ||
| 1733 | * Destroy all the FBs associated with @filp. | ||
| 1734 | * | ||
| 1735 | * Called by the user via ioctl. | ||
| 1736 | * | ||
| 1737 | * RETURNS: | ||
| 1738 | * Zero on success, errno on failure. | ||
| 1739 | */ | ||
| 1740 | void drm_fb_release(struct file *filp) | ||
| 1741 | { | ||
| 1742 | struct drm_file *priv = filp->private_data; | ||
| 1743 | struct drm_device *dev = priv->minor->dev; | ||
| 1744 | struct drm_framebuffer *fb, *tfb; | ||
| 1745 | |||
| 1746 | mutex_lock(&dev->mode_config.mutex); | ||
| 1747 | list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { | ||
| 1748 | list_del(&fb->filp_head); | ||
| 1749 | fb->funcs->destroy(fb); | ||
| 1750 | } | ||
| 1751 | mutex_unlock(&dev->mode_config.mutex); | ||
| 1752 | } | ||
| 1753 | |||
| 1754 | /** | ||
| 1755 | * drm_mode_attachmode - add a mode to the user mode list | ||
| 1756 | * @dev: DRM device | ||
| 1757 | * @connector: connector to add the mode to | ||
| 1758 | * @mode: mode to add | ||
| 1759 | * | ||
| 1760 | * Add @mode to @connector's user mode list. | ||
| 1761 | */ | ||
| 1762 | static int drm_mode_attachmode(struct drm_device *dev, | ||
| 1763 | struct drm_connector *connector, | ||
| 1764 | struct drm_display_mode *mode) | ||
| 1765 | { | ||
| 1766 | int ret = 0; | ||
| 1767 | |||
| 1768 | list_add_tail(&mode->head, &connector->user_modes); | ||
| 1769 | return ret; | ||
| 1770 | } | ||
| 1771 | |||
| 1772 | int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, | ||
| 1773 | struct drm_display_mode *mode) | ||
| 1774 | { | ||
| 1775 | struct drm_connector *connector; | ||
| 1776 | int ret = 0; | ||
| 1777 | struct drm_display_mode *dup_mode; | ||
| 1778 | int need_dup = 0; | ||
| 1779 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 1780 | if (!connector->encoder) | ||
| 1781 | break; | ||
| 1782 | if (connector->encoder->crtc == crtc) { | ||
| 1783 | if (need_dup) | ||
| 1784 | dup_mode = drm_mode_duplicate(dev, mode); | ||
| 1785 | else | ||
| 1786 | dup_mode = mode; | ||
| 1787 | ret = drm_mode_attachmode(dev, connector, dup_mode); | ||
| 1788 | if (ret) | ||
| 1789 | return ret; | ||
| 1790 | need_dup = 1; | ||
| 1791 | } | ||
| 1792 | } | ||
| 1793 | return 0; | ||
| 1794 | } | ||
| 1795 | EXPORT_SYMBOL(drm_mode_attachmode_crtc); | ||
| 1796 | |||
| 1797 | static int drm_mode_detachmode(struct drm_device *dev, | ||
| 1798 | struct drm_connector *connector, | ||
| 1799 | struct drm_display_mode *mode) | ||
| 1800 | { | ||
| 1801 | int found = 0; | ||
| 1802 | int ret = 0; | ||
| 1803 | struct drm_display_mode *match_mode, *t; | ||
| 1804 | |||
| 1805 | list_for_each_entry_safe(match_mode, t, &connector->user_modes, head) { | ||
| 1806 | if (drm_mode_equal(match_mode, mode)) { | ||
| 1807 | list_del(&match_mode->head); | ||
| 1808 | drm_mode_destroy(dev, match_mode); | ||
| 1809 | found = 1; | ||
| 1810 | break; | ||
| 1811 | } | ||
| 1812 | } | ||
| 1813 | |||
| 1814 | if (!found) | ||
| 1815 | ret = -EINVAL; | ||
| 1816 | |||
| 1817 | return ret; | ||
| 1818 | } | ||
| 1819 | |||
| 1820 | int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode) | ||
| 1821 | { | ||
| 1822 | struct drm_connector *connector; | ||
| 1823 | |||
| 1824 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 1825 | drm_mode_detachmode(dev, connector, mode); | ||
| 1826 | } | ||
| 1827 | return 0; | ||
| 1828 | } | ||
| 1829 | EXPORT_SYMBOL(drm_mode_detachmode_crtc); | ||
| 1830 | |||
| 1831 | /** | ||
| 1832 | * drm_fb_attachmode - Attach a user mode to an connector | ||
| 1833 | * @inode: inode from the ioctl | ||
| 1834 | * @filp: file * from the ioctl | ||
| 1835 | * @cmd: cmd from ioctl | ||
| 1836 | * @arg: arg from ioctl | ||
| 1837 | * | ||
| 1838 | * This attaches a user specified mode to an connector. | ||
| 1839 | * Called by the user via ioctl. | ||
| 1840 | * | ||
| 1841 | * RETURNS: | ||
| 1842 | * Zero on success, errno on failure. | ||
| 1843 | */ | ||
| 1844 | int drm_mode_attachmode_ioctl(struct drm_device *dev, | ||
| 1845 | void *data, struct drm_file *file_priv) | ||
| 1846 | { | ||
| 1847 | struct drm_mode_mode_cmd *mode_cmd = data; | ||
| 1848 | struct drm_connector *connector; | ||
| 1849 | struct drm_display_mode *mode; | ||
| 1850 | struct drm_mode_object *obj; | ||
| 1851 | struct drm_mode_modeinfo *umode = &mode_cmd->mode; | ||
| 1852 | int ret = 0; | ||
| 1853 | |||
| 1854 | mutex_lock(&dev->mode_config.mutex); | ||
| 1855 | |||
| 1856 | obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); | ||
| 1857 | if (!obj) { | ||
| 1858 | ret = -EINVAL; | ||
| 1859 | goto out; | ||
| 1860 | } | ||
| 1861 | connector = obj_to_connector(obj); | ||
| 1862 | |||
| 1863 | mode = drm_mode_create(dev); | ||
| 1864 | if (!mode) { | ||
| 1865 | ret = -ENOMEM; | ||
| 1866 | goto out; | ||
| 1867 | } | ||
| 1868 | |||
| 1869 | drm_crtc_convert_umode(mode, umode); | ||
| 1870 | |||
| 1871 | ret = drm_mode_attachmode(dev, connector, mode); | ||
| 1872 | out: | ||
| 1873 | mutex_unlock(&dev->mode_config.mutex); | ||
| 1874 | return ret; | ||
| 1875 | } | ||
| 1876 | |||
| 1877 | |||
| 1878 | /** | ||
| 1879 | * drm_fb_detachmode - Detach a user specified mode from an connector | ||
| 1880 | * @inode: inode from the ioctl | ||
| 1881 | * @filp: file * from the ioctl | ||
| 1882 | * @cmd: cmd from ioctl | ||
| 1883 | * @arg: arg from ioctl | ||
| 1884 | * | ||
| 1885 | * Called by the user via ioctl. | ||
| 1886 | * | ||
| 1887 | * RETURNS: | ||
| 1888 | * Zero on success, errno on failure. | ||
| 1889 | */ | ||
| 1890 | int drm_mode_detachmode_ioctl(struct drm_device *dev, | ||
| 1891 | void *data, struct drm_file *file_priv) | ||
| 1892 | { | ||
| 1893 | struct drm_mode_object *obj; | ||
| 1894 | struct drm_mode_mode_cmd *mode_cmd = data; | ||
| 1895 | struct drm_connector *connector; | ||
| 1896 | struct drm_display_mode mode; | ||
| 1897 | struct drm_mode_modeinfo *umode = &mode_cmd->mode; | ||
| 1898 | int ret = 0; | ||
| 1899 | |||
| 1900 | mutex_lock(&dev->mode_config.mutex); | ||
| 1901 | |||
| 1902 | obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); | ||
| 1903 | if (!obj) { | ||
| 1904 | ret = -EINVAL; | ||
| 1905 | goto out; | ||
| 1906 | } | ||
| 1907 | connector = obj_to_connector(obj); | ||
| 1908 | |||
| 1909 | drm_crtc_convert_umode(&mode, umode); | ||
| 1910 | ret = drm_mode_detachmode(dev, connector, &mode); | ||
| 1911 | out: | ||
| 1912 | mutex_unlock(&dev->mode_config.mutex); | ||
| 1913 | return ret; | ||
| 1914 | } | ||
| 1915 | |||
| 1916 | struct drm_property *drm_property_create(struct drm_device *dev, int flags, | ||
| 1917 | const char *name, int num_values) | ||
| 1918 | { | ||
| 1919 | struct drm_property *property = NULL; | ||
| 1920 | |||
| 1921 | property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); | ||
| 1922 | if (!property) | ||
| 1923 | return NULL; | ||
| 1924 | |||
| 1925 | if (num_values) { | ||
| 1926 | property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL); | ||
| 1927 | if (!property->values) | ||
| 1928 | goto fail; | ||
| 1929 | } | ||
| 1930 | |||
| 1931 | drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); | ||
| 1932 | property->flags = flags; | ||
| 1933 | property->num_values = num_values; | ||
| 1934 | INIT_LIST_HEAD(&property->enum_blob_list); | ||
| 1935 | |||
| 1936 | if (name) | ||
| 1937 | strncpy(property->name, name, DRM_PROP_NAME_LEN); | ||
| 1938 | |||
| 1939 | list_add_tail(&property->head, &dev->mode_config.property_list); | ||
| 1940 | return property; | ||
| 1941 | fail: | ||
| 1942 | kfree(property); | ||
| 1943 | return NULL; | ||
| 1944 | } | ||
| 1945 | EXPORT_SYMBOL(drm_property_create); | ||
| 1946 | |||
| 1947 | int drm_property_add_enum(struct drm_property *property, int index, | ||
| 1948 | uint64_t value, const char *name) | ||
| 1949 | { | ||
| 1950 | struct drm_property_enum *prop_enum; | ||
| 1951 | |||
| 1952 | if (!(property->flags & DRM_MODE_PROP_ENUM)) | ||
| 1953 | return -EINVAL; | ||
| 1954 | |||
| 1955 | if (!list_empty(&property->enum_blob_list)) { | ||
| 1956 | list_for_each_entry(prop_enum, &property->enum_blob_list, head) { | ||
| 1957 | if (prop_enum->value == value) { | ||
| 1958 | strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); | ||
| 1959 | prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; | ||
| 1960 | return 0; | ||
| 1961 | } | ||
| 1962 | } | ||
| 1963 | } | ||
| 1964 | |||
| 1965 | prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); | ||
| 1966 | if (!prop_enum) | ||
| 1967 | return -ENOMEM; | ||
| 1968 | |||
| 1969 | strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); | ||
| 1970 | prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; | ||
| 1971 | prop_enum->value = value; | ||
| 1972 | |||
| 1973 | property->values[index] = value; | ||
| 1974 | list_add_tail(&prop_enum->head, &property->enum_blob_list); | ||
| 1975 | return 0; | ||
| 1976 | } | ||
| 1977 | EXPORT_SYMBOL(drm_property_add_enum); | ||
| 1978 | |||
| 1979 | void drm_property_destroy(struct drm_device *dev, struct drm_property *property) | ||
| 1980 | { | ||
| 1981 | struct drm_property_enum *prop_enum, *pt; | ||
| 1982 | |||
| 1983 | list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) { | ||
| 1984 | list_del(&prop_enum->head); | ||
| 1985 | kfree(prop_enum); | ||
| 1986 | } | ||
| 1987 | |||
| 1988 | if (property->num_values) | ||
| 1989 | kfree(property->values); | ||
| 1990 | drm_mode_object_put(dev, &property->base); | ||
| 1991 | list_del(&property->head); | ||
| 1992 | kfree(property); | ||
| 1993 | } | ||
| 1994 | EXPORT_SYMBOL(drm_property_destroy); | ||
| 1995 | |||
| 1996 | int drm_connector_attach_property(struct drm_connector *connector, | ||
| 1997 | struct drm_property *property, uint64_t init_val) | ||
| 1998 | { | ||
| 1999 | int i; | ||
| 2000 | |||
| 2001 | for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { | ||
| 2002 | if (connector->property_ids[i] == 0) { | ||
| 2003 | connector->property_ids[i] = property->base.id; | ||
| 2004 | connector->property_values[i] = init_val; | ||
| 2005 | break; | ||
| 2006 | } | ||
| 2007 | } | ||
| 2008 | |||
| 2009 | if (i == DRM_CONNECTOR_MAX_PROPERTY) | ||
| 2010 | return -EINVAL; | ||
| 2011 | return 0; | ||
| 2012 | } | ||
| 2013 | EXPORT_SYMBOL(drm_connector_attach_property); | ||
| 2014 | |||
| 2015 | int drm_connector_property_set_value(struct drm_connector *connector, | ||
| 2016 | struct drm_property *property, uint64_t value) | ||
| 2017 | { | ||
| 2018 | int i; | ||
| 2019 | |||
| 2020 | for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { | ||
| 2021 | if (connector->property_ids[i] == property->base.id) { | ||
| 2022 | connector->property_values[i] = value; | ||
| 2023 | break; | ||
| 2024 | } | ||
| 2025 | } | ||
| 2026 | |||
| 2027 | if (i == DRM_CONNECTOR_MAX_PROPERTY) | ||
| 2028 | return -EINVAL; | ||
| 2029 | return 0; | ||
| 2030 | } | ||
| 2031 | EXPORT_SYMBOL(drm_connector_property_set_value); | ||
| 2032 | |||
| 2033 | int drm_connector_property_get_value(struct drm_connector *connector, | ||
| 2034 | struct drm_property *property, uint64_t *val) | ||
| 2035 | { | ||
| 2036 | int i; | ||
| 2037 | |||
| 2038 | for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { | ||
| 2039 | if (connector->property_ids[i] == property->base.id) { | ||
| 2040 | *val = connector->property_values[i]; | ||
| 2041 | break; | ||
| 2042 | } | ||
| 2043 | } | ||
| 2044 | |||
| 2045 | if (i == DRM_CONNECTOR_MAX_PROPERTY) | ||
| 2046 | return -EINVAL; | ||
| 2047 | return 0; | ||
| 2048 | } | ||
| 2049 | EXPORT_SYMBOL(drm_connector_property_get_value); | ||
| 2050 | |||
| 2051 | int drm_mode_getproperty_ioctl(struct drm_device *dev, | ||
| 2052 | void *data, struct drm_file *file_priv) | ||
| 2053 | { | ||
| 2054 | struct drm_mode_object *obj; | ||
| 2055 | struct drm_mode_get_property *out_resp = data; | ||
| 2056 | struct drm_property *property; | ||
| 2057 | int enum_count = 0; | ||
| 2058 | int blob_count = 0; | ||
| 2059 | int value_count = 0; | ||
| 2060 | int ret = 0, i; | ||
| 2061 | int copied; | ||
| 2062 | struct drm_property_enum *prop_enum; | ||
| 2063 | struct drm_mode_property_enum __user *enum_ptr; | ||
| 2064 | struct drm_property_blob *prop_blob; | ||
| 2065 | uint32_t *blob_id_ptr; | ||
| 2066 | uint64_t __user *values_ptr; | ||
| 2067 | uint32_t __user *blob_length_ptr; | ||
| 2068 | |||
| 2069 | mutex_lock(&dev->mode_config.mutex); | ||
| 2070 | obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); | ||
| 2071 | if (!obj) { | ||
| 2072 | ret = -EINVAL; | ||
| 2073 | goto done; | ||
| 2074 | } | ||
| 2075 | property = obj_to_property(obj); | ||
| 2076 | |||
| 2077 | if (property->flags & DRM_MODE_PROP_ENUM) { | ||
| 2078 | list_for_each_entry(prop_enum, &property->enum_blob_list, head) | ||
| 2079 | enum_count++; | ||
| 2080 | } else if (property->flags & DRM_MODE_PROP_BLOB) { | ||
| 2081 | list_for_each_entry(prop_blob, &property->enum_blob_list, head) | ||
| 2082 | blob_count++; | ||
| 2083 | } | ||
| 2084 | |||
| 2085 | value_count = property->num_values; | ||
| 2086 | |||
| 2087 | strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); | ||
| 2088 | out_resp->name[DRM_PROP_NAME_LEN-1] = 0; | ||
| 2089 | out_resp->flags = property->flags; | ||
| 2090 | |||
| 2091 | if ((out_resp->count_values >= value_count) && value_count) { | ||
| 2092 | values_ptr = (uint64_t *)(unsigned long)out_resp->values_ptr; | ||
| 2093 | for (i = 0; i < value_count; i++) { | ||
| 2094 | if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { | ||
| 2095 | ret = -EFAULT; | ||
| 2096 | goto done; | ||
| 2097 | } | ||
| 2098 | } | ||
| 2099 | } | ||
| 2100 | out_resp->count_values = value_count; | ||
| 2101 | |||
| 2102 | if (property->flags & DRM_MODE_PROP_ENUM) { | ||
| 2103 | if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { | ||
| 2104 | copied = 0; | ||
| 2105 | enum_ptr = (struct drm_mode_property_enum *)(unsigned long)out_resp->enum_blob_ptr; | ||
| 2106 | list_for_each_entry(prop_enum, &property->enum_blob_list, head) { | ||
| 2107 | |||
| 2108 | if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { | ||
| 2109 | ret = -EFAULT; | ||
| 2110 | goto done; | ||
| 2111 | } | ||
| 2112 | |||
| 2113 | if (copy_to_user(&enum_ptr[copied].name, | ||
| 2114 | &prop_enum->name, DRM_PROP_NAME_LEN)) { | ||
| 2115 | ret = -EFAULT; | ||
| 2116 | goto done; | ||
| 2117 | } | ||
| 2118 | copied++; | ||
| 2119 | } | ||
| 2120 | } | ||
| 2121 | out_resp->count_enum_blobs = enum_count; | ||
| 2122 | } | ||
| 2123 | |||
| 2124 | if (property->flags & DRM_MODE_PROP_BLOB) { | ||
| 2125 | if ((out_resp->count_enum_blobs >= blob_count) && blob_count) { | ||
| 2126 | copied = 0; | ||
| 2127 | blob_id_ptr = (uint32_t *)(unsigned long)out_resp->enum_blob_ptr; | ||
| 2128 | blob_length_ptr = (uint32_t *)(unsigned long)out_resp->values_ptr; | ||
| 2129 | |||
| 2130 | list_for_each_entry(prop_blob, &property->enum_blob_list, head) { | ||
| 2131 | if (put_user(prop_blob->base.id, blob_id_ptr + copied)) { | ||
| 2132 | ret = -EFAULT; | ||
| 2133 | goto done; | ||
| 2134 | } | ||
| 2135 | |||
| 2136 | if (put_user(prop_blob->length, blob_length_ptr + copied)) { | ||
| 2137 | ret = -EFAULT; | ||
| 2138 | goto done; | ||
| 2139 | } | ||
| 2140 | |||
| 2141 | copied++; | ||
| 2142 | } | ||
| 2143 | } | ||
| 2144 | out_resp->count_enum_blobs = blob_count; | ||
| 2145 | } | ||
| 2146 | done: | ||
| 2147 | mutex_unlock(&dev->mode_config.mutex); | ||
| 2148 | return ret; | ||
| 2149 | } | ||
| 2150 | |||
| 2151 | static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length, | ||
| 2152 | void *data) | ||
| 2153 | { | ||
| 2154 | struct drm_property_blob *blob; | ||
| 2155 | |||
| 2156 | if (!length || !data) | ||
| 2157 | return NULL; | ||
| 2158 | |||
| 2159 | blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); | ||
| 2160 | if (!blob) | ||
| 2161 | return NULL; | ||
| 2162 | |||
| 2163 | blob->data = (void *)((char *)blob + sizeof(struct drm_property_blob)); | ||
| 2164 | blob->length = length; | ||
| 2165 | |||
| 2166 | memcpy(blob->data, data, length); | ||
| 2167 | |||
| 2168 | drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); | ||
| 2169 | |||
| 2170 | list_add_tail(&blob->head, &dev->mode_config.property_blob_list); | ||
| 2171 | return blob; | ||
| 2172 | } | ||
| 2173 | |||
| 2174 | static void drm_property_destroy_blob(struct drm_device *dev, | ||
| 2175 | struct drm_property_blob *blob) | ||
| 2176 | { | ||
| 2177 | drm_mode_object_put(dev, &blob->base); | ||
| 2178 | list_del(&blob->head); | ||
| 2179 | kfree(blob); | ||
| 2180 | } | ||
| 2181 | |||
| 2182 | int drm_mode_getblob_ioctl(struct drm_device *dev, | ||
| 2183 | void *data, struct drm_file *file_priv) | ||
| 2184 | { | ||
| 2185 | struct drm_mode_object *obj; | ||
| 2186 | struct drm_mode_get_blob *out_resp = data; | ||
| 2187 | struct drm_property_blob *blob; | ||
| 2188 | int ret = 0; | ||
| 2189 | void *blob_ptr; | ||
| 2190 | |||
| 2191 | mutex_lock(&dev->mode_config.mutex); | ||
| 2192 | obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB); | ||
| 2193 | if (!obj) { | ||
| 2194 | ret = -EINVAL; | ||
| 2195 | goto done; | ||
| 2196 | } | ||
| 2197 | blob = obj_to_blob(obj); | ||
| 2198 | |||
| 2199 | if (out_resp->length == blob->length) { | ||
| 2200 | blob_ptr = (void *)(unsigned long)out_resp->data; | ||
| 2201 | if (copy_to_user(blob_ptr, blob->data, blob->length)){ | ||
| 2202 | ret = -EFAULT; | ||
| 2203 | goto done; | ||
| 2204 | } | ||
| 2205 | } | ||
| 2206 | out_resp->length = blob->length; | ||
| 2207 | |||
| 2208 | done: | ||
| 2209 | mutex_unlock(&dev->mode_config.mutex); | ||
| 2210 | return ret; | ||
| 2211 | } | ||
| 2212 | |||
| 2213 | int drm_mode_connector_update_edid_property(struct drm_connector *connector, | ||
| 2214 | struct edid *edid) | ||
| 2215 | { | ||
| 2216 | struct drm_device *dev = connector->dev; | ||
| 2217 | int ret = 0; | ||
| 2218 | |||
| 2219 | if (connector->edid_blob_ptr) | ||
| 2220 | drm_property_destroy_blob(dev, connector->edid_blob_ptr); | ||
| 2221 | |||
| 2222 | /* Delete edid, when there is none. */ | ||
| 2223 | if (!edid) { | ||
| 2224 | connector->edid_blob_ptr = NULL; | ||
| 2225 | ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, 0); | ||
| 2226 | return ret; | ||
| 2227 | } | ||
| 2228 | |||
| 2229 | connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 128, edid); | ||
| 2230 | |||
| 2231 | ret = drm_connector_property_set_value(connector, | ||
| 2232 | dev->mode_config.edid_property, | ||
| 2233 | connector->edid_blob_ptr->base.id); | ||
| 2234 | |||
| 2235 | return ret; | ||
| 2236 | } | ||
| 2237 | EXPORT_SYMBOL(drm_mode_connector_update_edid_property); | ||
| 2238 | |||
| 2239 | int drm_mode_connector_property_set_ioctl(struct drm_device *dev, | ||
| 2240 | void *data, struct drm_file *file_priv) | ||
| 2241 | { | ||
| 2242 | struct drm_mode_connector_set_property *out_resp = data; | ||
| 2243 | struct drm_mode_object *obj; | ||
| 2244 | struct drm_property *property; | ||
| 2245 | struct drm_connector *connector; | ||
| 2246 | int ret = -EINVAL; | ||
| 2247 | int i; | ||
| 2248 | |||
| 2249 | mutex_lock(&dev->mode_config.mutex); | ||
| 2250 | |||
| 2251 | obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR); | ||
| 2252 | if (!obj) { | ||
| 2253 | goto out; | ||
| 2254 | } | ||
| 2255 | connector = obj_to_connector(obj); | ||
| 2256 | |||
| 2257 | for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { | ||
| 2258 | if (connector->property_ids[i] == out_resp->prop_id) | ||
| 2259 | break; | ||
| 2260 | } | ||
| 2261 | |||
| 2262 | if (i == DRM_CONNECTOR_MAX_PROPERTY) { | ||
| 2263 | goto out; | ||
| 2264 | } | ||
| 2265 | |||
| 2266 | obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); | ||
| 2267 | if (!obj) { | ||
| 2268 | goto out; | ||
| 2269 | } | ||
| 2270 | property = obj_to_property(obj); | ||
| 2271 | |||
| 2272 | if (property->flags & DRM_MODE_PROP_IMMUTABLE) | ||
| 2273 | goto out; | ||
| 2274 | |||
| 2275 | if (property->flags & DRM_MODE_PROP_RANGE) { | ||
| 2276 | if (out_resp->value < property->values[0]) | ||
| 2277 | goto out; | ||
| 2278 | |||
| 2279 | if (out_resp->value > property->values[1]) | ||
| 2280 | goto out; | ||
| 2281 | } else { | ||
| 2282 | int found = 0; | ||
| 2283 | for (i = 0; i < property->num_values; i++) { | ||
| 2284 | if (property->values[i] == out_resp->value) { | ||
| 2285 | found = 1; | ||
| 2286 | break; | ||
| 2287 | } | ||
| 2288 | } | ||
| 2289 | if (!found) { | ||
| 2290 | goto out; | ||
| 2291 | } | ||
| 2292 | } | ||
| 2293 | |||
| 2294 | if (connector->funcs->set_property) | ||
| 2295 | ret = connector->funcs->set_property(connector, property, out_resp->value); | ||
| 2296 | |||
| 2297 | /* store the property value if succesful */ | ||
| 2298 | if (!ret) | ||
| 2299 | drm_connector_property_set_value(connector, property, out_resp->value); | ||
| 2300 | out: | ||
| 2301 | mutex_unlock(&dev->mode_config.mutex); | ||
| 2302 | return ret; | ||
| 2303 | } | ||
| 2304 | |||
| 2305 | int drm_mode_connector_attach_encoder(struct drm_connector *connector, | ||
| 2306 | struct drm_encoder *encoder) | ||
| 2307 | { | ||
| 2308 | int i; | ||
| 2309 | |||
| 2310 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { | ||
| 2311 | if (connector->encoder_ids[i] == 0) { | ||
| 2312 | connector->encoder_ids[i] = encoder->base.id; | ||
| 2313 | return 0; | ||
| 2314 | } | ||
| 2315 | } | ||
| 2316 | return -ENOMEM; | ||
| 2317 | } | ||
| 2318 | EXPORT_SYMBOL(drm_mode_connector_attach_encoder); | ||
| 2319 | |||
| 2320 | void drm_mode_connector_detach_encoder(struct drm_connector *connector, | ||
| 2321 | struct drm_encoder *encoder) | ||
| 2322 | { | ||
| 2323 | int i; | ||
| 2324 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { | ||
| 2325 | if (connector->encoder_ids[i] == encoder->base.id) { | ||
| 2326 | connector->encoder_ids[i] = 0; | ||
| 2327 | if (connector->encoder == encoder) | ||
| 2328 | connector->encoder = NULL; | ||
| 2329 | break; | ||
| 2330 | } | ||
| 2331 | } | ||
| 2332 | } | ||
| 2333 | EXPORT_SYMBOL(drm_mode_connector_detach_encoder); | ||
| 2334 | |||
| 2335 | bool drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, | ||
| 2336 | int gamma_size) | ||
| 2337 | { | ||
| 2338 | crtc->gamma_size = gamma_size; | ||
| 2339 | |||
| 2340 | crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL); | ||
| 2341 | if (!crtc->gamma_store) { | ||
| 2342 | crtc->gamma_size = 0; | ||
| 2343 | return false; | ||
| 2344 | } | ||
| 2345 | |||
| 2346 | return true; | ||
| 2347 | } | ||
| 2348 | EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); | ||
| 2349 | |||
| 2350 | int drm_mode_gamma_set_ioctl(struct drm_device *dev, | ||
| 2351 | void *data, struct drm_file *file_priv) | ||
| 2352 | { | ||
| 2353 | struct drm_mode_crtc_lut *crtc_lut = data; | ||
| 2354 | struct drm_mode_object *obj; | ||
| 2355 | struct drm_crtc *crtc; | ||
| 2356 | void *r_base, *g_base, *b_base; | ||
| 2357 | int size; | ||
| 2358 | int ret = 0; | ||
| 2359 | |||
| 2360 | mutex_lock(&dev->mode_config.mutex); | ||
| 2361 | obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); | ||
| 2362 | if (!obj) { | ||
| 2363 | ret = -EINVAL; | ||
| 2364 | goto out; | ||
| 2365 | } | ||
| 2366 | crtc = obj_to_crtc(obj); | ||
| 2367 | |||
| 2368 | /* memcpy into gamma store */ | ||
| 2369 | if (crtc_lut->gamma_size != crtc->gamma_size) { | ||
| 2370 | ret = -EINVAL; | ||
| 2371 | goto out; | ||
| 2372 | } | ||
| 2373 | |||
| 2374 | size = crtc_lut->gamma_size * (sizeof(uint16_t)); | ||
| 2375 | r_base = crtc->gamma_store; | ||
| 2376 | if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { | ||
| 2377 | ret = -EFAULT; | ||
| 2378 | goto out; | ||
| 2379 | } | ||
| 2380 | |||
| 2381 | g_base = r_base + size; | ||
| 2382 | if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { | ||
| 2383 | ret = -EFAULT; | ||
| 2384 | goto out; | ||
| 2385 | } | ||
| 2386 | |||
| 2387 | b_base = g_base + size; | ||
| 2388 | if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { | ||
| 2389 | ret = -EFAULT; | ||
| 2390 | goto out; | ||
| 2391 | } | ||
| 2392 | |||
| 2393 | crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); | ||
| 2394 | |||
| 2395 | out: | ||
| 2396 | mutex_unlock(&dev->mode_config.mutex); | ||
| 2397 | return ret; | ||
| 2398 | |||
| 2399 | } | ||
| 2400 | |||
| 2401 | int drm_mode_gamma_get_ioctl(struct drm_device *dev, | ||
| 2402 | void *data, struct drm_file *file_priv) | ||
| 2403 | { | ||
| 2404 | struct drm_mode_crtc_lut *crtc_lut = data; | ||
| 2405 | struct drm_mode_object *obj; | ||
| 2406 | struct drm_crtc *crtc; | ||
| 2407 | void *r_base, *g_base, *b_base; | ||
| 2408 | int size; | ||
| 2409 | int ret = 0; | ||
| 2410 | |||
| 2411 | mutex_lock(&dev->mode_config.mutex); | ||
| 2412 | obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); | ||
| 2413 | if (!obj) { | ||
| 2414 | ret = -EINVAL; | ||
| 2415 | goto out; | ||
| 2416 | } | ||
| 2417 | crtc = obj_to_crtc(obj); | ||
| 2418 | |||
| 2419 | /* memcpy into gamma store */ | ||
| 2420 | if (crtc_lut->gamma_size != crtc->gamma_size) { | ||
| 2421 | ret = -EINVAL; | ||
| 2422 | goto out; | ||
| 2423 | } | ||
| 2424 | |||
| 2425 | size = crtc_lut->gamma_size * (sizeof(uint16_t)); | ||
| 2426 | r_base = crtc->gamma_store; | ||
| 2427 | if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { | ||
| 2428 | ret = -EFAULT; | ||
| 2429 | goto out; | ||
| 2430 | } | ||
| 2431 | |||
| 2432 | g_base = r_base + size; | ||
| 2433 | if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { | ||
| 2434 | ret = -EFAULT; | ||
| 2435 | goto out; | ||
| 2436 | } | ||
| 2437 | |||
| 2438 | b_base = g_base + size; | ||
| 2439 | if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { | ||
| 2440 | ret = -EFAULT; | ||
| 2441 | goto out; | ||
| 2442 | } | ||
| 2443 | out: | ||
| 2444 | mutex_unlock(&dev->mode_config.mutex); | ||
| 2445 | return ret; | ||
| 2446 | } | ||
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c new file mode 100644 index 000000000000..d8a982b71296 --- /dev/null +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
| @@ -0,0 +1,826 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2006-2008 Intel Corporation | ||
| 3 | * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> | ||
| 4 | * | ||
| 5 | * DRM core CRTC related functions | ||
| 6 | * | ||
| 7 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
| 8 | * documentation for any purpose is hereby granted without fee, provided that | ||
| 9 | * the above copyright notice appear in all copies and that both that copyright | ||
| 10 | * notice and this permission notice appear in supporting documentation, and | ||
| 11 | * that the name of the copyright holders not be used in advertising or | ||
| 12 | * publicity pertaining to distribution of the software without specific, | ||
| 13 | * written prior permission. The copyright holders make no representations | ||
| 14 | * about the suitability of this software for any purpose. It is provided "as | ||
| 15 | * is" without express or implied warranty. | ||
| 16 | * | ||
| 17 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
| 18 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
| 19 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
| 20 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
| 21 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
| 22 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
| 23 | * OF THIS SOFTWARE. | ||
| 24 | * | ||
| 25 | * Authors: | ||
| 26 | * Keith Packard | ||
| 27 | * Eric Anholt <eric@anholt.net> | ||
| 28 | * Dave Airlie <airlied@linux.ie> | ||
| 29 | * Jesse Barnes <jesse.barnes@intel.com> | ||
| 30 | */ | ||
| 31 | |||
| 32 | #include "drmP.h" | ||
| 33 | #include "drm_crtc.h" | ||
| 34 | #include "drm_crtc_helper.h" | ||
| 35 | |||
| 36 | /* | ||
| 37 | * Detailed mode info for 800x600@60Hz | ||
| 38 | */ | ||
| 39 | static struct drm_display_mode std_mode[] = { | ||
| 40 | { DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 40000, 800, 840, | ||
| 41 | 968, 1056, 0, 600, 601, 605, 628, 0, | ||
| 42 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, | ||
| 43 | }; | ||
| 44 | |||
| 45 | /** | ||
| 46 | * drm_helper_probe_connector_modes - get complete set of display modes | ||
| 47 | * @dev: DRM device | ||
| 48 | * @maxX: max width for modes | ||
| 49 | * @maxY: max height for modes | ||
| 50 | * | ||
| 51 | * LOCKING: | ||
| 52 | * Caller must hold mode config lock. | ||
| 53 | * | ||
| 54 | * Based on @dev's mode_config layout, scan all the connectors and try to detect | ||
| 55 | * modes on them. Modes will first be added to the connector's probed_modes | ||
| 56 | * list, then culled (based on validity and the @maxX, @maxY parameters) and | ||
| 57 | * put into the normal modes list. | ||
| 58 | * | ||
| 59 | * Intended to be used either at bootup time or when major configuration | ||
| 60 | * changes have occurred. | ||
| 61 | * | ||
| 62 | * FIXME: take into account monitor limits | ||
| 63 | */ | ||
| 64 | void drm_helper_probe_single_connector_modes(struct drm_connector *connector, | ||
| 65 | uint32_t maxX, uint32_t maxY) | ||
| 66 | { | ||
| 67 | struct drm_device *dev = connector->dev; | ||
| 68 | struct drm_display_mode *mode, *t; | ||
| 69 | struct drm_connector_helper_funcs *connector_funcs = | ||
| 70 | connector->helper_private; | ||
| 71 | int ret; | ||
| 72 | |||
| 73 | DRM_DEBUG("%s\n", drm_get_connector_name(connector)); | ||
| 74 | /* set all modes to the unverified state */ | ||
| 75 | list_for_each_entry_safe(mode, t, &connector->modes, head) | ||
| 76 | mode->status = MODE_UNVERIFIED; | ||
| 77 | |||
| 78 | connector->status = connector->funcs->detect(connector); | ||
| 79 | |||
| 80 | if (connector->status == connector_status_disconnected) { | ||
| 81 | DRM_DEBUG("%s is disconnected\n", | ||
| 82 | drm_get_connector_name(connector)); | ||
| 83 | /* TODO set EDID to NULL */ | ||
| 84 | return; | ||
| 85 | } | ||
| 86 | |||
| 87 | ret = (*connector_funcs->get_modes)(connector); | ||
| 88 | |||
| 89 | if (ret) { | ||
| 90 | drm_mode_connector_list_update(connector); | ||
| 91 | } | ||
| 92 | |||
| 93 | if (maxX && maxY) | ||
| 94 | drm_mode_validate_size(dev, &connector->modes, maxX, | ||
| 95 | maxY, 0); | ||
| 96 | list_for_each_entry_safe(mode, t, &connector->modes, head) { | ||
| 97 | if (mode->status == MODE_OK) | ||
| 98 | mode->status = connector_funcs->mode_valid(connector, | ||
| 99 | mode); | ||
| 100 | } | ||
| 101 | |||
| 102 | |||
| 103 | drm_mode_prune_invalid(dev, &connector->modes, true); | ||
| 104 | |||
| 105 | if (list_empty(&connector->modes)) { | ||
| 106 | struct drm_display_mode *stdmode; | ||
| 107 | |||
| 108 | DRM_DEBUG("No valid modes on %s\n", | ||
| 109 | drm_get_connector_name(connector)); | ||
| 110 | |||
| 111 | /* Should we do this here ??? | ||
| 112 | * When no valid EDID modes are available we end up | ||
| 113 | * here and bailed in the past, now we add a standard | ||
| 114 | * 640x480@60Hz mode and carry on. | ||
| 115 | */ | ||
| 116 | stdmode = drm_mode_duplicate(dev, &std_mode[0]); | ||
| 117 | drm_mode_probed_add(connector, stdmode); | ||
| 118 | drm_mode_list_concat(&connector->probed_modes, | ||
| 119 | &connector->modes); | ||
| 120 | |||
| 121 | DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n", | ||
| 122 | drm_get_connector_name(connector)); | ||
| 123 | } | ||
| 124 | |||
| 125 | drm_mode_sort(&connector->modes); | ||
| 126 | |||
| 127 | DRM_DEBUG("Probed modes for %s\n", drm_get_connector_name(connector)); | ||
| 128 | list_for_each_entry_safe(mode, t, &connector->modes, head) { | ||
| 129 | mode->vrefresh = drm_mode_vrefresh(mode); | ||
| 130 | |||
| 131 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); | ||
| 132 | drm_mode_debug_printmodeline(mode); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); | ||
| 136 | |||
| 137 | void drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX, | ||
| 138 | uint32_t maxY) | ||
| 139 | { | ||
| 140 | struct drm_connector *connector; | ||
| 141 | |||
| 142 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 143 | drm_helper_probe_single_connector_modes(connector, maxX, maxY); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | EXPORT_SYMBOL(drm_helper_probe_connector_modes); | ||
| 147 | |||
| 148 | |||
| 149 | /** | ||
| 150 | * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config | ||
| 151 | * @crtc: CRTC to check | ||
| 152 | * | ||
| 153 | * LOCKING: | ||
| 154 | * Caller must hold mode config lock. | ||
| 155 | * | ||
| 156 | * Walk @crtc's DRM device's mode_config and see if it's in use. | ||
| 157 | * | ||
| 158 | * RETURNS: | ||
| 159 | * True if @crtc is part of the mode_config, false otherwise. | ||
| 160 | */ | ||
| 161 | bool drm_helper_crtc_in_use(struct drm_crtc *crtc) | ||
| 162 | { | ||
| 163 | struct drm_encoder *encoder; | ||
| 164 | struct drm_device *dev = crtc->dev; | ||
| 165 | /* FIXME: Locking around list access? */ | ||
| 166 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) | ||
| 167 | if (encoder->crtc == crtc) | ||
| 168 | return true; | ||
| 169 | return false; | ||
| 170 | } | ||
| 171 | EXPORT_SYMBOL(drm_helper_crtc_in_use); | ||
| 172 | |||
| 173 | /** | ||
| 174 | * drm_disable_unused_functions - disable unused objects | ||
| 175 | * @dev: DRM device | ||
| 176 | * | ||
| 177 | * LOCKING: | ||
| 178 | * Caller must hold mode config lock. | ||
| 179 | * | ||
| 180 | * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled | ||
| 181 | * by calling its dpms function, which should power it off. | ||
| 182 | */ | ||
| 183 | void drm_helper_disable_unused_functions(struct drm_device *dev) | ||
| 184 | { | ||
| 185 | struct drm_encoder *encoder; | ||
| 186 | struct drm_encoder_helper_funcs *encoder_funcs; | ||
| 187 | struct drm_crtc *crtc; | ||
| 188 | |||
| 189 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
| 190 | encoder_funcs = encoder->helper_private; | ||
| 191 | if (!encoder->crtc) | ||
| 192 | (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); | ||
| 193 | } | ||
| 194 | |||
| 195 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
| 196 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
| 197 | crtc->enabled = drm_helper_crtc_in_use(crtc); | ||
| 198 | if (!crtc->enabled) { | ||
| 199 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); | ||
| 200 | crtc->fb = NULL; | ||
| 201 | } | ||
| 202 | } | ||
| 203 | } | ||
| 204 | EXPORT_SYMBOL(drm_helper_disable_unused_functions); | ||
| 205 | |||
| 206 | static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height) | ||
| 207 | { | ||
| 208 | struct drm_display_mode *mode; | ||
| 209 | |||
| 210 | list_for_each_entry(mode, &connector->modes, head) { | ||
| 211 | if (drm_mode_width(mode) > width || | ||
| 212 | drm_mode_height(mode) > height) | ||
| 213 | continue; | ||
| 214 | if (mode->type & DRM_MODE_TYPE_PREFERRED) | ||
| 215 | return mode; | ||
| 216 | } | ||
| 217 | return NULL; | ||
| 218 | } | ||
| 219 | |||
| 220 | static bool drm_connector_enabled(struct drm_connector *connector, bool strict) | ||
| 221 | { | ||
| 222 | bool enable; | ||
| 223 | |||
| 224 | if (strict) { | ||
| 225 | enable = connector->status == connector_status_connected; | ||
| 226 | } else { | ||
| 227 | enable = connector->status != connector_status_disconnected; | ||
| 228 | } | ||
| 229 | return enable; | ||
| 230 | } | ||
| 231 | |||
| 232 | static void drm_enable_connectors(struct drm_device *dev, bool *enabled) | ||
| 233 | { | ||
| 234 | bool any_enabled = false; | ||
| 235 | struct drm_connector *connector; | ||
| 236 | int i = 0; | ||
| 237 | |||
| 238 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 239 | enabled[i] = drm_connector_enabled(connector, true); | ||
| 240 | any_enabled |= enabled[i]; | ||
| 241 | i++; | ||
| 242 | } | ||
| 243 | |||
| 244 | if (any_enabled) | ||
| 245 | return; | ||
| 246 | |||
| 247 | i = 0; | ||
| 248 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 249 | enabled[i] = drm_connector_enabled(connector, false); | ||
| 250 | i++; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | static bool drm_target_preferred(struct drm_device *dev, | ||
| 255 | struct drm_display_mode **modes, | ||
| 256 | bool *enabled, int width, int height) | ||
| 257 | { | ||
| 258 | struct drm_connector *connector; | ||
| 259 | int i = 0; | ||
| 260 | |||
| 261 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 262 | |||
| 263 | if (enabled[i] == false) { | ||
| 264 | i++; | ||
| 265 | continue; | ||
| 266 | } | ||
| 267 | |||
| 268 | modes[i] = drm_has_preferred_mode(connector, width, height); | ||
| 269 | if (!modes[i]) { | ||
| 270 | list_for_each_entry(modes[i], &connector->modes, head) | ||
| 271 | break; | ||
| 272 | } | ||
| 273 | i++; | ||
| 274 | } | ||
| 275 | return true; | ||
| 276 | } | ||
| 277 | |||
| 278 | static int drm_pick_crtcs(struct drm_device *dev, | ||
| 279 | struct drm_crtc **best_crtcs, | ||
| 280 | struct drm_display_mode **modes, | ||
| 281 | int n, int width, int height) | ||
| 282 | { | ||
| 283 | int c, o; | ||
| 284 | struct drm_connector *connector; | ||
| 285 | struct drm_connector_helper_funcs *connector_funcs; | ||
| 286 | struct drm_encoder *encoder; | ||
| 287 | struct drm_crtc *best_crtc; | ||
| 288 | int my_score, best_score, score; | ||
| 289 | struct drm_crtc **crtcs, *crtc; | ||
| 290 | |||
| 291 | if (n == dev->mode_config.num_connector) | ||
| 292 | return 0; | ||
| 293 | c = 0; | ||
| 294 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 295 | if (c == n) | ||
| 296 | break; | ||
| 297 | c++; | ||
| 298 | } | ||
| 299 | |||
| 300 | best_crtcs[n] = NULL; | ||
| 301 | best_crtc = NULL; | ||
| 302 | best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height); | ||
| 303 | if (modes[n] == NULL) | ||
| 304 | return best_score; | ||
| 305 | |||
| 306 | crtcs = kmalloc(dev->mode_config.num_connector * | ||
| 307 | sizeof(struct drm_crtc *), GFP_KERNEL); | ||
| 308 | if (!crtcs) | ||
| 309 | return best_score; | ||
| 310 | |||
| 311 | my_score = 1; | ||
| 312 | if (connector->status == connector_status_connected) | ||
| 313 | my_score++; | ||
| 314 | if (drm_has_preferred_mode(connector, width, height)) | ||
| 315 | my_score++; | ||
| 316 | |||
| 317 | connector_funcs = connector->helper_private; | ||
| 318 | encoder = connector_funcs->best_encoder(connector); | ||
| 319 | if (!encoder) | ||
| 320 | goto out; | ||
| 321 | |||
| 322 | connector->encoder = encoder; | ||
| 323 | |||
| 324 | /* select a crtc for this connector and then attempt to configure | ||
| 325 | remaining connectors */ | ||
| 326 | c = 0; | ||
| 327 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
| 328 | |||
| 329 | if ((connector->encoder->possible_crtcs & (1 << c)) == 0) { | ||
| 330 | c++; | ||
| 331 | continue; | ||
| 332 | } | ||
| 333 | |||
| 334 | for (o = 0; o < n; o++) | ||
| 335 | if (best_crtcs[o] == crtc) | ||
| 336 | break; | ||
| 337 | |||
| 338 | if (o < n) { | ||
| 339 | /* ignore cloning for now */ | ||
| 340 | c++; | ||
| 341 | continue; | ||
| 342 | } | ||
| 343 | |||
| 344 | crtcs[n] = crtc; | ||
| 345 | memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *)); | ||
| 346 | score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1, | ||
| 347 | width, height); | ||
| 348 | if (score > best_score) { | ||
| 349 | best_crtc = crtc; | ||
| 350 | best_score = score; | ||
| 351 | memcpy(best_crtcs, crtcs, | ||
| 352 | dev->mode_config.num_connector * | ||
| 353 | sizeof(struct drm_crtc *)); | ||
| 354 | } | ||
| 355 | c++; | ||
| 356 | } | ||
| 357 | out: | ||
| 358 | kfree(crtcs); | ||
| 359 | return best_score; | ||
| 360 | } | ||
| 361 | |||
| 362 | static void drm_setup_crtcs(struct drm_device *dev) | ||
| 363 | { | ||
| 364 | struct drm_crtc **crtcs; | ||
| 365 | struct drm_display_mode **modes; | ||
| 366 | struct drm_encoder *encoder; | ||
| 367 | struct drm_connector *connector; | ||
| 368 | bool *enabled; | ||
| 369 | int width, height; | ||
| 370 | int i, ret; | ||
| 371 | |||
| 372 | width = dev->mode_config.max_width; | ||
| 373 | height = dev->mode_config.max_height; | ||
| 374 | |||
| 375 | /* clean out all the encoder/crtc combos */ | ||
| 376 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
| 377 | encoder->crtc = NULL; | ||
| 378 | } | ||
| 379 | |||
| 380 | crtcs = kcalloc(dev->mode_config.num_connector, | ||
| 381 | sizeof(struct drm_crtc *), GFP_KERNEL); | ||
| 382 | modes = kcalloc(dev->mode_config.num_connector, | ||
| 383 | sizeof(struct drm_display_mode *), GFP_KERNEL); | ||
| 384 | enabled = kcalloc(dev->mode_config.num_connector, | ||
| 385 | sizeof(bool), GFP_KERNEL); | ||
| 386 | |||
| 387 | drm_enable_connectors(dev, enabled); | ||
| 388 | |||
| 389 | ret = drm_target_preferred(dev, modes, enabled, width, height); | ||
| 390 | if (!ret) | ||
| 391 | DRM_ERROR("Unable to find initial modes\n"); | ||
| 392 | |||
| 393 | drm_pick_crtcs(dev, crtcs, modes, 0, width, height); | ||
| 394 | |||
| 395 | i = 0; | ||
| 396 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 397 | struct drm_display_mode *mode = modes[i]; | ||
| 398 | struct drm_crtc *crtc = crtcs[i]; | ||
| 399 | |||
| 400 | if (connector->encoder == NULL) { | ||
| 401 | i++; | ||
| 402 | continue; | ||
| 403 | } | ||
| 404 | |||
| 405 | if (mode && crtc) { | ||
| 406 | crtc->desired_mode = mode; | ||
| 407 | connector->encoder->crtc = crtc; | ||
| 408 | } else | ||
| 409 | connector->encoder->crtc = NULL; | ||
| 410 | i++; | ||
| 411 | } | ||
| 412 | |||
| 413 | kfree(crtcs); | ||
| 414 | kfree(modes); | ||
| 415 | kfree(enabled); | ||
| 416 | } | ||
| 417 | /** | ||
| 418 | * drm_crtc_set_mode - set a mode | ||
| 419 | * @crtc: CRTC to program | ||
| 420 | * @mode: mode to use | ||
| 421 | * @x: width of mode | ||
| 422 | * @y: height of mode | ||
| 423 | * | ||
| 424 | * LOCKING: | ||
| 425 | * Caller must hold mode config lock. | ||
| 426 | * | ||
| 427 | * Try to set @mode on @crtc. Give @crtc and its associated connectors a chance | ||
| 428 | * to fixup or reject the mode prior to trying to set it. | ||
| 429 | * | ||
| 430 | * RETURNS: | ||
| 431 | * True if the mode was set successfully, or false otherwise. | ||
| 432 | */ | ||
| 433 | bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, | ||
| 434 | struct drm_display_mode *mode, | ||
| 435 | int x, int y, | ||
| 436 | struct drm_framebuffer *old_fb) | ||
| 437 | { | ||
| 438 | struct drm_device *dev = crtc->dev; | ||
| 439 | struct drm_display_mode *adjusted_mode, saved_mode; | ||
| 440 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
| 441 | struct drm_encoder_helper_funcs *encoder_funcs; | ||
| 442 | int saved_x, saved_y; | ||
| 443 | struct drm_encoder *encoder; | ||
| 444 | bool ret = true; | ||
| 445 | |||
| 446 | adjusted_mode = drm_mode_duplicate(dev, mode); | ||
| 447 | |||
| 448 | crtc->enabled = drm_helper_crtc_in_use(crtc); | ||
| 449 | |||
| 450 | if (!crtc->enabled) | ||
| 451 | return true; | ||
| 452 | |||
| 453 | saved_mode = crtc->mode; | ||
| 454 | saved_x = crtc->x; | ||
| 455 | saved_y = crtc->y; | ||
| 456 | |||
| 457 | /* Update crtc values up front so the driver can rely on them for mode | ||
| 458 | * setting. | ||
| 459 | */ | ||
| 460 | crtc->mode = *mode; | ||
| 461 | crtc->x = x; | ||
| 462 | crtc->y = y; | ||
| 463 | |||
| 464 | if (drm_mode_equal(&saved_mode, &crtc->mode)) { | ||
| 465 | if (saved_x != crtc->x || saved_y != crtc->y) { | ||
| 466 | crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y, | ||
| 467 | old_fb); | ||
| 468 | goto done; | ||
| 469 | } | ||
| 470 | } | ||
| 471 | |||
| 472 | /* Pass our mode to the connectors and the CRTC to give them a chance to | ||
| 473 | * adjust it according to limitations or connector properties, and also | ||
| 474 | * a chance to reject the mode entirely. | ||
| 475 | */ | ||
| 476 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
| 477 | |||
| 478 | if (encoder->crtc != crtc) | ||
| 479 | continue; | ||
| 480 | encoder_funcs = encoder->helper_private; | ||
| 481 | if (!(ret = encoder_funcs->mode_fixup(encoder, mode, | ||
| 482 | adjusted_mode))) { | ||
| 483 | goto done; | ||
| 484 | } | ||
| 485 | } | ||
| 486 | |||
| 487 | if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { | ||
| 488 | goto done; | ||
| 489 | } | ||
| 490 | |||
| 491 | /* Prepare the encoders and CRTCs before setting the mode. */ | ||
| 492 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
| 493 | |||
| 494 | if (encoder->crtc != crtc) | ||
| 495 | continue; | ||
| 496 | encoder_funcs = encoder->helper_private; | ||
| 497 | /* Disable the encoders as the first thing we do. */ | ||
| 498 | encoder_funcs->prepare(encoder); | ||
| 499 | } | ||
| 500 | |||
| 501 | crtc_funcs->prepare(crtc); | ||
| 502 | |||
| 503 | /* Set up the DPLL and any encoders state that needs to adjust or depend | ||
| 504 | * on the DPLL. | ||
| 505 | */ | ||
| 506 | crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb); | ||
| 507 | |||
| 508 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
| 509 | |||
| 510 | if (encoder->crtc != crtc) | ||
| 511 | continue; | ||
| 512 | |||
| 513 | DRM_INFO("%s: set mode %s %x\n", drm_get_encoder_name(encoder), | ||
| 514 | mode->name, mode->base.id); | ||
| 515 | encoder_funcs = encoder->helper_private; | ||
| 516 | encoder_funcs->mode_set(encoder, mode, adjusted_mode); | ||
| 517 | } | ||
| 518 | |||
| 519 | /* Now enable the clocks, plane, pipe, and connectors that we set up. */ | ||
| 520 | crtc_funcs->commit(crtc); | ||
| 521 | |||
| 522 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
| 523 | |||
| 524 | if (encoder->crtc != crtc) | ||
| 525 | continue; | ||
| 526 | |||
| 527 | encoder_funcs = encoder->helper_private; | ||
| 528 | encoder_funcs->commit(encoder); | ||
| 529 | |||
| 530 | } | ||
| 531 | |||
| 532 | /* XXX free adjustedmode */ | ||
| 533 | drm_mode_destroy(dev, adjusted_mode); | ||
| 534 | /* FIXME: add subpixel order */ | ||
| 535 | done: | ||
| 536 | if (!ret) { | ||
| 537 | crtc->mode = saved_mode; | ||
| 538 | crtc->x = saved_x; | ||
| 539 | crtc->y = saved_y; | ||
| 540 | } | ||
| 541 | |||
| 542 | return ret; | ||
| 543 | } | ||
| 544 | EXPORT_SYMBOL(drm_crtc_helper_set_mode); | ||
| 545 | |||
| 546 | |||
| 547 | /** | ||
| 548 | * drm_crtc_helper_set_config - set a new config from userspace | ||
| 549 | * @crtc: CRTC to setup | ||
| 550 | * @crtc_info: user provided configuration | ||
| 551 | * @new_mode: new mode to set | ||
| 552 | * @connector_set: set of connectors for the new config | ||
| 553 | * @fb: new framebuffer | ||
| 554 | * | ||
| 555 | * LOCKING: | ||
| 556 | * Caller must hold mode config lock. | ||
| 557 | * | ||
| 558 | * Setup a new configuration, provided by the user in @crtc_info, and enable | ||
| 559 | * it. | ||
| 560 | * | ||
| 561 | * RETURNS: | ||
| 562 | * Zero. (FIXME) | ||
| 563 | */ | ||
| 564 | int drm_crtc_helper_set_config(struct drm_mode_set *set) | ||
| 565 | { | ||
| 566 | struct drm_device *dev; | ||
| 567 | struct drm_crtc **save_crtcs, *new_crtc; | ||
| 568 | struct drm_encoder **save_encoders, *new_encoder; | ||
| 569 | struct drm_framebuffer *old_fb; | ||
| 570 | bool save_enabled; | ||
| 571 | bool changed = false; | ||
| 572 | bool flip_or_move = false; | ||
| 573 | struct drm_connector *connector; | ||
| 574 | int count = 0, ro, fail = 0; | ||
| 575 | struct drm_crtc_helper_funcs *crtc_funcs; | ||
| 576 | int ret = 0; | ||
| 577 | |||
| 578 | DRM_DEBUG("\n"); | ||
| 579 | |||
| 580 | if (!set) | ||
| 581 | return -EINVAL; | ||
| 582 | |||
| 583 | if (!set->crtc) | ||
| 584 | return -EINVAL; | ||
| 585 | |||
| 586 | if (!set->crtc->helper_private) | ||
| 587 | return -EINVAL; | ||
| 588 | |||
| 589 | crtc_funcs = set->crtc->helper_private; | ||
| 590 | |||
| 591 | DRM_DEBUG("crtc: %p %d fb: %p connectors: %p num_connectors: %d (x, y) (%i, %i)\n", | ||
| 592 | set->crtc, set->crtc->base.id, set->fb, set->connectors, | ||
| 593 | (int)set->num_connectors, set->x, set->y); | ||
| 594 | |||
| 595 | dev = set->crtc->dev; | ||
| 596 | |||
| 597 | /* save previous config */ | ||
| 598 | save_enabled = set->crtc->enabled; | ||
| 599 | |||
| 600 | /* this is meant to be num_connector not num_crtc */ | ||
| 601 | save_crtcs = kzalloc(dev->mode_config.num_connector * | ||
| 602 | sizeof(struct drm_crtc *), GFP_KERNEL); | ||
| 603 | if (!save_crtcs) | ||
| 604 | return -ENOMEM; | ||
| 605 | |||
| 606 | save_encoders = kzalloc(dev->mode_config.num_connector * | ||
| 607 | sizeof(struct drm_encoders *), GFP_KERNEL); | ||
| 608 | if (!save_encoders) { | ||
| 609 | kfree(save_crtcs); | ||
| 610 | return -ENOMEM; | ||
| 611 | } | ||
| 612 | |||
| 613 | /* We should be able to check here if the fb has the same properties | ||
| 614 | * and then just flip_or_move it */ | ||
| 615 | if (set->crtc->fb != set->fb) { | ||
| 616 | /* if we have no fb then its a change not a flip */ | ||
| 617 | if (set->crtc->fb == NULL) | ||
| 618 | changed = true; | ||
| 619 | else | ||
| 620 | flip_or_move = true; | ||
| 621 | } | ||
| 622 | |||
| 623 | if (set->x != set->crtc->x || set->y != set->crtc->y) | ||
| 624 | flip_or_move = true; | ||
| 625 | |||
| 626 | if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { | ||
| 627 | DRM_DEBUG("modes are different\n"); | ||
| 628 | drm_mode_debug_printmodeline(&set->crtc->mode); | ||
| 629 | drm_mode_debug_printmodeline(set->mode); | ||
| 630 | changed = true; | ||
| 631 | } | ||
| 632 | |||
| 633 | /* a) traverse passed in connector list and get encoders for them */ | ||
| 634 | count = 0; | ||
| 635 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 636 | struct drm_connector_helper_funcs *connector_funcs = | ||
| 637 | connector->helper_private; | ||
| 638 | save_encoders[count++] = connector->encoder; | ||
| 639 | new_encoder = connector->encoder; | ||
| 640 | for (ro = 0; ro < set->num_connectors; ro++) { | ||
| 641 | if (set->connectors[ro] == connector) { | ||
| 642 | new_encoder = connector_funcs->best_encoder(connector); | ||
| 643 | /* if we can't get an encoder for a connector | ||
| 644 | we are setting now - then fail */ | ||
| 645 | if (new_encoder == NULL) | ||
| 646 | /* don't break so fail path works correct */ | ||
| 647 | fail = 1; | ||
| 648 | break; | ||
| 649 | } | ||
| 650 | } | ||
| 651 | |||
| 652 | if (new_encoder != connector->encoder) { | ||
| 653 | changed = true; | ||
| 654 | connector->encoder = new_encoder; | ||
| 655 | } | ||
| 656 | } | ||
| 657 | |||
| 658 | if (fail) { | ||
| 659 | ret = -EINVAL; | ||
| 660 | goto fail_no_encoder; | ||
| 661 | } | ||
| 662 | |||
| 663 | count = 0; | ||
| 664 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 665 | if (!connector->encoder) | ||
| 666 | continue; | ||
| 667 | |||
| 668 | save_crtcs[count++] = connector->encoder->crtc; | ||
| 669 | |||
| 670 | if (connector->encoder->crtc == set->crtc) | ||
| 671 | new_crtc = NULL; | ||
| 672 | else | ||
| 673 | new_crtc = connector->encoder->crtc; | ||
| 674 | |||
| 675 | for (ro = 0; ro < set->num_connectors; ro++) { | ||
| 676 | if (set->connectors[ro] == connector) | ||
| 677 | new_crtc = set->crtc; | ||
| 678 | } | ||
| 679 | if (new_crtc != connector->encoder->crtc) { | ||
| 680 | changed = true; | ||
| 681 | connector->encoder->crtc = new_crtc; | ||
| 682 | } | ||
| 683 | } | ||
| 684 | |||
| 685 | /* mode_set_base is not a required function */ | ||
| 686 | if (flip_or_move && !crtc_funcs->mode_set_base) | ||
| 687 | changed = true; | ||
| 688 | |||
| 689 | if (changed) { | ||
| 690 | old_fb = set->crtc->fb; | ||
| 691 | set->crtc->fb = set->fb; | ||
| 692 | set->crtc->enabled = (set->mode != NULL); | ||
| 693 | if (set->mode != NULL) { | ||
| 694 | DRM_DEBUG("attempting to set mode from userspace\n"); | ||
| 695 | drm_mode_debug_printmodeline(set->mode); | ||
| 696 | if (!drm_crtc_helper_set_mode(set->crtc, set->mode, | ||
| 697 | set->x, set->y, | ||
| 698 | old_fb)) { | ||
| 699 | ret = -EINVAL; | ||
| 700 | goto fail_set_mode; | ||
| 701 | } | ||
| 702 | /* TODO are these needed? */ | ||
| 703 | set->crtc->desired_x = set->x; | ||
| 704 | set->crtc->desired_y = set->y; | ||
| 705 | set->crtc->desired_mode = set->mode; | ||
| 706 | } | ||
| 707 | drm_helper_disable_unused_functions(dev); | ||
| 708 | } else if (flip_or_move) { | ||
| 709 | old_fb = set->crtc->fb; | ||
| 710 | if (set->crtc->fb != set->fb) | ||
| 711 | set->crtc->fb = set->fb; | ||
| 712 | crtc_funcs->mode_set_base(set->crtc, set->x, set->y, old_fb); | ||
| 713 | } | ||
| 714 | |||
| 715 | kfree(save_encoders); | ||
| 716 | kfree(save_crtcs); | ||
| 717 | return 0; | ||
| 718 | |||
| 719 | fail_set_mode: | ||
| 720 | set->crtc->enabled = save_enabled; | ||
| 721 | count = 0; | ||
| 722 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) | ||
| 723 | connector->encoder->crtc = save_crtcs[count++]; | ||
| 724 | fail_no_encoder: | ||
| 725 | kfree(save_crtcs); | ||
| 726 | count = 0; | ||
| 727 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 728 | connector->encoder = save_encoders[count++]; | ||
| 729 | } | ||
| 730 | kfree(save_encoders); | ||
| 731 | return ret; | ||
| 732 | } | ||
| 733 | EXPORT_SYMBOL(drm_crtc_helper_set_config); | ||
| 734 | |||
| 735 | bool drm_helper_plugged_event(struct drm_device *dev) | ||
| 736 | { | ||
| 737 | DRM_DEBUG("\n"); | ||
| 738 | |||
| 739 | drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, | ||
| 740 | dev->mode_config.max_height); | ||
| 741 | |||
| 742 | drm_setup_crtcs(dev); | ||
| 743 | |||
| 744 | /* alert the driver fb layer */ | ||
| 745 | dev->mode_config.funcs->fb_changed(dev); | ||
| 746 | |||
| 747 | /* FIXME: send hotplug event */ | ||
| 748 | return true; | ||
| 749 | } | ||
| 750 | /** | ||
| 751 | * drm_initial_config - setup a sane initial connector configuration | ||
| 752 | * @dev: DRM device | ||
| 753 | * @can_grow: this configuration is growable | ||
| 754 | * | ||
| 755 | * LOCKING: | ||
| 756 | * Called at init time, must take mode config lock. | ||
| 757 | * | ||
| 758 | * Scan the CRTCs and connectors and try to put together an initial setup. | ||
| 759 | * At the moment, this is a cloned configuration across all heads with | ||
| 760 | * a new framebuffer object as the backing store. | ||
| 761 | * | ||
| 762 | * RETURNS: | ||
| 763 | * Zero if everything went ok, nonzero otherwise. | ||
| 764 | */ | ||
| 765 | bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) | ||
| 766 | { | ||
| 767 | int ret = false; | ||
| 768 | |||
| 769 | drm_helper_plugged_event(dev); | ||
| 770 | return ret; | ||
| 771 | } | ||
| 772 | EXPORT_SYMBOL(drm_helper_initial_config); | ||
| 773 | |||
| 774 | /** | ||
| 775 | * drm_hotplug_stage_two | ||
| 776 | * @dev DRM device | ||
| 777 | * @connector hotpluged connector | ||
| 778 | * | ||
| 779 | * LOCKING. | ||
| 780 | * Caller must hold mode config lock, function might grab struct lock. | ||
| 781 | * | ||
| 782 | * Stage two of a hotplug. | ||
| 783 | * | ||
| 784 | * RETURNS: | ||
| 785 | * Zero on success, errno on failure. | ||
| 786 | */ | ||
| 787 | int drm_helper_hotplug_stage_two(struct drm_device *dev) | ||
| 788 | { | ||
| 789 | drm_helper_plugged_event(dev); | ||
| 790 | |||
| 791 | return 0; | ||
| 792 | } | ||
| 793 | EXPORT_SYMBOL(drm_helper_hotplug_stage_two); | ||
| 794 | |||
| 795 | int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, | ||
| 796 | struct drm_mode_fb_cmd *mode_cmd) | ||
| 797 | { | ||
| 798 | fb->width = mode_cmd->width; | ||
| 799 | fb->height = mode_cmd->height; | ||
| 800 | fb->pitch = mode_cmd->pitch; | ||
| 801 | fb->bits_per_pixel = mode_cmd->bpp; | ||
| 802 | fb->depth = mode_cmd->depth; | ||
| 803 | |||
| 804 | return 0; | ||
| 805 | } | ||
| 806 | EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); | ||
| 807 | |||
| 808 | int drm_helper_resume_force_mode(struct drm_device *dev) | ||
| 809 | { | ||
| 810 | struct drm_crtc *crtc; | ||
| 811 | int ret; | ||
| 812 | |||
| 813 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
| 814 | |||
| 815 | if (!crtc->enabled) | ||
| 816 | continue; | ||
| 817 | |||
| 818 | ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, | ||
| 819 | crtc->x, crtc->y, crtc->fb); | ||
| 820 | |||
| 821 | if (ret == false) | ||
| 822 | DRM_ERROR("failed to set mode on crtc %p\n", crtc); | ||
| 823 | } | ||
| 824 | return 0; | ||
| 825 | } | ||
| 826 | EXPORT_SYMBOL(drm_helper_resume_force_mode); | ||
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 996097acb5e7..febb517ee679 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c | |||
| @@ -74,6 +74,9 @@ static struct drm_ioctl_desc drm_ioctls[] = { | |||
| 74 | DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 74 | DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
| 75 | DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH), | 75 | DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH), |
| 76 | 76 | ||
| 77 | DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY), | ||
| 78 | DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY), | ||
| 79 | |||
| 77 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY), | 80 | DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY), |
| 78 | DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 81 | DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
| 79 | DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 82 | DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
| @@ -123,6 +126,23 @@ static struct drm_ioctl_desc drm_ioctls[] = { | |||
| 123 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, 0), | 126 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, 0), |
| 124 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH), | 127 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH), |
| 125 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH), | 128 | DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH), |
| 129 | |||
| 130 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW), | ||
| 131 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW), | ||
| 132 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW), | ||
| 133 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), | ||
| 134 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER), | ||
| 135 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER), | ||
| 136 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW), | ||
| 137 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_MASTER|DRM_CONTROL_ALLOW), | ||
| 138 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), | ||
| 139 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), | ||
| 140 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW), | ||
| 141 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), | ||
| 142 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), | ||
| 143 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW), | ||
| 144 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW), | ||
| 145 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW), | ||
| 126 | }; | 146 | }; |
| 127 | 147 | ||
| 128 | #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) | 148 | #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) |
| @@ -138,8 +158,6 @@ static struct drm_ioctl_desc drm_ioctls[] = { | |||
| 138 | */ | 158 | */ |
| 139 | int drm_lastclose(struct drm_device * dev) | 159 | int drm_lastclose(struct drm_device * dev) |
| 140 | { | 160 | { |
| 141 | struct drm_magic_entry *pt, *next; | ||
| 142 | struct drm_map_list *r_list, *list_t; | ||
| 143 | struct drm_vma_entry *vma, *vma_temp; | 161 | struct drm_vma_entry *vma, *vma_temp; |
| 144 | int i; | 162 | int i; |
| 145 | 163 | ||
| @@ -149,13 +167,7 @@ int drm_lastclose(struct drm_device * dev) | |||
| 149 | dev->driver->lastclose(dev); | 167 | dev->driver->lastclose(dev); |
| 150 | DRM_DEBUG("driver lastclose completed\n"); | 168 | DRM_DEBUG("driver lastclose completed\n"); |
| 151 | 169 | ||
| 152 | if (dev->unique) { | 170 | if (dev->irq_enabled && !drm_core_check_feature(dev, DRIVER_MODESET)) |
| 153 | drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER); | ||
| 154 | dev->unique = NULL; | ||
| 155 | dev->unique_len = 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | if (dev->irq_enabled) | ||
| 159 | drm_irq_uninstall(dev); | 171 | drm_irq_uninstall(dev); |
| 160 | 172 | ||
| 161 | mutex_lock(&dev->struct_mutex); | 173 | mutex_lock(&dev->struct_mutex); |
| @@ -164,18 +176,9 @@ int drm_lastclose(struct drm_device * dev) | |||
| 164 | drm_drawable_free_all(dev); | 176 | drm_drawable_free_all(dev); |
| 165 | del_timer(&dev->timer); | 177 | del_timer(&dev->timer); |
| 166 | 178 | ||
| 167 | /* Clear pid list */ | ||
| 168 | if (dev->magicfree.next) { | ||
| 169 | list_for_each_entry_safe(pt, next, &dev->magicfree, head) { | ||
| 170 | list_del(&pt->head); | ||
| 171 | drm_ht_remove_item(&dev->magiclist, &pt->hash_item); | ||
| 172 | drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); | ||
| 173 | } | ||
| 174 | drm_ht_remove(&dev->magiclist); | ||
| 175 | } | ||
| 176 | |||
| 177 | /* Clear AGP information */ | 179 | /* Clear AGP information */ |
| 178 | if (drm_core_has_AGP(dev) && dev->agp) { | 180 | if (drm_core_has_AGP(dev) && dev->agp && |
| 181 | !drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
| 179 | struct drm_agp_mem *entry, *tempe; | 182 | struct drm_agp_mem *entry, *tempe; |
| 180 | 183 | ||
| 181 | /* Remove AGP resources, but leave dev->agp | 184 | /* Remove AGP resources, but leave dev->agp |
| @@ -194,7 +197,8 @@ int drm_lastclose(struct drm_device * dev) | |||
| 194 | dev->agp->acquired = 0; | 197 | dev->agp->acquired = 0; |
| 195 | dev->agp->enabled = 0; | 198 | dev->agp->enabled = 0; |
| 196 | } | 199 | } |
| 197 | if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg) { | 200 | if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg && |
| 201 | !drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
| 198 | drm_sg_cleanup(dev->sg); | 202 | drm_sg_cleanup(dev->sg); |
| 199 | dev->sg = NULL; | 203 | dev->sg = NULL; |
| 200 | } | 204 | } |
| @@ -205,13 +209,6 @@ int drm_lastclose(struct drm_device * dev) | |||
| 205 | drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); | 209 | drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); |
| 206 | } | 210 | } |
| 207 | 211 | ||
| 208 | list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) { | ||
| 209 | if (!(r_list->map->flags & _DRM_DRIVER)) { | ||
| 210 | drm_rmmap_locked(dev, r_list->map); | ||
| 211 | r_list = NULL; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) { | 212 | if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) { |
| 216 | for (i = 0; i < dev->queue_count; i++) { | 213 | for (i = 0; i < dev->queue_count; i++) { |
| 217 | if (dev->queuelist[i]) { | 214 | if (dev->queuelist[i]) { |
| @@ -228,14 +225,11 @@ int drm_lastclose(struct drm_device * dev) | |||
| 228 | } | 225 | } |
| 229 | dev->queue_count = 0; | 226 | dev->queue_count = 0; |
| 230 | 227 | ||
| 231 | if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) | 228 | if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && |
| 229 | !drm_core_check_feature(dev, DRIVER_MODESET)) | ||
| 232 | drm_dma_takedown(dev); | 230 | drm_dma_takedown(dev); |
| 233 | 231 | ||
| 234 | if (dev->lock.hw_lock) { | 232 | dev->dev_mapping = NULL; |
| 235 | dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ | ||
| 236 | dev->lock.file_priv = NULL; | ||
| 237 | wake_up_interruptible(&dev->lock.lock_queue); | ||
| 238 | } | ||
| 239 | mutex_unlock(&dev->struct_mutex); | 233 | mutex_unlock(&dev->struct_mutex); |
| 240 | 234 | ||
| 241 | DRM_DEBUG("lastclose completed\n"); | 235 | DRM_DEBUG("lastclose completed\n"); |
| @@ -263,6 +257,8 @@ int drm_init(struct drm_driver *driver) | |||
| 263 | 257 | ||
| 264 | DRM_DEBUG("\n"); | 258 | DRM_DEBUG("\n"); |
| 265 | 259 | ||
| 260 | INIT_LIST_HEAD(&driver->device_list); | ||
| 261 | |||
| 266 | for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) { | 262 | for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) { |
| 267 | pid = (struct pci_device_id *)&driver->pci_driver.id_table[i]; | 263 | pid = (struct pci_device_id *)&driver->pci_driver.id_table[i]; |
| 268 | 264 | ||
| @@ -329,35 +325,24 @@ static void drm_cleanup(struct drm_device * dev) | |||
| 329 | drm_ht_remove(&dev->map_hash); | 325 | drm_ht_remove(&dev->map_hash); |
| 330 | drm_ctxbitmap_cleanup(dev); | 326 | drm_ctxbitmap_cleanup(dev); |
| 331 | 327 | ||
| 328 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
| 329 | drm_put_minor(&dev->control); | ||
| 330 | |||
| 331 | if (dev->driver->driver_features & DRIVER_GEM) | ||
| 332 | drm_gem_destroy(dev); | ||
| 333 | |||
| 332 | drm_put_minor(&dev->primary); | 334 | drm_put_minor(&dev->primary); |
| 333 | if (drm_put_dev(dev)) | 335 | if (drm_put_dev(dev)) |
| 334 | DRM_ERROR("Cannot unload module\n"); | 336 | DRM_ERROR("Cannot unload module\n"); |
| 335 | } | 337 | } |
| 336 | 338 | ||
| 337 | static int drm_minors_cleanup(int id, void *ptr, void *data) | ||
| 338 | { | ||
| 339 | struct drm_minor *minor = ptr; | ||
| 340 | struct drm_device *dev; | ||
| 341 | struct drm_driver *driver = data; | ||
| 342 | |||
| 343 | dev = minor->dev; | ||
| 344 | if (minor->dev->driver != driver) | ||
| 345 | return 0; | ||
| 346 | |||
| 347 | if (minor->type != DRM_MINOR_LEGACY) | ||
| 348 | return 0; | ||
| 349 | |||
| 350 | if (dev) | ||
| 351 | pci_dev_put(dev->pdev); | ||
| 352 | drm_cleanup(dev); | ||
| 353 | return 1; | ||
| 354 | } | ||
| 355 | |||
| 356 | void drm_exit(struct drm_driver *driver) | 339 | void drm_exit(struct drm_driver *driver) |
| 357 | { | 340 | { |
| 341 | struct drm_device *dev, *tmp; | ||
| 358 | DRM_DEBUG("\n"); | 342 | DRM_DEBUG("\n"); |
| 359 | 343 | ||
| 360 | idr_for_each(&drm_minors_idr, &drm_minors_cleanup, driver); | 344 | list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item) |
| 345 | drm_cleanup(dev); | ||
| 361 | 346 | ||
| 362 | DRM_INFO("Module unloaded\n"); | 347 | DRM_INFO("Module unloaded\n"); |
| 363 | } | 348 | } |
| @@ -503,7 +488,7 @@ int drm_ioctl(struct inode *inode, struct file *filp, | |||
| 503 | retcode = -EINVAL; | 488 | retcode = -EINVAL; |
| 504 | } else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) || | 489 | } else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) || |
| 505 | ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) || | 490 | ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) || |
| 506 | ((ioctl->flags & DRM_MASTER) && !file_priv->master)) { | 491 | ((ioctl->flags & DRM_MASTER) && !file_priv->is_master)) { |
| 507 | retcode = -EACCES; | 492 | retcode = -EACCES; |
| 508 | } else { | 493 | } else { |
| 509 | if (cmd & (IOC_IN | IOC_OUT)) { | 494 | if (cmd & (IOC_IN | IOC_OUT)) { |
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c new file mode 100644 index 000000000000..0fbb0da342cb --- /dev/null +++ b/drivers/gpu/drm/drm_edid.c | |||
| @@ -0,0 +1,732 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2006 Luc Verhaegen (quirks list) | ||
| 3 | * Copyright (c) 2007-2008 Intel Corporation | ||
| 4 | * Jesse Barnes <jesse.barnes@intel.com> | ||
| 5 | * | ||
| 6 | * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from | ||
| 7 | * FB layer. | ||
| 8 | * Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com> | ||
| 9 | * | ||
| 10 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 11 | * copy of this software and associated documentation files (the "Software"), | ||
| 12 | * to deal in the Software without restriction, including without limitation | ||
| 13 | * the rights to use, copy, modify, merge, publish, distribute, sub license, | ||
| 14 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 15 | * Software is furnished to do so, subject to the following conditions: | ||
| 16 | * | ||
| 17 | * The above copyright notice and this permission notice (including the | ||
| 18 | * next paragraph) shall be included in all copies or substantial portions | ||
| 19 | * of the Software. | ||
| 20 | * | ||
| 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
| 24 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 27 | * DEALINGS IN THE SOFTWARE. | ||
| 28 | */ | ||
| 29 | #include <linux/kernel.h> | ||
| 30 | #include <linux/i2c.h> | ||
| 31 | #include <linux/i2c-algo-bit.h> | ||
| 32 | #include "drmP.h" | ||
| 33 | #include "drm_edid.h" | ||
| 34 | |||
| 35 | /* | ||
| 36 | * TODO: | ||
| 37 | * - support EDID 1.4 (incl. CE blocks) | ||
| 38 | */ | ||
| 39 | |||
| 40 | /* | ||
| 41 | * EDID blocks out in the wild have a variety of bugs, try to collect | ||
| 42 | * them here (note that userspace may work around broken monitors first, | ||
| 43 | * but fixes should make their way here so that the kernel "just works" | ||
| 44 | * on as many displays as possible). | ||
| 45 | */ | ||
| 46 | |||
| 47 | /* First detailed mode wrong, use largest 60Hz mode */ | ||
| 48 | #define EDID_QUIRK_PREFER_LARGE_60 (1 << 0) | ||
| 49 | /* Reported 135MHz pixel clock is too high, needs adjustment */ | ||
| 50 | #define EDID_QUIRK_135_CLOCK_TOO_HIGH (1 << 1) | ||
| 51 | /* Prefer the largest mode at 75 Hz */ | ||
| 52 | #define EDID_QUIRK_PREFER_LARGE_75 (1 << 2) | ||
| 53 | /* Detail timing is in cm not mm */ | ||
| 54 | #define EDID_QUIRK_DETAILED_IN_CM (1 << 3) | ||
| 55 | /* Detailed timing descriptors have bogus size values, so just take the | ||
| 56 | * maximum size and use that. | ||
| 57 | */ | ||
| 58 | #define EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE (1 << 4) | ||
| 59 | /* Monitor forgot to set the first detailed is preferred bit. */ | ||
| 60 | #define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5) | ||
| 61 | /* use +hsync +vsync for detailed mode */ | ||
| 62 | #define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6) | ||
| 63 | |||
| 64 | static struct edid_quirk { | ||
| 65 | char *vendor; | ||
| 66 | int product_id; | ||
| 67 | u32 quirks; | ||
| 68 | } edid_quirk_list[] = { | ||
| 69 | /* Acer AL1706 */ | ||
| 70 | { "ACR", 44358, EDID_QUIRK_PREFER_LARGE_60 }, | ||
| 71 | /* Acer F51 */ | ||
| 72 | { "API", 0x7602, EDID_QUIRK_PREFER_LARGE_60 }, | ||
| 73 | /* Unknown Acer */ | ||
| 74 | { "ACR", 2423, EDID_QUIRK_FIRST_DETAILED_PREFERRED }, | ||
| 75 | |||
| 76 | /* Belinea 10 15 55 */ | ||
| 77 | { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 }, | ||
| 78 | { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 }, | ||
| 79 | |||
| 80 | /* Envision Peripherals, Inc. EN-7100e */ | ||
| 81 | { "EPI", 59264, EDID_QUIRK_135_CLOCK_TOO_HIGH }, | ||
| 82 | |||
| 83 | /* Funai Electronics PM36B */ | ||
| 84 | { "FCM", 13600, EDID_QUIRK_PREFER_LARGE_75 | | ||
| 85 | EDID_QUIRK_DETAILED_IN_CM }, | ||
| 86 | |||
| 87 | /* LG Philips LCD LP154W01-A5 */ | ||
| 88 | { "LPL", 0, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE }, | ||
| 89 | { "LPL", 0x2a00, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE }, | ||
| 90 | |||
| 91 | /* Philips 107p5 CRT */ | ||
| 92 | { "PHL", 57364, EDID_QUIRK_FIRST_DETAILED_PREFERRED }, | ||
| 93 | |||
| 94 | /* Proview AY765C */ | ||
| 95 | { "PTS", 765, EDID_QUIRK_FIRST_DETAILED_PREFERRED }, | ||
| 96 | |||
| 97 | /* Samsung SyncMaster 205BW. Note: irony */ | ||
| 98 | { "SAM", 541, EDID_QUIRK_DETAILED_SYNC_PP }, | ||
| 99 | /* Samsung SyncMaster 22[5-6]BW */ | ||
| 100 | { "SAM", 596, EDID_QUIRK_PREFER_LARGE_60 }, | ||
| 101 | { "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 }, | ||
| 102 | }; | ||
| 103 | |||
| 104 | |||
| 105 | /* Valid EDID header has these bytes */ | ||
| 106 | static u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; | ||
| 107 | |||
| 108 | /** | ||
| 109 | * edid_is_valid - sanity check EDID data | ||
| 110 | * @edid: EDID data | ||
| 111 | * | ||
| 112 | * Sanity check the EDID block by looking at the header, the version number | ||
| 113 | * and the checksum. Return 0 if the EDID doesn't check out, or 1 if it's | ||
| 114 | * valid. | ||
| 115 | */ | ||
| 116 | static bool edid_is_valid(struct edid *edid) | ||
| 117 | { | ||
| 118 | int i; | ||
| 119 | u8 csum = 0; | ||
| 120 | u8 *raw_edid = (u8 *)edid; | ||
| 121 | |||
| 122 | if (memcmp(edid->header, edid_header, sizeof(edid_header))) | ||
| 123 | goto bad; | ||
| 124 | if (edid->version != 1) { | ||
| 125 | DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version); | ||
| 126 | goto bad; | ||
| 127 | } | ||
| 128 | if (edid->revision <= 0 || edid->revision > 3) { | ||
| 129 | DRM_ERROR("EDID has minor version %d, which is not between 0-3\n", edid->revision); | ||
| 130 | goto bad; | ||
| 131 | } | ||
| 132 | |||
| 133 | for (i = 0; i < EDID_LENGTH; i++) | ||
| 134 | csum += raw_edid[i]; | ||
| 135 | if (csum) { | ||
| 136 | DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum); | ||
| 137 | goto bad; | ||
| 138 | } | ||
| 139 | |||
| 140 | return 1; | ||
| 141 | |||
| 142 | bad: | ||
| 143 | if (raw_edid) { | ||
| 144 | DRM_ERROR("Raw EDID:\n"); | ||
| 145 | print_hex_dump_bytes(KERN_ERR, DUMP_PREFIX_NONE, raw_edid, EDID_LENGTH); | ||
| 146 | printk("\n"); | ||
| 147 | } | ||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | /** | ||
| 152 | * edid_vendor - match a string against EDID's obfuscated vendor field | ||
| 153 | * @edid: EDID to match | ||
| 154 | * @vendor: vendor string | ||
| 155 | * | ||
| 156 | * Returns true if @vendor is in @edid, false otherwise | ||
| 157 | */ | ||
| 158 | static bool edid_vendor(struct edid *edid, char *vendor) | ||
| 159 | { | ||
| 160 | char edid_vendor[3]; | ||
| 161 | |||
| 162 | edid_vendor[0] = ((edid->mfg_id[0] & 0x7c) >> 2) + '@'; | ||
| 163 | edid_vendor[1] = (((edid->mfg_id[0] & 0x3) << 3) | | ||
| 164 | ((edid->mfg_id[1] & 0xe0) >> 5)) + '@'; | ||
| 165 | edid_vendor[2] = (edid->mfg_id[2] & 0x1f) + '@'; | ||
| 166 | |||
| 167 | return !strncmp(edid_vendor, vendor, 3); | ||
| 168 | } | ||
| 169 | |||
| 170 | /** | ||
| 171 | * edid_get_quirks - return quirk flags for a given EDID | ||
| 172 | * @edid: EDID to process | ||
| 173 | * | ||
| 174 | * This tells subsequent routines what fixes they need to apply. | ||
| 175 | */ | ||
| 176 | static u32 edid_get_quirks(struct edid *edid) | ||
| 177 | { | ||
| 178 | struct edid_quirk *quirk; | ||
| 179 | int i; | ||
| 180 | |||
| 181 | for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) { | ||
| 182 | quirk = &edid_quirk_list[i]; | ||
| 183 | |||
| 184 | if (edid_vendor(edid, quirk->vendor) && | ||
| 185 | (EDID_PRODUCT_ID(edid) == quirk->product_id)) | ||
| 186 | return quirk->quirks; | ||
| 187 | } | ||
| 188 | |||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 192 | #define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay) | ||
| 193 | #define MODE_REFRESH_DIFF(m,r) (abs((m)->vrefresh - target_refresh)) | ||
| 194 | |||
| 195 | |||
| 196 | /** | ||
| 197 | * edid_fixup_preferred - set preferred modes based on quirk list | ||
| 198 | * @connector: has mode list to fix up | ||
| 199 | * @quirks: quirks list | ||
| 200 | * | ||
| 201 | * Walk the mode list for @connector, clearing the preferred status | ||
| 202 | * on existing modes and setting it anew for the right mode ala @quirks. | ||
| 203 | */ | ||
| 204 | static void edid_fixup_preferred(struct drm_connector *connector, | ||
| 205 | u32 quirks) | ||
| 206 | { | ||
| 207 | struct drm_display_mode *t, *cur_mode, *preferred_mode; | ||
| 208 | int target_refresh = 0; | ||
| 209 | |||
| 210 | if (list_empty(&connector->probed_modes)) | ||
| 211 | return; | ||
| 212 | |||
| 213 | if (quirks & EDID_QUIRK_PREFER_LARGE_60) | ||
| 214 | target_refresh = 60; | ||
| 215 | if (quirks & EDID_QUIRK_PREFER_LARGE_75) | ||
| 216 | target_refresh = 75; | ||
| 217 | |||
| 218 | preferred_mode = list_first_entry(&connector->probed_modes, | ||
| 219 | struct drm_display_mode, head); | ||
| 220 | |||
| 221 | list_for_each_entry_safe(cur_mode, t, &connector->probed_modes, head) { | ||
| 222 | cur_mode->type &= ~DRM_MODE_TYPE_PREFERRED; | ||
| 223 | |||
| 224 | if (cur_mode == preferred_mode) | ||
| 225 | continue; | ||
| 226 | |||
| 227 | /* Largest mode is preferred */ | ||
| 228 | if (MODE_SIZE(cur_mode) > MODE_SIZE(preferred_mode)) | ||
| 229 | preferred_mode = cur_mode; | ||
| 230 | |||
| 231 | /* At a given size, try to get closest to target refresh */ | ||
| 232 | if ((MODE_SIZE(cur_mode) == MODE_SIZE(preferred_mode)) && | ||
| 233 | MODE_REFRESH_DIFF(cur_mode, target_refresh) < | ||
| 234 | MODE_REFRESH_DIFF(preferred_mode, target_refresh)) { | ||
| 235 | preferred_mode = cur_mode; | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 | preferred_mode->type |= DRM_MODE_TYPE_PREFERRED; | ||
| 240 | } | ||
| 241 | |||
| 242 | /** | ||
| 243 | * drm_mode_std - convert standard mode info (width, height, refresh) into mode | ||
| 244 | * @t: standard timing params | ||
| 245 | * | ||
| 246 | * Take the standard timing params (in this case width, aspect, and refresh) | ||
| 247 | * and convert them into a real mode using CVT. | ||
| 248 | * | ||
| 249 | * Punts for now, but should eventually use the FB layer's CVT based mode | ||
| 250 | * generation code. | ||
| 251 | */ | ||
| 252 | struct drm_display_mode *drm_mode_std(struct drm_device *dev, | ||
| 253 | struct std_timing *t) | ||
| 254 | { | ||
| 255 | struct drm_display_mode *mode; | ||
| 256 | int hsize = t->hsize * 8 + 248, vsize; | ||
| 257 | |||
| 258 | mode = drm_mode_create(dev); | ||
| 259 | if (!mode) | ||
| 260 | return NULL; | ||
| 261 | |||
| 262 | if (t->aspect_ratio == 0) | ||
| 263 | vsize = (hsize * 10) / 16; | ||
| 264 | else if (t->aspect_ratio == 1) | ||
| 265 | vsize = (hsize * 3) / 4; | ||
| 266 | else if (t->aspect_ratio == 2) | ||
| 267 | vsize = (hsize * 4) / 5; | ||
| 268 | else | ||
| 269 | vsize = (hsize * 9) / 16; | ||
| 270 | |||
| 271 | drm_mode_set_name(mode); | ||
| 272 | |||
| 273 | return mode; | ||
| 274 | } | ||
| 275 | |||
| 276 | /** | ||
| 277 | * drm_mode_detailed - create a new mode from an EDID detailed timing section | ||
| 278 | * @dev: DRM device (needed to create new mode) | ||
| 279 | * @edid: EDID block | ||
| 280 | * @timing: EDID detailed timing info | ||
| 281 | * @quirks: quirks to apply | ||
| 282 | * | ||
| 283 | * An EDID detailed timing block contains enough info for us to create and | ||
| 284 | * return a new struct drm_display_mode. | ||
| 285 | */ | ||
| 286 | static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, | ||
| 287 | struct edid *edid, | ||
| 288 | struct detailed_timing *timing, | ||
| 289 | u32 quirks) | ||
| 290 | { | ||
| 291 | struct drm_display_mode *mode; | ||
| 292 | struct detailed_pixel_timing *pt = &timing->data.pixel_data; | ||
| 293 | |||
| 294 | if (pt->stereo) { | ||
| 295 | printk(KERN_WARNING "stereo mode not supported\n"); | ||
| 296 | return NULL; | ||
| 297 | } | ||
| 298 | if (!pt->separate_sync) { | ||
| 299 | printk(KERN_WARNING "integrated sync not supported\n"); | ||
| 300 | return NULL; | ||
| 301 | } | ||
| 302 | |||
| 303 | mode = drm_mode_create(dev); | ||
| 304 | if (!mode) | ||
| 305 | return NULL; | ||
| 306 | |||
| 307 | mode->type = DRM_MODE_TYPE_DRIVER; | ||
| 308 | |||
| 309 | if (quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH) | ||
| 310 | timing->pixel_clock = 1088; | ||
| 311 | |||
| 312 | mode->clock = timing->pixel_clock * 10; | ||
| 313 | |||
| 314 | mode->hdisplay = (pt->hactive_hi << 8) | pt->hactive_lo; | ||
| 315 | mode->hsync_start = mode->hdisplay + ((pt->hsync_offset_hi << 8) | | ||
| 316 | pt->hsync_offset_lo); | ||
| 317 | mode->hsync_end = mode->hsync_start + | ||
| 318 | ((pt->hsync_pulse_width_hi << 8) | | ||
| 319 | pt->hsync_pulse_width_lo); | ||
| 320 | mode->htotal = mode->hdisplay + ((pt->hblank_hi << 8) | pt->hblank_lo); | ||
| 321 | |||
| 322 | mode->vdisplay = (pt->vactive_hi << 8) | pt->vactive_lo; | ||
| 323 | mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 8) | | ||
| 324 | pt->vsync_offset_lo); | ||
| 325 | mode->vsync_end = mode->vsync_start + | ||
| 326 | ((pt->vsync_pulse_width_hi << 8) | | ||
| 327 | pt->vsync_pulse_width_lo); | ||
| 328 | mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) | pt->vblank_lo); | ||
| 329 | |||
| 330 | drm_mode_set_name(mode); | ||
| 331 | |||
| 332 | if (pt->interlaced) | ||
| 333 | mode->flags |= DRM_MODE_FLAG_INTERLACE; | ||
| 334 | |||
| 335 | if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { | ||
| 336 | pt->hsync_positive = 1; | ||
| 337 | pt->vsync_positive = 1; | ||
| 338 | } | ||
| 339 | |||
| 340 | mode->flags |= pt->hsync_positive ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; | ||
| 341 | mode->flags |= pt->vsync_positive ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; | ||
| 342 | |||
| 343 | mode->width_mm = pt->width_mm_lo | (pt->width_mm_hi << 8); | ||
| 344 | mode->height_mm = pt->height_mm_lo | (pt->height_mm_hi << 8); | ||
| 345 | |||
| 346 | if (quirks & EDID_QUIRK_DETAILED_IN_CM) { | ||
| 347 | mode->width_mm *= 10; | ||
| 348 | mode->height_mm *= 10; | ||
| 349 | } | ||
| 350 | |||
| 351 | if (quirks & EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE) { | ||
| 352 | mode->width_mm = edid->width_cm * 10; | ||
| 353 | mode->height_mm = edid->height_cm * 10; | ||
| 354 | } | ||
| 355 | |||
| 356 | return mode; | ||
| 357 | } | ||
| 358 | |||
| 359 | /* | ||
| 360 | * Detailed mode info for the EDID "established modes" data to use. | ||
| 361 | */ | ||
| 362 | static struct drm_display_mode edid_est_modes[] = { | ||
| 363 | { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, | ||
| 364 | 968, 1056, 0, 600, 601, 605, 628, 0, | ||
| 365 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */ | ||
| 366 | { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824, | ||
| 367 | 896, 1024, 0, 600, 601, 603, 625, 0, | ||
| 368 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */ | ||
| 369 | { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656, | ||
| 370 | 720, 840, 0, 480, 481, 484, 500, 0, | ||
| 371 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */ | ||
| 372 | { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664, | ||
| 373 | 704, 832, 0, 480, 489, 491, 520, 0, | ||
| 374 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */ | ||
| 375 | { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704, | ||
| 376 | 768, 864, 0, 480, 483, 486, 525, 0, | ||
| 377 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */ | ||
| 378 | { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656, | ||
| 379 | 752, 800, 0, 480, 490, 492, 525, 0, | ||
| 380 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */ | ||
| 381 | { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738, | ||
| 382 | 846, 900, 0, 400, 421, 423, 449, 0, | ||
| 383 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */ | ||
| 384 | { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738, | ||
| 385 | 846, 900, 0, 400, 412, 414, 449, 0, | ||
| 386 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */ | ||
| 387 | { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296, | ||
| 388 | 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, | ||
| 389 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */ | ||
| 390 | { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040, | ||
| 391 | 1136, 1312, 0, 768, 769, 772, 800, 0, | ||
| 392 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */ | ||
| 393 | { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048, | ||
| 394 | 1184, 1328, 0, 768, 771, 777, 806, 0, | ||
| 395 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */ | ||
| 396 | { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, | ||
| 397 | 1184, 1344, 0, 768, 771, 777, 806, 0, | ||
| 398 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */ | ||
| 399 | { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032, | ||
| 400 | 1208, 1264, 0, 768, 768, 776, 817, 0, | ||
| 401 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */ | ||
| 402 | { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864, | ||
| 403 | 928, 1152, 0, 624, 625, 628, 667, 0, | ||
| 404 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */ | ||
| 405 | { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816, | ||
| 406 | 896, 1056, 0, 600, 601, 604, 625, 0, | ||
| 407 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */ | ||
| 408 | { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856, | ||
| 409 | 976, 1040, 0, 600, 637, 643, 666, 0, | ||
| 410 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */ | ||
| 411 | { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216, | ||
| 412 | 1344, 1600, 0, 864, 865, 868, 900, 0, | ||
| 413 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */ | ||
| 414 | }; | ||
| 415 | |||
| 416 | #define EDID_EST_TIMINGS 16 | ||
| 417 | #define EDID_STD_TIMINGS 8 | ||
| 418 | #define EDID_DETAILED_TIMINGS 4 | ||
| 419 | |||
| 420 | /** | ||
| 421 | * add_established_modes - get est. modes from EDID and add them | ||
| 422 | * @edid: EDID block to scan | ||
| 423 | * | ||
| 424 | * Each EDID block contains a bitmap of the supported "established modes" list | ||
| 425 | * (defined above). Tease them out and add them to the global modes list. | ||
| 426 | */ | ||
| 427 | static int add_established_modes(struct drm_connector *connector, struct edid *edid) | ||
| 428 | { | ||
| 429 | struct drm_device *dev = connector->dev; | ||
| 430 | unsigned long est_bits = edid->established_timings.t1 | | ||
| 431 | (edid->established_timings.t2 << 8) | | ||
| 432 | ((edid->established_timings.mfg_rsvd & 0x80) << 9); | ||
| 433 | int i, modes = 0; | ||
| 434 | |||
| 435 | for (i = 0; i <= EDID_EST_TIMINGS; i++) | ||
| 436 | if (est_bits & (1<<i)) { | ||
| 437 | struct drm_display_mode *newmode; | ||
| 438 | newmode = drm_mode_duplicate(dev, &edid_est_modes[i]); | ||
| 439 | if (newmode) { | ||
| 440 | drm_mode_probed_add(connector, newmode); | ||
| 441 | modes++; | ||
| 442 | } | ||
| 443 | } | ||
| 444 | |||
| 445 | return modes; | ||
| 446 | } | ||
| 447 | |||
| 448 | /** | ||
| 449 | * add_standard_modes - get std. modes from EDID and add them | ||
| 450 | * @edid: EDID block to scan | ||
| 451 | * | ||
| 452 | * Standard modes can be calculated using the CVT standard. Grab them from | ||
| 453 | * @edid, calculate them, and add them to the list. | ||
| 454 | */ | ||
| 455 | static int add_standard_modes(struct drm_connector *connector, struct edid *edid) | ||
| 456 | { | ||
| 457 | struct drm_device *dev = connector->dev; | ||
| 458 | int i, modes = 0; | ||
| 459 | |||
| 460 | for (i = 0; i < EDID_STD_TIMINGS; i++) { | ||
| 461 | struct std_timing *t = &edid->standard_timings[i]; | ||
| 462 | struct drm_display_mode *newmode; | ||
| 463 | |||
| 464 | /* If std timings bytes are 1, 1 it's empty */ | ||
| 465 | if (t->hsize == 1 && (t->aspect_ratio | t->vfreq) == 1) | ||
| 466 | continue; | ||
| 467 | |||
| 468 | newmode = drm_mode_std(dev, &edid->standard_timings[i]); | ||
| 469 | if (newmode) { | ||
| 470 | drm_mode_probed_add(connector, newmode); | ||
| 471 | modes++; | ||
| 472 | } | ||
| 473 | } | ||
| 474 | |||
| 475 | return modes; | ||
| 476 | } | ||
| 477 | |||
| 478 | /** | ||
| 479 | * add_detailed_modes - get detailed mode info from EDID data | ||
| 480 | * @connector: attached connector | ||
| 481 | * @edid: EDID block to scan | ||
| 482 | * @quirks: quirks to apply | ||
| 483 | * | ||
| 484 | * Some of the detailed timing sections may contain mode information. Grab | ||
| 485 | * it and add it to the list. | ||
| 486 | */ | ||
| 487 | static int add_detailed_info(struct drm_connector *connector, | ||
| 488 | struct edid *edid, u32 quirks) | ||
| 489 | { | ||
| 490 | struct drm_device *dev = connector->dev; | ||
| 491 | int i, j, modes = 0; | ||
| 492 | |||
| 493 | for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { | ||
| 494 | struct detailed_timing *timing = &edid->detailed_timings[i]; | ||
| 495 | struct detailed_non_pixel *data = &timing->data.other_data; | ||
| 496 | struct drm_display_mode *newmode; | ||
| 497 | |||
| 498 | /* EDID up to and including 1.2 may put monitor info here */ | ||
| 499 | if (edid->version == 1 && edid->revision < 3) | ||
| 500 | continue; | ||
| 501 | |||
| 502 | /* Detailed mode timing */ | ||
| 503 | if (timing->pixel_clock) { | ||
| 504 | newmode = drm_mode_detailed(dev, edid, timing, quirks); | ||
| 505 | if (!newmode) | ||
| 506 | continue; | ||
| 507 | |||
| 508 | /* First detailed mode is preferred */ | ||
| 509 | if (i == 0 && edid->preferred_timing) | ||
| 510 | newmode->type |= DRM_MODE_TYPE_PREFERRED; | ||
| 511 | drm_mode_probed_add(connector, newmode); | ||
| 512 | |||
| 513 | modes++; | ||
| 514 | continue; | ||
| 515 | } | ||
| 516 | |||
| 517 | /* Other timing or info */ | ||
| 518 | switch (data->type) { | ||
| 519 | case EDID_DETAIL_MONITOR_SERIAL: | ||
| 520 | break; | ||
| 521 | case EDID_DETAIL_MONITOR_STRING: | ||
| 522 | break; | ||
| 523 | case EDID_DETAIL_MONITOR_RANGE: | ||
| 524 | /* Get monitor range data */ | ||
| 525 | break; | ||
| 526 | case EDID_DETAIL_MONITOR_NAME: | ||
| 527 | break; | ||
| 528 | case EDID_DETAIL_MONITOR_CPDATA: | ||
| 529 | break; | ||
| 530 | case EDID_DETAIL_STD_MODES: | ||
| 531 | /* Five modes per detailed section */ | ||
| 532 | for (j = 0; j < 5; i++) { | ||
| 533 | struct std_timing *std; | ||
| 534 | struct drm_display_mode *newmode; | ||
| 535 | |||
| 536 | std = &data->data.timings[j]; | ||
| 537 | newmode = drm_mode_std(dev, std); | ||
| 538 | if (newmode) { | ||
| 539 | drm_mode_probed_add(connector, newmode); | ||
| 540 | modes++; | ||
| 541 | } | ||
| 542 | } | ||
| 543 | break; | ||
| 544 | default: | ||
| 545 | break; | ||
| 546 | } | ||
| 547 | } | ||
| 548 | |||
| 549 | return modes; | ||
| 550 | } | ||
| 551 | |||
| 552 | #define DDC_ADDR 0x50 | ||
| 553 | |||
| 554 | unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter) | ||
| 555 | { | ||
| 556 | unsigned char start = 0x0; | ||
| 557 | unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL); | ||
| 558 | struct i2c_msg msgs[] = { | ||
| 559 | { | ||
| 560 | .addr = DDC_ADDR, | ||
| 561 | .flags = 0, | ||
| 562 | .len = 1, | ||
| 563 | .buf = &start, | ||
| 564 | }, { | ||
| 565 | .addr = DDC_ADDR, | ||
| 566 | .flags = I2C_M_RD, | ||
| 567 | .len = EDID_LENGTH, | ||
| 568 | .buf = buf, | ||
| 569 | } | ||
| 570 | }; | ||
| 571 | |||
| 572 | if (!buf) { | ||
| 573 | dev_warn(&adapter->dev, "unable to allocate memory for EDID " | ||
| 574 | "block.\n"); | ||
| 575 | return NULL; | ||
| 576 | } | ||
| 577 | |||
| 578 | if (i2c_transfer(adapter, msgs, 2) == 2) | ||
| 579 | return buf; | ||
| 580 | |||
| 581 | dev_info(&adapter->dev, "unable to read EDID block.\n"); | ||
| 582 | kfree(buf); | ||
| 583 | return NULL; | ||
| 584 | } | ||
| 585 | EXPORT_SYMBOL(drm_do_probe_ddc_edid); | ||
| 586 | |||
| 587 | static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) | ||
| 588 | { | ||
| 589 | struct i2c_algo_bit_data *algo_data = adapter->algo_data; | ||
| 590 | unsigned char *edid = NULL; | ||
| 591 | int i, j; | ||
| 592 | |||
| 593 | algo_data->setscl(algo_data->data, 1); | ||
| 594 | |||
| 595 | for (i = 0; i < 1; i++) { | ||
| 596 | /* For some old monitors we need the | ||
| 597 | * following process to initialize/stop DDC | ||
| 598 | */ | ||
| 599 | algo_data->setsda(algo_data->data, 1); | ||
| 600 | msleep(13); | ||
| 601 | |||
| 602 | algo_data->setscl(algo_data->data, 1); | ||
| 603 | for (j = 0; j < 5; j++) { | ||
| 604 | msleep(10); | ||
| 605 | if (algo_data->getscl(algo_data->data)) | ||
| 606 | break; | ||
| 607 | } | ||
| 608 | if (j == 5) | ||
| 609 | continue; | ||
| 610 | |||
| 611 | algo_data->setsda(algo_data->data, 0); | ||
| 612 | msleep(15); | ||
| 613 | algo_data->setscl(algo_data->data, 0); | ||
| 614 | msleep(15); | ||
| 615 | algo_data->setsda(algo_data->data, 1); | ||
| 616 | msleep(15); | ||
| 617 | |||
| 618 | /* Do the real work */ | ||
| 619 | edid = drm_do_probe_ddc_edid(adapter); | ||
| 620 | algo_data->setsda(algo_data->data, 0); | ||
| 621 | algo_data->setscl(algo_data->data, 0); | ||
| 622 | msleep(15); | ||
| 623 | |||
| 624 | algo_data->setscl(algo_data->data, 1); | ||
| 625 | for (j = 0; j < 10; j++) { | ||
| 626 | msleep(10); | ||
| 627 | if (algo_data->getscl(algo_data->data)) | ||
| 628 | break; | ||
| 629 | } | ||
| 630 | |||
| 631 | algo_data->setsda(algo_data->data, 1); | ||
| 632 | msleep(15); | ||
| 633 | algo_data->setscl(algo_data->data, 0); | ||
| 634 | algo_data->setsda(algo_data->data, 0); | ||
| 635 | if (edid) | ||
| 636 | break; | ||
| 637 | } | ||
| 638 | /* Release the DDC lines when done or the Apple Cinema HD display | ||
| 639 | * will switch off | ||
| 640 | */ | ||
| 641 | algo_data->setsda(algo_data->data, 1); | ||
| 642 | algo_data->setscl(algo_data->data, 1); | ||
| 643 | |||
| 644 | return edid; | ||
| 645 | } | ||
| 646 | |||
| 647 | /** | ||
| 648 | * drm_get_edid - get EDID data, if available | ||
| 649 | * @connector: connector we're probing | ||
| 650 | * @adapter: i2c adapter to use for DDC | ||
| 651 | * | ||
| 652 | * Poke the given connector's i2c channel to grab EDID data if possible. | ||
| 653 | * | ||
| 654 | * Return edid data or NULL if we couldn't find any. | ||
| 655 | */ | ||
| 656 | struct edid *drm_get_edid(struct drm_connector *connector, | ||
| 657 | struct i2c_adapter *adapter) | ||
| 658 | { | ||
| 659 | struct edid *edid; | ||
| 660 | |||
| 661 | edid = (struct edid *)drm_ddc_read(adapter); | ||
| 662 | if (!edid) { | ||
| 663 | dev_warn(&connector->dev->pdev->dev, "%s: no EDID data\n", | ||
| 664 | drm_get_connector_name(connector)); | ||
| 665 | return NULL; | ||
| 666 | } | ||
| 667 | if (!edid_is_valid(edid)) { | ||
| 668 | dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", | ||
| 669 | drm_get_connector_name(connector)); | ||
| 670 | kfree(edid); | ||
| 671 | return NULL; | ||
| 672 | } | ||
| 673 | |||
| 674 | connector->display_info.raw_edid = (char *)edid; | ||
| 675 | |||
| 676 | return edid; | ||
| 677 | } | ||
| 678 | EXPORT_SYMBOL(drm_get_edid); | ||
| 679 | |||
| 680 | /** | ||
| 681 | * drm_add_edid_modes - add modes from EDID data, if available | ||
| 682 | * @connector: connector we're probing | ||
| 683 | * @edid: edid data | ||
| 684 | * | ||
| 685 | * Add the specified modes to the connector's mode list. | ||
| 686 | * | ||
| 687 | * Return number of modes added or 0 if we couldn't find any. | ||
| 688 | */ | ||
| 689 | int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) | ||
| 690 | { | ||
| 691 | int num_modes = 0; | ||
| 692 | u32 quirks; | ||
| 693 | |||
| 694 | if (edid == NULL) { | ||
| 695 | return 0; | ||
| 696 | } | ||
| 697 | if (!edid_is_valid(edid)) { | ||
| 698 | dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", | ||
| 699 | drm_get_connector_name(connector)); | ||
| 700 | return 0; | ||
| 701 | } | ||
| 702 | |||
| 703 | quirks = edid_get_quirks(edid); | ||
| 704 | |||
| 705 | num_modes += add_established_modes(connector, edid); | ||
| 706 | num_modes += add_standard_modes(connector, edid); | ||
| 707 | num_modes += add_detailed_info(connector, edid, quirks); | ||
| 708 | |||
| 709 | if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) | ||
| 710 | edid_fixup_preferred(connector, quirks); | ||
| 711 | |||
| 712 | connector->display_info.serration_vsync = edid->serration_vsync; | ||
| 713 | connector->display_info.sync_on_green = edid->sync_on_green; | ||
| 714 | connector->display_info.composite_sync = edid->composite_sync; | ||
| 715 | connector->display_info.separate_syncs = edid->separate_syncs; | ||
| 716 | connector->display_info.blank_to_black = edid->blank_to_black; | ||
| 717 | connector->display_info.video_level = edid->video_level; | ||
| 718 | connector->display_info.digital = edid->digital; | ||
| 719 | connector->display_info.width_mm = edid->width_cm * 10; | ||
| 720 | connector->display_info.height_mm = edid->height_cm * 10; | ||
| 721 | connector->display_info.gamma = edid->gamma; | ||
| 722 | connector->display_info.gtf_supported = edid->default_gtf; | ||
| 723 | connector->display_info.standard_color = edid->standard_color; | ||
| 724 | connector->display_info.display_type = edid->display_type; | ||
| 725 | connector->display_info.active_off_supported = edid->pm_active_off; | ||
| 726 | connector->display_info.suspend_supported = edid->pm_suspend; | ||
| 727 | connector->display_info.standby_supported = edid->pm_standby; | ||
| 728 | connector->display_info.gamma = edid->gamma; | ||
| 729 | |||
| 730 | return num_modes; | ||
| 731 | } | ||
| 732 | EXPORT_SYMBOL(drm_add_edid_modes); | ||
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 78eeed5caaff..3733e36d135e 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c | |||
| @@ -35,7 +35,6 @@ | |||
| 35 | */ | 35 | */ |
| 36 | 36 | ||
| 37 | #include "drmP.h" | 37 | #include "drmP.h" |
| 38 | #include "drm_sarea.h" | ||
| 39 | #include <linux/poll.h> | 38 | #include <linux/poll.h> |
| 40 | #include <linux/smp_lock.h> | 39 | #include <linux/smp_lock.h> |
| 41 | 40 | ||
| @@ -44,10 +43,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
| 44 | 43 | ||
| 45 | static int drm_setup(struct drm_device * dev) | 44 | static int drm_setup(struct drm_device * dev) |
| 46 | { | 45 | { |
| 47 | drm_local_map_t *map; | ||
| 48 | int i; | 46 | int i; |
| 49 | int ret; | 47 | int ret; |
| 50 | u32 sareapage; | ||
| 51 | 48 | ||
| 52 | if (dev->driver->firstopen) { | 49 | if (dev->driver->firstopen) { |
| 53 | ret = dev->driver->firstopen(dev); | 50 | ret = dev->driver->firstopen(dev); |
| @@ -55,20 +52,14 @@ static int drm_setup(struct drm_device * dev) | |||
| 55 | return ret; | 52 | return ret; |
| 56 | } | 53 | } |
| 57 | 54 | ||
| 58 | dev->magicfree.next = NULL; | ||
| 59 | |||
| 60 | /* prebuild the SAREA */ | ||
| 61 | sareapage = max_t(unsigned, SAREA_MAX, PAGE_SIZE); | ||
| 62 | i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); | ||
| 63 | if (i != 0) | ||
| 64 | return i; | ||
| 65 | |||
| 66 | atomic_set(&dev->ioctl_count, 0); | 55 | atomic_set(&dev->ioctl_count, 0); |
| 67 | atomic_set(&dev->vma_count, 0); | 56 | atomic_set(&dev->vma_count, 0); |
| 68 | dev->buf_use = 0; | ||
| 69 | atomic_set(&dev->buf_alloc, 0); | ||
| 70 | 57 | ||
| 71 | if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) { | 58 | if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && |
| 59 | !drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
| 60 | dev->buf_use = 0; | ||
| 61 | atomic_set(&dev->buf_alloc, 0); | ||
| 62 | |||
| 72 | i = drm_dma_setup(dev); | 63 | i = drm_dma_setup(dev); |
| 73 | if (i < 0) | 64 | if (i < 0) |
| 74 | return i; | 65 | return i; |
| @@ -77,16 +68,12 @@ static int drm_setup(struct drm_device * dev) | |||
| 77 | for (i = 0; i < ARRAY_SIZE(dev->counts); i++) | 68 | for (i = 0; i < ARRAY_SIZE(dev->counts); i++) |
| 78 | atomic_set(&dev->counts[i], 0); | 69 | atomic_set(&dev->counts[i], 0); |
| 79 | 70 | ||
| 80 | drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER); | ||
| 81 | INIT_LIST_HEAD(&dev->magicfree); | ||
| 82 | |||
| 83 | dev->sigdata.lock = NULL; | 71 | dev->sigdata.lock = NULL; |
| 84 | init_waitqueue_head(&dev->lock.lock_queue); | 72 | |
| 85 | dev->queue_count = 0; | 73 | dev->queue_count = 0; |
| 86 | dev->queue_reserved = 0; | 74 | dev->queue_reserved = 0; |
| 87 | dev->queue_slots = 0; | 75 | dev->queue_slots = 0; |
| 88 | dev->queuelist = NULL; | 76 | dev->queuelist = NULL; |
| 89 | dev->irq_enabled = 0; | ||
| 90 | dev->context_flag = 0; | 77 | dev->context_flag = 0; |
| 91 | dev->interrupt_flag = 0; | 78 | dev->interrupt_flag = 0; |
| 92 | dev->dma_flag = 0; | 79 | dev->dma_flag = 0; |
| @@ -147,10 +134,20 @@ int drm_open(struct inode *inode, struct file *filp) | |||
| 147 | spin_lock(&dev->count_lock); | 134 | spin_lock(&dev->count_lock); |
| 148 | if (!dev->open_count++) { | 135 | if (!dev->open_count++) { |
| 149 | spin_unlock(&dev->count_lock); | 136 | spin_unlock(&dev->count_lock); |
| 150 | return drm_setup(dev); | 137 | retcode = drm_setup(dev); |
| 138 | goto out; | ||
| 151 | } | 139 | } |
| 152 | spin_unlock(&dev->count_lock); | 140 | spin_unlock(&dev->count_lock); |
| 153 | } | 141 | } |
| 142 | out: | ||
| 143 | mutex_lock(&dev->struct_mutex); | ||
| 144 | if (minor->type == DRM_MINOR_LEGACY) { | ||
| 145 | BUG_ON((dev->dev_mapping != NULL) && | ||
| 146 | (dev->dev_mapping != inode->i_mapping)); | ||
| 147 | if (dev->dev_mapping == NULL) | ||
| 148 | dev->dev_mapping = inode->i_mapping; | ||
| 149 | } | ||
| 150 | mutex_unlock(&dev->struct_mutex); | ||
| 154 | 151 | ||
| 155 | return retcode; | 152 | return retcode; |
| 156 | } | 153 | } |
| @@ -255,6 +252,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
| 255 | priv->lock_count = 0; | 252 | priv->lock_count = 0; |
| 256 | 253 | ||
| 257 | INIT_LIST_HEAD(&priv->lhead); | 254 | INIT_LIST_HEAD(&priv->lhead); |
| 255 | INIT_LIST_HEAD(&priv->fbs); | ||
| 258 | 256 | ||
| 259 | if (dev->driver->driver_features & DRIVER_GEM) | 257 | if (dev->driver->driver_features & DRIVER_GEM) |
| 260 | drm_gem_open(dev, priv); | 258 | drm_gem_open(dev, priv); |
| @@ -265,10 +263,42 @@ static int drm_open_helper(struct inode *inode, struct file *filp, | |||
| 265 | goto out_free; | 263 | goto out_free; |
| 266 | } | 264 | } |
| 267 | 265 | ||
| 266 | |||
| 267 | /* if there is no current master make this fd it */ | ||
| 268 | mutex_lock(&dev->struct_mutex); | 268 | mutex_lock(&dev->struct_mutex); |
| 269 | if (list_empty(&dev->filelist)) | 269 | if (!priv->minor->master) { |
| 270 | priv->master = 1; | 270 | /* create a new master */ |
| 271 | priv->minor->master = drm_master_create(priv->minor); | ||
| 272 | if (!priv->minor->master) { | ||
| 273 | ret = -ENOMEM; | ||
| 274 | goto out_free; | ||
| 275 | } | ||
| 271 | 276 | ||
| 277 | priv->is_master = 1; | ||
| 278 | /* take another reference for the copy in the local file priv */ | ||
| 279 | priv->master = drm_master_get(priv->minor->master); | ||
| 280 | |||
| 281 | priv->authenticated = 1; | ||
| 282 | |||
| 283 | mutex_unlock(&dev->struct_mutex); | ||
| 284 | if (dev->driver->master_create) { | ||
| 285 | ret = dev->driver->master_create(dev, priv->master); | ||
| 286 | if (ret) { | ||
| 287 | mutex_lock(&dev->struct_mutex); | ||
| 288 | /* drop both references if this fails */ | ||
| 289 | drm_master_put(&priv->minor->master); | ||
| 290 | drm_master_put(&priv->master); | ||
| 291 | mutex_unlock(&dev->struct_mutex); | ||
| 292 | goto out_free; | ||
| 293 | } | ||
| 294 | } | ||
| 295 | } else { | ||
| 296 | /* get a reference to the master */ | ||
| 297 | priv->master = drm_master_get(priv->minor->master); | ||
| 298 | mutex_unlock(&dev->struct_mutex); | ||
| 299 | } | ||
| 300 | |||
| 301 | mutex_lock(&dev->struct_mutex); | ||
| 272 | list_add(&priv->lhead, &dev->filelist); | 302 | list_add(&priv->lhead, &dev->filelist); |
| 273 | mutex_unlock(&dev->struct_mutex); | 303 | mutex_unlock(&dev->struct_mutex); |
| 274 | 304 | ||
| @@ -314,6 +344,74 @@ int drm_fasync(int fd, struct file *filp, int on) | |||
| 314 | } | 344 | } |
| 315 | EXPORT_SYMBOL(drm_fasync); | 345 | EXPORT_SYMBOL(drm_fasync); |
| 316 | 346 | ||
| 347 | /* | ||
| 348 | * Reclaim locked buffers; note that this may be a bad idea if the current | ||
| 349 | * context doesn't have the hw lock... | ||
| 350 | */ | ||
| 351 | static void drm_reclaim_locked_buffers(struct drm_device *dev, struct file *f) | ||
| 352 | { | ||
| 353 | struct drm_file *file_priv = f->private_data; | ||
| 354 | |||
| 355 | if (drm_i_have_hw_lock(dev, file_priv)) { | ||
| 356 | dev->driver->reclaim_buffers_locked(dev, file_priv); | ||
| 357 | } else { | ||
| 358 | unsigned long _end = jiffies + 3 * DRM_HZ; | ||
| 359 | int locked = 0; | ||
| 360 | |||
| 361 | drm_idlelock_take(&file_priv->master->lock); | ||
| 362 | |||
| 363 | /* | ||
| 364 | * Wait for a while. | ||
| 365 | */ | ||
| 366 | do { | ||
| 367 | spin_lock_bh(&file_priv->master->lock.spinlock); | ||
| 368 | locked = file_priv->master->lock.idle_has_lock; | ||
| 369 | spin_unlock_bh(&file_priv->master->lock.spinlock); | ||
| 370 | if (locked) | ||
| 371 | break; | ||
| 372 | schedule(); | ||
| 373 | } while (!time_after_eq(jiffies, _end)); | ||
| 374 | |||
| 375 | if (!locked) { | ||
| 376 | DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" | ||
| 377 | "\tdriver to use reclaim_buffers_idlelocked() instead.\n" | ||
| 378 | "\tI will go on reclaiming the buffers anyway.\n"); | ||
| 379 | } | ||
| 380 | |||
| 381 | dev->driver->reclaim_buffers_locked(dev, file_priv); | ||
| 382 | drm_idlelock_release(&file_priv->master->lock); | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | static void drm_master_release(struct drm_device *dev, struct file *filp) | ||
| 387 | { | ||
| 388 | struct drm_file *file_priv = filp->private_data; | ||
| 389 | |||
| 390 | if (dev->driver->reclaim_buffers_locked && | ||
| 391 | file_priv->master->lock.hw_lock) | ||
| 392 | drm_reclaim_locked_buffers(dev, filp); | ||
| 393 | |||
| 394 | if (dev->driver->reclaim_buffers_idlelocked && | ||
| 395 | file_priv->master->lock.hw_lock) { | ||
| 396 | drm_idlelock_take(&file_priv->master->lock); | ||
| 397 | dev->driver->reclaim_buffers_idlelocked(dev, file_priv); | ||
| 398 | drm_idlelock_release(&file_priv->master->lock); | ||
| 399 | } | ||
| 400 | |||
| 401 | |||
| 402 | if (drm_i_have_hw_lock(dev, file_priv)) { | ||
| 403 | DRM_DEBUG("File %p released, freeing lock for context %d\n", | ||
| 404 | filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); | ||
| 405 | drm_lock_free(&file_priv->master->lock, | ||
| 406 | _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); | ||
| 407 | } | ||
| 408 | |||
| 409 | if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && | ||
| 410 | !dev->driver->reclaim_buffers_locked) { | ||
| 411 | dev->driver->reclaim_buffers(dev, file_priv); | ||
| 412 | } | ||
| 413 | } | ||
| 414 | |||
| 317 | /** | 415 | /** |
| 318 | * Release file. | 416 | * Release file. |
| 319 | * | 417 | * |
| @@ -348,60 +446,9 @@ int drm_release(struct inode *inode, struct file *filp) | |||
| 348 | (long)old_encode_dev(file_priv->minor->device), | 446 | (long)old_encode_dev(file_priv->minor->device), |
| 349 | dev->open_count); | 447 | dev->open_count); |
| 350 | 448 | ||
| 351 | if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) { | 449 | /* if the master has gone away we can't do anything with the lock */ |
| 352 | if (drm_i_have_hw_lock(dev, file_priv)) { | 450 | if (file_priv->minor->master) |
| 353 | dev->driver->reclaim_buffers_locked(dev, file_priv); | 451 | drm_master_release(dev, filp); |
| 354 | } else { | ||
| 355 | unsigned long endtime = jiffies + 3 * DRM_HZ; | ||
| 356 | int locked = 0; | ||
| 357 | |||
| 358 | drm_idlelock_take(&dev->lock); | ||
| 359 | |||
| 360 | /* | ||
| 361 | * Wait for a while. | ||
| 362 | */ | ||
| 363 | |||
| 364 | do{ | ||
| 365 | spin_lock_bh(&dev->lock.spinlock); | ||
| 366 | locked = dev->lock.idle_has_lock; | ||
| 367 | spin_unlock_bh(&dev->lock.spinlock); | ||
| 368 | if (locked) | ||
| 369 | break; | ||
| 370 | schedule(); | ||
| 371 | } while (!time_after_eq(jiffies, endtime)); | ||
| 372 | |||
| 373 | if (!locked) { | ||
| 374 | DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" | ||
| 375 | "\tdriver to use reclaim_buffers_idlelocked() instead.\n" | ||
| 376 | "\tI will go on reclaiming the buffers anyway.\n"); | ||
| 377 | } | ||
| 378 | |||
| 379 | dev->driver->reclaim_buffers_locked(dev, file_priv); | ||
| 380 | drm_idlelock_release(&dev->lock); | ||
| 381 | } | ||
| 382 | } | ||
| 383 | |||
| 384 | if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) { | ||
| 385 | |||
| 386 | drm_idlelock_take(&dev->lock); | ||
| 387 | dev->driver->reclaim_buffers_idlelocked(dev, file_priv); | ||
| 388 | drm_idlelock_release(&dev->lock); | ||
| 389 | |||
| 390 | } | ||
| 391 | |||
| 392 | if (drm_i_have_hw_lock(dev, file_priv)) { | ||
| 393 | DRM_DEBUG("File %p released, freeing lock for context %d\n", | ||
| 394 | filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); | ||
| 395 | |||
| 396 | drm_lock_free(&dev->lock, | ||
| 397 | _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); | ||
| 398 | } | ||
| 399 | |||
| 400 | |||
| 401 | if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && | ||
| 402 | !dev->driver->reclaim_buffers_locked) { | ||
| 403 | dev->driver->reclaim_buffers(dev, file_priv); | ||
| 404 | } | ||
| 405 | 452 | ||
| 406 | if (dev->driver->driver_features & DRIVER_GEM) | 453 | if (dev->driver->driver_features & DRIVER_GEM) |
| 407 | drm_gem_release(dev, file_priv); | 454 | drm_gem_release(dev, file_priv); |
| @@ -428,12 +475,24 @@ int drm_release(struct inode *inode, struct file *filp) | |||
| 428 | mutex_unlock(&dev->ctxlist_mutex); | 475 | mutex_unlock(&dev->ctxlist_mutex); |
| 429 | 476 | ||
| 430 | mutex_lock(&dev->struct_mutex); | 477 | mutex_lock(&dev->struct_mutex); |
| 431 | if (file_priv->remove_auth_on_close == 1) { | 478 | |
| 479 | if (file_priv->is_master) { | ||
| 432 | struct drm_file *temp; | 480 | struct drm_file *temp; |
| 481 | list_for_each_entry(temp, &dev->filelist, lhead) { | ||
| 482 | if ((temp->master == file_priv->master) && | ||
| 483 | (temp != file_priv)) | ||
| 484 | temp->authenticated = 0; | ||
| 485 | } | ||
| 433 | 486 | ||
| 434 | list_for_each_entry(temp, &dev->filelist, lhead) | 487 | if (file_priv->minor->master == file_priv->master) { |
| 435 | temp->authenticated = 0; | 488 | /* drop the reference held my the minor */ |
| 489 | drm_master_put(&file_priv->minor->master); | ||
| 490 | } | ||
| 436 | } | 491 | } |
| 492 | |||
| 493 | /* drop the reference held my the file priv */ | ||
| 494 | drm_master_put(&file_priv->master); | ||
| 495 | file_priv->is_master = 0; | ||
| 437 | list_del(&file_priv->lhead); | 496 | list_del(&file_priv->lhead); |
| 438 | mutex_unlock(&dev->struct_mutex); | 497 | mutex_unlock(&dev->struct_mutex); |
| 439 | 498 | ||
| @@ -448,9 +507,9 @@ int drm_release(struct inode *inode, struct file *filp) | |||
| 448 | atomic_inc(&dev->counts[_DRM_STAT_CLOSES]); | 507 | atomic_inc(&dev->counts[_DRM_STAT_CLOSES]); |
| 449 | spin_lock(&dev->count_lock); | 508 | spin_lock(&dev->count_lock); |
| 450 | if (!--dev->open_count) { | 509 | if (!--dev->open_count) { |
| 451 | if (atomic_read(&dev->ioctl_count) || dev->blocked) { | 510 | if (atomic_read(&dev->ioctl_count)) { |
| 452 | DRM_ERROR("Device busy: %d %d\n", | 511 | DRM_ERROR("Device busy: %d\n", |
| 453 | atomic_read(&dev->ioctl_count), dev->blocked); | 512 | atomic_read(&dev->ioctl_count)); |
| 454 | spin_unlock(&dev->count_lock); | 513 | spin_unlock(&dev->count_lock); |
| 455 | unlock_kernel(); | 514 | unlock_kernel(); |
| 456 | return -EBUSY; | 515 | return -EBUSY; |
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index ccd1afdede02..9da581452874 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c | |||
| @@ -64,6 +64,13 @@ | |||
| 64 | * up at a later date, and as our interface with shmfs for memory allocation. | 64 | * up at a later date, and as our interface with shmfs for memory allocation. |
| 65 | */ | 65 | */ |
| 66 | 66 | ||
| 67 | /* | ||
| 68 | * We make up offsets for buffer objects so we can recognize them at | ||
| 69 | * mmap time. | ||
| 70 | */ | ||
| 71 | #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1) | ||
| 72 | #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16) | ||
| 73 | |||
| 67 | /** | 74 | /** |
| 68 | * Initialize the GEM device fields | 75 | * Initialize the GEM device fields |
| 69 | */ | 76 | */ |
| @@ -71,6 +78,8 @@ | |||
| 71 | int | 78 | int |
| 72 | drm_gem_init(struct drm_device *dev) | 79 | drm_gem_init(struct drm_device *dev) |
| 73 | { | 80 | { |
| 81 | struct drm_gem_mm *mm; | ||
| 82 | |||
| 74 | spin_lock_init(&dev->object_name_lock); | 83 | spin_lock_init(&dev->object_name_lock); |
| 75 | idr_init(&dev->object_name_idr); | 84 | idr_init(&dev->object_name_idr); |
| 76 | atomic_set(&dev->object_count, 0); | 85 | atomic_set(&dev->object_count, 0); |
| @@ -79,9 +88,41 @@ drm_gem_init(struct drm_device *dev) | |||
| 79 | atomic_set(&dev->pin_memory, 0); | 88 | atomic_set(&dev->pin_memory, 0); |
| 80 | atomic_set(&dev->gtt_count, 0); | 89 | atomic_set(&dev->gtt_count, 0); |
| 81 | atomic_set(&dev->gtt_memory, 0); | 90 | atomic_set(&dev->gtt_memory, 0); |
| 91 | |||
| 92 | mm = drm_calloc(1, sizeof(struct drm_gem_mm), DRM_MEM_MM); | ||
| 93 | if (!mm) { | ||
| 94 | DRM_ERROR("out of memory\n"); | ||
| 95 | return -ENOMEM; | ||
| 96 | } | ||
| 97 | |||
| 98 | dev->mm_private = mm; | ||
| 99 | |||
| 100 | if (drm_ht_create(&mm->offset_hash, 19)) { | ||
| 101 | drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM); | ||
| 102 | return -ENOMEM; | ||
| 103 | } | ||
| 104 | |||
| 105 | if (drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START, | ||
| 106 | DRM_FILE_PAGE_OFFSET_SIZE)) { | ||
| 107 | drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM); | ||
| 108 | drm_ht_remove(&mm->offset_hash); | ||
| 109 | return -ENOMEM; | ||
| 110 | } | ||
| 111 | |||
| 82 | return 0; | 112 | return 0; |
| 83 | } | 113 | } |
| 84 | 114 | ||
| 115 | void | ||
| 116 | drm_gem_destroy(struct drm_device *dev) | ||
| 117 | { | ||
| 118 | struct drm_gem_mm *mm = dev->mm_private; | ||
| 119 | |||
| 120 | drm_mm_takedown(&mm->offset_manager); | ||
| 121 | drm_ht_remove(&mm->offset_hash); | ||
| 122 | drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM); | ||
| 123 | dev->mm_private = NULL; | ||
| 124 | } | ||
| 125 | |||
| 85 | /** | 126 | /** |
| 86 | * Allocate a GEM object of the specified size with shmfs backing store | 127 | * Allocate a GEM object of the specified size with shmfs backing store |
| 87 | */ | 128 | */ |
| @@ -419,3 +460,73 @@ drm_gem_object_handle_free(struct kref *kref) | |||
| 419 | } | 460 | } |
| 420 | EXPORT_SYMBOL(drm_gem_object_handle_free); | 461 | EXPORT_SYMBOL(drm_gem_object_handle_free); |
| 421 | 462 | ||
| 463 | /** | ||
| 464 | * drm_gem_mmap - memory map routine for GEM objects | ||
| 465 | * @filp: DRM file pointer | ||
| 466 | * @vma: VMA for the area to be mapped | ||
| 467 | * | ||
| 468 | * If a driver supports GEM object mapping, mmap calls on the DRM file | ||
| 469 | * descriptor will end up here. | ||
| 470 | * | ||
| 471 | * If we find the object based on the offset passed in (vma->vm_pgoff will | ||
| 472 | * contain the fake offset we created when the GTT map ioctl was called on | ||
| 473 | * the object), we set up the driver fault handler so that any accesses | ||
| 474 | * to the object can be trapped, to perform migration, GTT binding, surface | ||
| 475 | * register allocation, or performance monitoring. | ||
| 476 | */ | ||
| 477 | int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) | ||
| 478 | { | ||
| 479 | struct drm_file *priv = filp->private_data; | ||
| 480 | struct drm_device *dev = priv->minor->dev; | ||
| 481 | struct drm_gem_mm *mm = dev->mm_private; | ||
| 482 | struct drm_map *map = NULL; | ||
| 483 | struct drm_gem_object *obj; | ||
| 484 | struct drm_hash_item *hash; | ||
| 485 | unsigned long prot; | ||
| 486 | int ret = 0; | ||
| 487 | |||
| 488 | mutex_lock(&dev->struct_mutex); | ||
| 489 | |||
| 490 | if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) { | ||
| 491 | mutex_unlock(&dev->struct_mutex); | ||
| 492 | return drm_mmap(filp, vma); | ||
| 493 | } | ||
| 494 | |||
| 495 | map = drm_hash_entry(hash, struct drm_map_list, hash)->map; | ||
| 496 | if (!map || | ||
| 497 | ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) { | ||
| 498 | ret = -EPERM; | ||
| 499 | goto out_unlock; | ||
| 500 | } | ||
| 501 | |||
| 502 | /* Check for valid size. */ | ||
| 503 | if (map->size < vma->vm_end - vma->vm_start) { | ||
| 504 | ret = -EINVAL; | ||
| 505 | goto out_unlock; | ||
| 506 | } | ||
| 507 | |||
| 508 | obj = map->handle; | ||
| 509 | if (!obj->dev->driver->gem_vm_ops) { | ||
| 510 | ret = -EINVAL; | ||
| 511 | goto out_unlock; | ||
| 512 | } | ||
| 513 | |||
| 514 | vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND; | ||
| 515 | vma->vm_ops = obj->dev->driver->gem_vm_ops; | ||
| 516 | vma->vm_private_data = map->handle; | ||
| 517 | /* FIXME: use pgprot_writecombine when available */ | ||
| 518 | prot = pgprot_val(vma->vm_page_prot); | ||
| 519 | #ifdef CONFIG_X86 | ||
| 520 | prot |= _PAGE_CACHE_WC; | ||
| 521 | #endif | ||
| 522 | vma->vm_page_prot = __pgprot(prot); | ||
| 523 | |||
| 524 | vma->vm_file = filp; /* Needed for drm_vm_open() */ | ||
| 525 | drm_vm_open_locked(vma); | ||
| 526 | |||
| 527 | out_unlock: | ||
| 528 | mutex_unlock(&dev->struct_mutex); | ||
| 529 | |||
| 530 | return ret; | ||
| 531 | } | ||
| 532 | EXPORT_SYMBOL(drm_gem_mmap); | ||
diff --git a/drivers/gpu/drm/drm_hashtab.c b/drivers/gpu/drm/drm_hashtab.c index 33160673a7b7..af539f7d87dd 100644 --- a/drivers/gpu/drm/drm_hashtab.c +++ b/drivers/gpu/drm/drm_hashtab.c | |||
| @@ -127,6 +127,7 @@ int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item) | |||
| 127 | } | 127 | } |
| 128 | return 0; | 128 | return 0; |
| 129 | } | 129 | } |
| 130 | EXPORT_SYMBOL(drm_ht_insert_item); | ||
| 130 | 131 | ||
| 131 | /* | 132 | /* |
| 132 | * Just insert an item and return any "bits" bit key that hasn't been | 133 | * Just insert an item and return any "bits" bit key that hasn't been |
| @@ -188,6 +189,7 @@ int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item) | |||
| 188 | ht->fill--; | 189 | ht->fill--; |
| 189 | return 0; | 190 | return 0; |
| 190 | } | 191 | } |
| 192 | EXPORT_SYMBOL(drm_ht_remove_item); | ||
| 191 | 193 | ||
| 192 | void drm_ht_remove(struct drm_open_hash *ht) | 194 | void drm_ht_remove(struct drm_open_hash *ht) |
| 193 | { | 195 | { |
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 16829fb3089d..1fad76289e66 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c | |||
| @@ -53,12 +53,13 @@ int drm_getunique(struct drm_device *dev, void *data, | |||
| 53 | struct drm_file *file_priv) | 53 | struct drm_file *file_priv) |
| 54 | { | 54 | { |
| 55 | struct drm_unique *u = data; | 55 | struct drm_unique *u = data; |
| 56 | struct drm_master *master = file_priv->master; | ||
| 56 | 57 | ||
| 57 | if (u->unique_len >= dev->unique_len) { | 58 | if (u->unique_len >= master->unique_len) { |
| 58 | if (copy_to_user(u->unique, dev->unique, dev->unique_len)) | 59 | if (copy_to_user(u->unique, master->unique, master->unique_len)) |
| 59 | return -EFAULT; | 60 | return -EFAULT; |
| 60 | } | 61 | } |
| 61 | u->unique_len = dev->unique_len; | 62 | u->unique_len = master->unique_len; |
| 62 | 63 | ||
| 63 | return 0; | 64 | return 0; |
| 64 | } | 65 | } |
| @@ -81,36 +82,38 @@ int drm_setunique(struct drm_device *dev, void *data, | |||
| 81 | struct drm_file *file_priv) | 82 | struct drm_file *file_priv) |
| 82 | { | 83 | { |
| 83 | struct drm_unique *u = data; | 84 | struct drm_unique *u = data; |
| 85 | struct drm_master *master = file_priv->master; | ||
| 84 | int domain, bus, slot, func, ret; | 86 | int domain, bus, slot, func, ret; |
| 85 | 87 | ||
| 86 | if (dev->unique_len || dev->unique) | 88 | if (master->unique_len || master->unique) |
| 87 | return -EBUSY; | 89 | return -EBUSY; |
| 88 | 90 | ||
| 89 | if (!u->unique_len || u->unique_len > 1024) | 91 | if (!u->unique_len || u->unique_len > 1024) |
| 90 | return -EINVAL; | 92 | return -EINVAL; |
| 91 | 93 | ||
| 92 | dev->unique_len = u->unique_len; | 94 | master->unique_len = u->unique_len; |
| 93 | dev->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER); | 95 | master->unique_size = u->unique_len + 1; |
| 94 | if (!dev->unique) | 96 | master->unique = drm_alloc(master->unique_size, DRM_MEM_DRIVER); |
| 97 | if (!master->unique) | ||
| 95 | return -ENOMEM; | 98 | return -ENOMEM; |
| 96 | if (copy_from_user(dev->unique, u->unique, dev->unique_len)) | 99 | if (copy_from_user(master->unique, u->unique, master->unique_len)) |
| 97 | return -EFAULT; | 100 | return -EFAULT; |
| 98 | 101 | ||
| 99 | dev->unique[dev->unique_len] = '\0'; | 102 | master->unique[master->unique_len] = '\0'; |
| 100 | 103 | ||
| 101 | dev->devname = | 104 | dev->devname = |
| 102 | drm_alloc(strlen(dev->driver->pci_driver.name) + | 105 | drm_alloc(strlen(dev->driver->pci_driver.name) + |
| 103 | strlen(dev->unique) + 2, DRM_MEM_DRIVER); | 106 | strlen(master->unique) + 2, DRM_MEM_DRIVER); |
| 104 | if (!dev->devname) | 107 | if (!dev->devname) |
| 105 | return -ENOMEM; | 108 | return -ENOMEM; |
| 106 | 109 | ||
| 107 | sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, | 110 | sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, |
| 108 | dev->unique); | 111 | master->unique); |
| 109 | 112 | ||
| 110 | /* Return error if the busid submitted doesn't match the device's actual | 113 | /* Return error if the busid submitted doesn't match the device's actual |
| 111 | * busid. | 114 | * busid. |
| 112 | */ | 115 | */ |
| 113 | ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func); | 116 | ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func); |
| 114 | if (ret != 3) | 117 | if (ret != 3) |
| 115 | return -EINVAL; | 118 | return -EINVAL; |
| 116 | domain = bus >> 8; | 119 | domain = bus >> 8; |
| @@ -125,34 +128,38 @@ int drm_setunique(struct drm_device *dev, void *data, | |||
| 125 | return 0; | 128 | return 0; |
| 126 | } | 129 | } |
| 127 | 130 | ||
| 128 | static int drm_set_busid(struct drm_device * dev) | 131 | static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) |
| 129 | { | 132 | { |
| 133 | struct drm_master *master = file_priv->master; | ||
| 130 | int len; | 134 | int len; |
| 131 | 135 | ||
| 132 | if (dev->unique != NULL) | 136 | if (master->unique != NULL) |
| 133 | return 0; | 137 | return -EBUSY; |
| 134 | 138 | ||
| 135 | dev->unique_len = 40; | 139 | master->unique_len = 40; |
| 136 | dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER); | 140 | master->unique_size = master->unique_len; |
| 137 | if (dev->unique == NULL) | 141 | master->unique = drm_alloc(master->unique_size, DRM_MEM_DRIVER); |
| 142 | if (master->unique == NULL) | ||
| 138 | return -ENOMEM; | 143 | return -ENOMEM; |
| 139 | 144 | ||
| 140 | len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", | 145 | len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%d", |
| 141 | drm_get_pci_domain(dev), dev->pdev->bus->number, | 146 | drm_get_pci_domain(dev), |
| 147 | dev->pdev->bus->number, | ||
| 142 | PCI_SLOT(dev->pdev->devfn), | 148 | PCI_SLOT(dev->pdev->devfn), |
| 143 | PCI_FUNC(dev->pdev->devfn)); | 149 | PCI_FUNC(dev->pdev->devfn)); |
| 144 | 150 | if (len >= master->unique_len) | |
| 145 | if (len > dev->unique_len) | 151 | DRM_ERROR("buffer overflow"); |
| 146 | DRM_ERROR("Unique buffer overflowed\n"); | 152 | else |
| 153 | master->unique_len = len; | ||
| 147 | 154 | ||
| 148 | dev->devname = | 155 | dev->devname = |
| 149 | drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len + | 156 | drm_alloc(strlen(dev->driver->pci_driver.name) + master->unique_len + |
| 150 | 2, DRM_MEM_DRIVER); | 157 | 2, DRM_MEM_DRIVER); |
| 151 | if (dev->devname == NULL) | 158 | if (dev->devname == NULL) |
| 152 | return -ENOMEM; | 159 | return -ENOMEM; |
| 153 | 160 | ||
| 154 | sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, | 161 | sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, |
| 155 | dev->unique); | 162 | master->unique); |
| 156 | 163 | ||
| 157 | return 0; | 164 | return 0; |
| 158 | } | 165 | } |
| @@ -276,7 +283,7 @@ int drm_getstats(struct drm_device *dev, void *data, | |||
| 276 | for (i = 0; i < dev->counters; i++) { | 283 | for (i = 0; i < dev->counters; i++) { |
| 277 | if (dev->types[i] == _DRM_STAT_LOCK) | 284 | if (dev->types[i] == _DRM_STAT_LOCK) |
| 278 | stats->data[i].value = | 285 | stats->data[i].value = |
| 279 | (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0); | 286 | (file_priv->master->lock.hw_lock ? file_priv->master->lock.hw_lock->lock : 0); |
| 280 | else | 287 | else |
| 281 | stats->data[i].value = atomic_read(&dev->counts[i]); | 288 | stats->data[i].value = atomic_read(&dev->counts[i]); |
| 282 | stats->data[i].type = dev->types[i]; | 289 | stats->data[i].type = dev->types[i]; |
| @@ -318,7 +325,7 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri | |||
| 318 | /* | 325 | /* |
| 319 | * Version 1.1 includes tying of DRM to specific device | 326 | * Version 1.1 includes tying of DRM to specific device |
| 320 | */ | 327 | */ |
| 321 | drm_set_busid(dev); | 328 | drm_set_busid(dev, file_priv); |
| 322 | } | 329 | } |
| 323 | } | 330 | } |
| 324 | 331 | ||
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 1e787f894b3c..724e505873cf 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
| @@ -116,6 +116,9 @@ void drm_vblank_cleanup(struct drm_device *dev) | |||
| 116 | dev->num_crtcs, DRM_MEM_DRIVER); | 116 | dev->num_crtcs, DRM_MEM_DRIVER); |
| 117 | drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, | 117 | drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, |
| 118 | DRM_MEM_DRIVER); | 118 | DRM_MEM_DRIVER); |
| 119 | drm_free(dev->last_vblank_wait, | ||
| 120 | sizeof(*dev->last_vblank_wait) * dev->num_crtcs, | ||
| 121 | DRM_MEM_DRIVER); | ||
| 119 | drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) * | 122 | drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) * |
| 120 | dev->num_crtcs, DRM_MEM_DRIVER); | 123 | dev->num_crtcs, DRM_MEM_DRIVER); |
| 121 | 124 | ||
| @@ -161,6 +164,11 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) | |||
| 161 | if (!dev->last_vblank) | 164 | if (!dev->last_vblank) |
| 162 | goto err; | 165 | goto err; |
| 163 | 166 | ||
| 167 | dev->last_vblank_wait = drm_calloc(num_crtcs, sizeof(u32), | ||
| 168 | DRM_MEM_DRIVER); | ||
| 169 | if (!dev->last_vblank_wait) | ||
| 170 | goto err; | ||
| 171 | |||
| 164 | dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int), | 172 | dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int), |
| 165 | DRM_MEM_DRIVER); | 173 | DRM_MEM_DRIVER); |
| 166 | if (!dev->vblank_inmodeset) | 174 | if (!dev->vblank_inmodeset) |
| @@ -305,6 +313,8 @@ int drm_control(struct drm_device *dev, void *data, | |||
| 305 | case DRM_INST_HANDLER: | 313 | case DRM_INST_HANDLER: |
| 306 | if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) | 314 | if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) |
| 307 | return 0; | 315 | return 0; |
| 316 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
| 317 | return 0; | ||
| 308 | if (dev->if_version < DRM_IF_VERSION(1, 2) && | 318 | if (dev->if_version < DRM_IF_VERSION(1, 2) && |
| 309 | ctl->irq != dev->pdev->irq) | 319 | ctl->irq != dev->pdev->irq) |
| 310 | return -EINVAL; | 320 | return -EINVAL; |
| @@ -312,6 +322,8 @@ int drm_control(struct drm_device *dev, void *data, | |||
| 312 | case DRM_UNINST_HANDLER: | 322 | case DRM_UNINST_HANDLER: |
| 313 | if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) | 323 | if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) |
| 314 | return 0; | 324 | return 0; |
| 325 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
| 326 | return 0; | ||
| 315 | return drm_irq_uninstall(dev); | 327 | return drm_irq_uninstall(dev); |
| 316 | default: | 328 | default: |
| 317 | return -EINVAL; | 329 | return -EINVAL; |
| @@ -427,6 +439,45 @@ void drm_vblank_put(struct drm_device *dev, int crtc) | |||
| 427 | EXPORT_SYMBOL(drm_vblank_put); | 439 | EXPORT_SYMBOL(drm_vblank_put); |
| 428 | 440 | ||
| 429 | /** | 441 | /** |
| 442 | * drm_vblank_pre_modeset - account for vblanks across mode sets | ||
| 443 | * @dev: DRM device | ||
| 444 | * @crtc: CRTC in question | ||
| 445 | * @post: post or pre mode set? | ||
| 446 | * | ||
| 447 | * Account for vblank events across mode setting events, which will likely | ||
| 448 | * reset the hardware frame counter. | ||
| 449 | */ | ||
| 450 | void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) | ||
| 451 | { | ||
| 452 | /* | ||
| 453 | * To avoid all the problems that might happen if interrupts | ||
| 454 | * were enabled/disabled around or between these calls, we just | ||
| 455 | * have the kernel take a reference on the CRTC (just once though | ||
| 456 | * to avoid corrupting the count if multiple, mismatch calls occur), | ||
| 457 | * so that interrupts remain enabled in the interim. | ||
| 458 | */ | ||
| 459 | if (!dev->vblank_inmodeset[crtc]) { | ||
| 460 | dev->vblank_inmodeset[crtc] = 1; | ||
| 461 | drm_vblank_get(dev, crtc); | ||
| 462 | } | ||
| 463 | } | ||
| 464 | EXPORT_SYMBOL(drm_vblank_pre_modeset); | ||
| 465 | |||
| 466 | void drm_vblank_post_modeset(struct drm_device *dev, int crtc) | ||
| 467 | { | ||
| 468 | unsigned long irqflags; | ||
| 469 | |||
| 470 | if (dev->vblank_inmodeset[crtc]) { | ||
| 471 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
| 472 | dev->vblank_disable_allowed = 1; | ||
| 473 | dev->vblank_inmodeset[crtc] = 0; | ||
| 474 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
| 475 | drm_vblank_put(dev, crtc); | ||
| 476 | } | ||
| 477 | } | ||
| 478 | EXPORT_SYMBOL(drm_vblank_post_modeset); | ||
| 479 | |||
| 480 | /** | ||
| 430 | * drm_modeset_ctl - handle vblank event counter changes across mode switch | 481 | * drm_modeset_ctl - handle vblank event counter changes across mode switch |
| 431 | * @DRM_IOCTL_ARGS: standard ioctl arguments | 482 | * @DRM_IOCTL_ARGS: standard ioctl arguments |
| 432 | * | 483 | * |
| @@ -441,7 +492,6 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, | |||
| 441 | struct drm_file *file_priv) | 492 | struct drm_file *file_priv) |
| 442 | { | 493 | { |
| 443 | struct drm_modeset_ctl *modeset = data; | 494 | struct drm_modeset_ctl *modeset = data; |
| 444 | unsigned long irqflags; | ||
| 445 | int crtc, ret = 0; | 495 | int crtc, ret = 0; |
| 446 | 496 | ||
| 447 | /* If drm_vblank_init() hasn't been called yet, just no-op */ | 497 | /* If drm_vblank_init() hasn't been called yet, just no-op */ |
| @@ -454,28 +504,12 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, | |||
| 454 | goto out; | 504 | goto out; |
| 455 | } | 505 | } |
| 456 | 506 | ||
| 457 | /* | ||
| 458 | * To avoid all the problems that might happen if interrupts | ||
| 459 | * were enabled/disabled around or between these calls, we just | ||
| 460 | * have the kernel take a reference on the CRTC (just once though | ||
| 461 | * to avoid corrupting the count if multiple, mismatch calls occur), | ||
| 462 | * so that interrupts remain enabled in the interim. | ||
| 463 | */ | ||
| 464 | switch (modeset->cmd) { | 507 | switch (modeset->cmd) { |
| 465 | case _DRM_PRE_MODESET: | 508 | case _DRM_PRE_MODESET: |
| 466 | if (!dev->vblank_inmodeset[crtc]) { | 509 | drm_vblank_pre_modeset(dev, crtc); |
| 467 | dev->vblank_inmodeset[crtc] = 1; | ||
| 468 | drm_vblank_get(dev, crtc); | ||
| 469 | } | ||
| 470 | break; | 510 | break; |
| 471 | case _DRM_POST_MODESET: | 511 | case _DRM_POST_MODESET: |
| 472 | if (dev->vblank_inmodeset[crtc]) { | 512 | drm_vblank_post_modeset(dev, crtc); |
| 473 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
| 474 | dev->vblank_disable_allowed = 1; | ||
| 475 | dev->vblank_inmodeset[crtc] = 0; | ||
| 476 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
| 477 | drm_vblank_put(dev, crtc); | ||
| 478 | } | ||
| 479 | break; | 513 | break; |
| 480 | default: | 514 | default: |
| 481 | ret = -EINVAL; | 515 | ret = -EINVAL; |
| @@ -616,6 +650,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
| 616 | } else { | 650 | } else { |
| 617 | DRM_DEBUG("waiting on vblank count %d, crtc %d\n", | 651 | DRM_DEBUG("waiting on vblank count %d, crtc %d\n", |
| 618 | vblwait->request.sequence, crtc); | 652 | vblwait->request.sequence, crtc); |
| 653 | dev->last_vblank_wait[crtc] = vblwait->request.sequence; | ||
| 619 | DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, | 654 | DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, |
| 620 | ((drm_vblank_count(dev, crtc) | 655 | ((drm_vblank_count(dev, crtc) |
| 621 | - vblwait->request.sequence) <= (1 << 23))); | 656 | - vblwait->request.sequence) <= (1 << 23))); |
diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c index 1cfa72031f8f..46e7b28f0707 100644 --- a/drivers/gpu/drm/drm_lock.c +++ b/drivers/gpu/drm/drm_lock.c | |||
| @@ -52,6 +52,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
| 52 | { | 52 | { |
| 53 | DECLARE_WAITQUEUE(entry, current); | 53 | DECLARE_WAITQUEUE(entry, current); |
| 54 | struct drm_lock *lock = data; | 54 | struct drm_lock *lock = data; |
| 55 | struct drm_master *master = file_priv->master; | ||
| 55 | int ret = 0; | 56 | int ret = 0; |
| 56 | 57 | ||
| 57 | ++file_priv->lock_count; | 58 | ++file_priv->lock_count; |
| @@ -64,26 +65,27 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
| 64 | 65 | ||
| 65 | DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", | 66 | DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", |
| 66 | lock->context, task_pid_nr(current), | 67 | lock->context, task_pid_nr(current), |
| 67 | dev->lock.hw_lock->lock, lock->flags); | 68 | master->lock.hw_lock->lock, lock->flags); |
| 68 | 69 | ||
| 69 | if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE)) | 70 | if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE)) |
| 70 | if (lock->context < 0) | 71 | if (lock->context < 0) |
| 71 | return -EINVAL; | 72 | return -EINVAL; |
| 72 | 73 | ||
| 73 | add_wait_queue(&dev->lock.lock_queue, &entry); | 74 | add_wait_queue(&master->lock.lock_queue, &entry); |
| 74 | spin_lock_bh(&dev->lock.spinlock); | 75 | spin_lock_bh(&master->lock.spinlock); |
| 75 | dev->lock.user_waiters++; | 76 | master->lock.user_waiters++; |
| 76 | spin_unlock_bh(&dev->lock.spinlock); | 77 | spin_unlock_bh(&master->lock.spinlock); |
| 78 | |||
| 77 | for (;;) { | 79 | for (;;) { |
| 78 | __set_current_state(TASK_INTERRUPTIBLE); | 80 | __set_current_state(TASK_INTERRUPTIBLE); |
| 79 | if (!dev->lock.hw_lock) { | 81 | if (!master->lock.hw_lock) { |
| 80 | /* Device has been unregistered */ | 82 | /* Device has been unregistered */ |
| 81 | ret = -EINTR; | 83 | ret = -EINTR; |
| 82 | break; | 84 | break; |
| 83 | } | 85 | } |
| 84 | if (drm_lock_take(&dev->lock, lock->context)) { | 86 | if (drm_lock_take(&master->lock, lock->context)) { |
| 85 | dev->lock.file_priv = file_priv; | 87 | master->lock.file_priv = file_priv; |
| 86 | dev->lock.lock_time = jiffies; | 88 | master->lock.lock_time = jiffies; |
| 87 | atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); | 89 | atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); |
| 88 | break; /* Got lock */ | 90 | break; /* Got lock */ |
| 89 | } | 91 | } |
| @@ -95,11 +97,11 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
| 95 | break; | 97 | break; |
| 96 | } | 98 | } |
| 97 | } | 99 | } |
| 98 | spin_lock_bh(&dev->lock.spinlock); | 100 | spin_lock_bh(&master->lock.spinlock); |
| 99 | dev->lock.user_waiters--; | 101 | master->lock.user_waiters--; |
| 100 | spin_unlock_bh(&dev->lock.spinlock); | 102 | spin_unlock_bh(&master->lock.spinlock); |
| 101 | __set_current_state(TASK_RUNNING); | 103 | __set_current_state(TASK_RUNNING); |
| 102 | remove_wait_queue(&dev->lock.lock_queue, &entry); | 104 | remove_wait_queue(&master->lock.lock_queue, &entry); |
| 103 | 105 | ||
| 104 | DRM_DEBUG("%d %s\n", lock->context, | 106 | DRM_DEBUG("%d %s\n", lock->context, |
| 105 | ret ? "interrupted" : "has lock"); | 107 | ret ? "interrupted" : "has lock"); |
| @@ -108,14 +110,14 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
| 108 | /* don't set the block all signals on the master process for now | 110 | /* don't set the block all signals on the master process for now |
| 109 | * really probably not the correct answer but lets us debug xkb | 111 | * really probably not the correct answer but lets us debug xkb |
| 110 | * xserver for now */ | 112 | * xserver for now */ |
| 111 | if (!file_priv->master) { | 113 | if (!file_priv->is_master) { |
| 112 | sigemptyset(&dev->sigmask); | 114 | sigemptyset(&dev->sigmask); |
| 113 | sigaddset(&dev->sigmask, SIGSTOP); | 115 | sigaddset(&dev->sigmask, SIGSTOP); |
| 114 | sigaddset(&dev->sigmask, SIGTSTP); | 116 | sigaddset(&dev->sigmask, SIGTSTP); |
| 115 | sigaddset(&dev->sigmask, SIGTTIN); | 117 | sigaddset(&dev->sigmask, SIGTTIN); |
| 116 | sigaddset(&dev->sigmask, SIGTTOU); | 118 | sigaddset(&dev->sigmask, SIGTTOU); |
| 117 | dev->sigdata.context = lock->context; | 119 | dev->sigdata.context = lock->context; |
| 118 | dev->sigdata.lock = dev->lock.hw_lock; | 120 | dev->sigdata.lock = master->lock.hw_lock; |
| 119 | block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); | 121 | block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); |
| 120 | } | 122 | } |
| 121 | 123 | ||
| @@ -154,6 +156,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
| 154 | int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) | 156 | int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) |
| 155 | { | 157 | { |
| 156 | struct drm_lock *lock = data; | 158 | struct drm_lock *lock = data; |
| 159 | struct drm_master *master = file_priv->master; | ||
| 157 | 160 | ||
| 158 | if (lock->context == DRM_KERNEL_CONTEXT) { | 161 | if (lock->context == DRM_KERNEL_CONTEXT) { |
| 159 | DRM_ERROR("Process %d using kernel context %d\n", | 162 | DRM_ERROR("Process %d using kernel context %d\n", |
| @@ -169,7 +172,7 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) | |||
| 169 | if (dev->driver->kernel_context_switch_unlock) | 172 | if (dev->driver->kernel_context_switch_unlock) |
| 170 | dev->driver->kernel_context_switch_unlock(dev); | 173 | dev->driver->kernel_context_switch_unlock(dev); |
| 171 | else { | 174 | else { |
| 172 | if (drm_lock_free(&dev->lock,lock->context)) { | 175 | if (drm_lock_free(&master->lock, lock->context)) { |
| 173 | /* FIXME: Should really bail out here. */ | 176 | /* FIXME: Should really bail out here. */ |
| 174 | } | 177 | } |
| 175 | } | 178 | } |
| @@ -379,9 +382,10 @@ EXPORT_SYMBOL(drm_idlelock_release); | |||
| 379 | 382 | ||
| 380 | int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv) | 383 | int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv) |
| 381 | { | 384 | { |
| 382 | return (file_priv->lock_count && dev->lock.hw_lock && | 385 | struct drm_master *master = file_priv->master; |
| 383 | _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && | 386 | return (file_priv->lock_count && master->lock.hw_lock && |
| 384 | dev->lock.file_priv == file_priv); | 387 | _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) && |
| 388 | master->lock.file_priv == file_priv); | ||
| 385 | } | 389 | } |
| 386 | 390 | ||
| 387 | EXPORT_SYMBOL(drm_i_have_hw_lock); | 391 | EXPORT_SYMBOL(drm_i_have_hw_lock); |
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 217ad7dc7076..367c590ffbba 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c | |||
| @@ -296,3 +296,4 @@ void drm_mm_takedown(struct drm_mm * mm) | |||
| 296 | 296 | ||
| 297 | drm_free(entry, sizeof(*entry), DRM_MEM_MM); | 297 | drm_free(entry, sizeof(*entry), DRM_MEM_MM); |
| 298 | } | 298 | } |
| 299 | EXPORT_SYMBOL(drm_mm_takedown); | ||
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c new file mode 100644 index 000000000000..c9b80fdd4630 --- /dev/null +++ b/drivers/gpu/drm/drm_modes.c | |||
| @@ -0,0 +1,576 @@ | |||
| 1 | /* | ||
| 2 | * The list_sort function is (presumably) licensed under the GPL (see the | ||
| 3 | * top level "COPYING" file for details). | ||
| 4 | * | ||
| 5 | * The remainder of this file is: | ||
| 6 | * | ||
| 7 | * Copyright © 1997-2003 by The XFree86 Project, Inc. | ||
| 8 | * Copyright © 2007 Dave Airlie | ||
| 9 | * Copyright © 2007-2008 Intel Corporation | ||
| 10 | * Jesse Barnes <jesse.barnes@intel.com> | ||
| 11 | * | ||
| 12 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 13 | * copy of this software and associated documentation files (the "Software"), | ||
| 14 | * to deal in the Software without restriction, including without limitation | ||
| 15 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 16 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 17 | * Software is furnished to do so, subject to the following conditions: | ||
| 18 | * | ||
| 19 | * The above copyright notice and this permission notice shall be included in | ||
| 20 | * all copies or substantial portions of the Software. | ||
| 21 | * | ||
| 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 25 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
| 26 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
| 27 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
| 28 | * OTHER DEALINGS IN THE SOFTWARE. | ||
| 29 | * | ||
| 30 | * Except as contained in this notice, the name of the copyright holder(s) | ||
| 31 | * and author(s) shall not be used in advertising or otherwise to promote | ||
| 32 | * the sale, use or other dealings in this Software without prior written | ||
| 33 | * authorization from the copyright holder(s) and author(s). | ||
| 34 | */ | ||
| 35 | |||
| 36 | #include <linux/list.h> | ||
| 37 | #include "drmP.h" | ||
| 38 | #include "drm.h" | ||
| 39 | #include "drm_crtc.h" | ||
| 40 | |||
| 41 | /** | ||
| 42 | * drm_mode_debug_printmodeline - debug print a mode | ||
| 43 | * @dev: DRM device | ||
| 44 | * @mode: mode to print | ||
| 45 | * | ||
| 46 | * LOCKING: | ||
| 47 | * None. | ||
| 48 | * | ||
| 49 | * Describe @mode using DRM_DEBUG. | ||
| 50 | */ | ||
| 51 | void drm_mode_debug_printmodeline(struct drm_display_mode *mode) | ||
| 52 | { | ||
| 53 | DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", | ||
| 54 | mode->base.id, mode->name, mode->vrefresh, mode->clock, | ||
| 55 | mode->hdisplay, mode->hsync_start, | ||
| 56 | mode->hsync_end, mode->htotal, | ||
| 57 | mode->vdisplay, mode->vsync_start, | ||
| 58 | mode->vsync_end, mode->vtotal, mode->type, mode->flags); | ||
| 59 | } | ||
| 60 | EXPORT_SYMBOL(drm_mode_debug_printmodeline); | ||
| 61 | |||
| 62 | /** | ||
| 63 | * drm_mode_set_name - set the name on a mode | ||
| 64 | * @mode: name will be set in this mode | ||
| 65 | * | ||
| 66 | * LOCKING: | ||
| 67 | * None. | ||
| 68 | * | ||
| 69 | * Set the name of @mode to a standard format. | ||
| 70 | */ | ||
| 71 | void drm_mode_set_name(struct drm_display_mode *mode) | ||
| 72 | { | ||
| 73 | snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", mode->hdisplay, | ||
| 74 | mode->vdisplay); | ||
| 75 | } | ||
| 76 | EXPORT_SYMBOL(drm_mode_set_name); | ||
| 77 | |||
| 78 | /** | ||
| 79 | * drm_mode_list_concat - move modes from one list to another | ||
| 80 | * @head: source list | ||
| 81 | * @new: dst list | ||
| 82 | * | ||
| 83 | * LOCKING: | ||
| 84 | * Caller must ensure both lists are locked. | ||
| 85 | * | ||
| 86 | * Move all the modes from @head to @new. | ||
| 87 | */ | ||
| 88 | void drm_mode_list_concat(struct list_head *head, struct list_head *new) | ||
| 89 | { | ||
| 90 | |||
| 91 | struct list_head *entry, *tmp; | ||
| 92 | |||
| 93 | list_for_each_safe(entry, tmp, head) { | ||
| 94 | list_move_tail(entry, new); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | EXPORT_SYMBOL(drm_mode_list_concat); | ||
| 98 | |||
| 99 | /** | ||
| 100 | * drm_mode_width - get the width of a mode | ||
| 101 | * @mode: mode | ||
| 102 | * | ||
| 103 | * LOCKING: | ||
| 104 | * None. | ||
| 105 | * | ||
| 106 | * Return @mode's width (hdisplay) value. | ||
| 107 | * | ||
| 108 | * FIXME: is this needed? | ||
| 109 | * | ||
| 110 | * RETURNS: | ||
| 111 | * @mode->hdisplay | ||
| 112 | */ | ||
| 113 | int drm_mode_width(struct drm_display_mode *mode) | ||
| 114 | { | ||
| 115 | return mode->hdisplay; | ||
| 116 | |||
| 117 | } | ||
| 118 | EXPORT_SYMBOL(drm_mode_width); | ||
| 119 | |||
| 120 | /** | ||
| 121 | * drm_mode_height - get the height of a mode | ||
| 122 | * @mode: mode | ||
| 123 | * | ||
| 124 | * LOCKING: | ||
| 125 | * None. | ||
| 126 | * | ||
| 127 | * Return @mode's height (vdisplay) value. | ||
| 128 | * | ||
| 129 | * FIXME: is this needed? | ||
| 130 | * | ||
| 131 | * RETURNS: | ||
| 132 | * @mode->vdisplay | ||
| 133 | */ | ||
| 134 | int drm_mode_height(struct drm_display_mode *mode) | ||
| 135 | { | ||
| 136 | return mode->vdisplay; | ||
| 137 | } | ||
| 138 | EXPORT_SYMBOL(drm_mode_height); | ||
| 139 | |||
| 140 | /** | ||
| 141 | * drm_mode_vrefresh - get the vrefresh of a mode | ||
| 142 | * @mode: mode | ||
| 143 | * | ||
| 144 | * LOCKING: | ||
| 145 | * None. | ||
| 146 | * | ||
| 147 | * Return @mode's vrefresh rate or calculate it if necessary. | ||
| 148 | * | ||
| 149 | * FIXME: why is this needed? shouldn't vrefresh be set already? | ||
| 150 | * | ||
| 151 | * RETURNS: | ||
| 152 | * Vertical refresh rate of @mode x 1000. For precision reasons. | ||
| 153 | */ | ||
| 154 | int drm_mode_vrefresh(struct drm_display_mode *mode) | ||
| 155 | { | ||
| 156 | int refresh = 0; | ||
| 157 | unsigned int calc_val; | ||
| 158 | |||
| 159 | if (mode->vrefresh > 0) | ||
| 160 | refresh = mode->vrefresh; | ||
| 161 | else if (mode->htotal > 0 && mode->vtotal > 0) { | ||
| 162 | /* work out vrefresh the value will be x1000 */ | ||
| 163 | calc_val = (mode->clock * 1000); | ||
| 164 | |||
| 165 | calc_val /= mode->htotal; | ||
| 166 | calc_val *= 1000; | ||
| 167 | calc_val /= mode->vtotal; | ||
| 168 | |||
| 169 | refresh = calc_val; | ||
| 170 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | ||
| 171 | refresh *= 2; | ||
| 172 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
| 173 | refresh /= 2; | ||
| 174 | if (mode->vscan > 1) | ||
| 175 | refresh /= mode->vscan; | ||
| 176 | } | ||
| 177 | return refresh; | ||
| 178 | } | ||
| 179 | EXPORT_SYMBOL(drm_mode_vrefresh); | ||
| 180 | |||
| 181 | /** | ||
| 182 | * drm_mode_set_crtcinfo - set CRTC modesetting parameters | ||
| 183 | * @p: mode | ||
| 184 | * @adjust_flags: unused? (FIXME) | ||
| 185 | * | ||
| 186 | * LOCKING: | ||
| 187 | * None. | ||
| 188 | * | ||
| 189 | * Setup the CRTC modesetting parameters for @p, adjusting if necessary. | ||
| 190 | */ | ||
| 191 | void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) | ||
| 192 | { | ||
| 193 | if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN)) | ||
| 194 | return; | ||
| 195 | |||
| 196 | p->crtc_hdisplay = p->hdisplay; | ||
| 197 | p->crtc_hsync_start = p->hsync_start; | ||
| 198 | p->crtc_hsync_end = p->hsync_end; | ||
| 199 | p->crtc_htotal = p->htotal; | ||
| 200 | p->crtc_hskew = p->hskew; | ||
| 201 | p->crtc_vdisplay = p->vdisplay; | ||
| 202 | p->crtc_vsync_start = p->vsync_start; | ||
| 203 | p->crtc_vsync_end = p->vsync_end; | ||
| 204 | p->crtc_vtotal = p->vtotal; | ||
| 205 | |||
| 206 | if (p->flags & DRM_MODE_FLAG_INTERLACE) { | ||
| 207 | if (adjust_flags & CRTC_INTERLACE_HALVE_V) { | ||
| 208 | p->crtc_vdisplay /= 2; | ||
| 209 | p->crtc_vsync_start /= 2; | ||
| 210 | p->crtc_vsync_end /= 2; | ||
| 211 | p->crtc_vtotal /= 2; | ||
| 212 | } | ||
| 213 | |||
| 214 | p->crtc_vtotal |= 1; | ||
| 215 | } | ||
| 216 | |||
| 217 | if (p->flags & DRM_MODE_FLAG_DBLSCAN) { | ||
| 218 | p->crtc_vdisplay *= 2; | ||
| 219 | p->crtc_vsync_start *= 2; | ||
| 220 | p->crtc_vsync_end *= 2; | ||
| 221 | p->crtc_vtotal *= 2; | ||
| 222 | } | ||
| 223 | |||
| 224 | if (p->vscan > 1) { | ||
| 225 | p->crtc_vdisplay *= p->vscan; | ||
| 226 | p->crtc_vsync_start *= p->vscan; | ||
| 227 | p->crtc_vsync_end *= p->vscan; | ||
| 228 | p->crtc_vtotal *= p->vscan; | ||
| 229 | } | ||
| 230 | |||
| 231 | p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay); | ||
| 232 | p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal); | ||
| 233 | p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay); | ||
| 234 | p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal); | ||
| 235 | |||
| 236 | p->crtc_hadjusted = false; | ||
| 237 | p->crtc_vadjusted = false; | ||
| 238 | } | ||
| 239 | EXPORT_SYMBOL(drm_mode_set_crtcinfo); | ||
| 240 | |||
| 241 | |||
| 242 | /** | ||
| 243 | * drm_mode_duplicate - allocate and duplicate an existing mode | ||
| 244 | * @m: mode to duplicate | ||
| 245 | * | ||
| 246 | * LOCKING: | ||
| 247 | * None. | ||
| 248 | * | ||
| 249 | * Just allocate a new mode, copy the existing mode into it, and return | ||
| 250 | * a pointer to it. Used to create new instances of established modes. | ||
| 251 | */ | ||
| 252 | struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, | ||
| 253 | struct drm_display_mode *mode) | ||
| 254 | { | ||
| 255 | struct drm_display_mode *nmode; | ||
| 256 | int new_id; | ||
| 257 | |||
| 258 | nmode = drm_mode_create(dev); | ||
| 259 | if (!nmode) | ||
| 260 | return NULL; | ||
| 261 | |||
| 262 | new_id = nmode->base.id; | ||
| 263 | *nmode = *mode; | ||
| 264 | nmode->base.id = new_id; | ||
| 265 | INIT_LIST_HEAD(&nmode->head); | ||
| 266 | return nmode; | ||
| 267 | } | ||
| 268 | EXPORT_SYMBOL(drm_mode_duplicate); | ||
| 269 | |||
| 270 | /** | ||
| 271 | * drm_mode_equal - test modes for equality | ||
| 272 | * @mode1: first mode | ||
| 273 | * @mode2: second mode | ||
| 274 | * | ||
| 275 | * LOCKING: | ||
| 276 | * None. | ||
| 277 | * | ||
| 278 | * Check to see if @mode1 and @mode2 are equivalent. | ||
| 279 | * | ||
| 280 | * RETURNS: | ||
| 281 | * True if the modes are equal, false otherwise. | ||
| 282 | */ | ||
| 283 | bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2) | ||
| 284 | { | ||
| 285 | /* do clock check convert to PICOS so fb modes get matched | ||
| 286 | * the same */ | ||
| 287 | if (mode1->clock && mode2->clock) { | ||
| 288 | if (KHZ2PICOS(mode1->clock) != KHZ2PICOS(mode2->clock)) | ||
| 289 | return false; | ||
| 290 | } else if (mode1->clock != mode2->clock) | ||
| 291 | return false; | ||
| 292 | |||
| 293 | if (mode1->hdisplay == mode2->hdisplay && | ||
| 294 | mode1->hsync_start == mode2->hsync_start && | ||
| 295 | mode1->hsync_end == mode2->hsync_end && | ||
| 296 | mode1->htotal == mode2->htotal && | ||
| 297 | mode1->hskew == mode2->hskew && | ||
| 298 | mode1->vdisplay == mode2->vdisplay && | ||
| 299 | mode1->vsync_start == mode2->vsync_start && | ||
| 300 | mode1->vsync_end == mode2->vsync_end && | ||
| 301 | mode1->vtotal == mode2->vtotal && | ||
| 302 | mode1->vscan == mode2->vscan && | ||
| 303 | mode1->flags == mode2->flags) | ||
| 304 | return true; | ||
| 305 | |||
| 306 | return false; | ||
| 307 | } | ||
| 308 | EXPORT_SYMBOL(drm_mode_equal); | ||
| 309 | |||
| 310 | /** | ||
| 311 | * drm_mode_validate_size - make sure modes adhere to size constraints | ||
| 312 | * @dev: DRM device | ||
| 313 | * @mode_list: list of modes to check | ||
| 314 | * @maxX: maximum width | ||
| 315 | * @maxY: maximum height | ||
| 316 | * @maxPitch: max pitch | ||
| 317 | * | ||
| 318 | * LOCKING: | ||
| 319 | * Caller must hold a lock protecting @mode_list. | ||
| 320 | * | ||
| 321 | * The DRM device (@dev) has size and pitch limits. Here we validate the | ||
| 322 | * modes we probed for @dev against those limits and set their status as | ||
| 323 | * necessary. | ||
| 324 | */ | ||
| 325 | void drm_mode_validate_size(struct drm_device *dev, | ||
| 326 | struct list_head *mode_list, | ||
| 327 | int maxX, int maxY, int maxPitch) | ||
| 328 | { | ||
| 329 | struct drm_display_mode *mode; | ||
| 330 | |||
| 331 | list_for_each_entry(mode, mode_list, head) { | ||
| 332 | if (maxPitch > 0 && mode->hdisplay > maxPitch) | ||
| 333 | mode->status = MODE_BAD_WIDTH; | ||
| 334 | |||
| 335 | if (maxX > 0 && mode->hdisplay > maxX) | ||
| 336 | mode->status = MODE_VIRTUAL_X; | ||
| 337 | |||
| 338 | if (maxY > 0 && mode->vdisplay > maxY) | ||
| 339 | mode->status = MODE_VIRTUAL_Y; | ||
| 340 | } | ||
| 341 | } | ||
| 342 | EXPORT_SYMBOL(drm_mode_validate_size); | ||
| 343 | |||
| 344 | /** | ||
| 345 | * drm_mode_validate_clocks - validate modes against clock limits | ||
| 346 | * @dev: DRM device | ||
| 347 | * @mode_list: list of modes to check | ||
| 348 | * @min: minimum clock rate array | ||
| 349 | * @max: maximum clock rate array | ||
| 350 | * @n_ranges: number of clock ranges (size of arrays) | ||
| 351 | * | ||
| 352 | * LOCKING: | ||
| 353 | * Caller must hold a lock protecting @mode_list. | ||
| 354 | * | ||
| 355 | * Some code may need to check a mode list against the clock limits of the | ||
| 356 | * device in question. This function walks the mode list, testing to make | ||
| 357 | * sure each mode falls within a given range (defined by @min and @max | ||
| 358 | * arrays) and sets @mode->status as needed. | ||
| 359 | */ | ||
| 360 | void drm_mode_validate_clocks(struct drm_device *dev, | ||
| 361 | struct list_head *mode_list, | ||
| 362 | int *min, int *max, int n_ranges) | ||
| 363 | { | ||
| 364 | struct drm_display_mode *mode; | ||
| 365 | int i; | ||
| 366 | |||
| 367 | list_for_each_entry(mode, mode_list, head) { | ||
| 368 | bool good = false; | ||
| 369 | for (i = 0; i < n_ranges; i++) { | ||
| 370 | if (mode->clock >= min[i] && mode->clock <= max[i]) { | ||
| 371 | good = true; | ||
| 372 | break; | ||
| 373 | } | ||
| 374 | } | ||
| 375 | if (!good) | ||
| 376 | mode->status = MODE_CLOCK_RANGE; | ||
| 377 | } | ||
| 378 | } | ||
| 379 | EXPORT_SYMBOL(drm_mode_validate_clocks); | ||
| 380 | |||
| 381 | /** | ||
| 382 | * drm_mode_prune_invalid - remove invalid modes from mode list | ||
| 383 | * @dev: DRM device | ||
| 384 | * @mode_list: list of modes to check | ||
| 385 | * @verbose: be verbose about it | ||
| 386 | * | ||
| 387 | * LOCKING: | ||
| 388 | * Caller must hold a lock protecting @mode_list. | ||
| 389 | * | ||
| 390 | * Once mode list generation is complete, a caller can use this routine to | ||
| 391 | * remove invalid modes from a mode list. If any of the modes have a | ||
| 392 | * status other than %MODE_OK, they are removed from @mode_list and freed. | ||
| 393 | */ | ||
| 394 | void drm_mode_prune_invalid(struct drm_device *dev, | ||
| 395 | struct list_head *mode_list, bool verbose) | ||
| 396 | { | ||
| 397 | struct drm_display_mode *mode, *t; | ||
| 398 | |||
| 399 | list_for_each_entry_safe(mode, t, mode_list, head) { | ||
| 400 | if (mode->status != MODE_OK) { | ||
| 401 | list_del(&mode->head); | ||
| 402 | if (verbose) { | ||
| 403 | drm_mode_debug_printmodeline(mode); | ||
| 404 | DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status); | ||
| 405 | } | ||
| 406 | drm_mode_destroy(dev, mode); | ||
| 407 | } | ||
| 408 | } | ||
| 409 | } | ||
| 410 | EXPORT_SYMBOL(drm_mode_prune_invalid); | ||
| 411 | |||
| 412 | /** | ||
| 413 | * drm_mode_compare - compare modes for favorability | ||
| 414 | * @lh_a: list_head for first mode | ||
| 415 | * @lh_b: list_head for second mode | ||
| 416 | * | ||
| 417 | * LOCKING: | ||
| 418 | * None. | ||
| 419 | * | ||
| 420 | * Compare two modes, given by @lh_a and @lh_b, returning a value indicating | ||
| 421 | * which is better. | ||
| 422 | * | ||
| 423 | * RETURNS: | ||
| 424 | * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or | ||
| 425 | * positive if @lh_b is better than @lh_a. | ||
| 426 | */ | ||
| 427 | static int drm_mode_compare(struct list_head *lh_a, struct list_head *lh_b) | ||
| 428 | { | ||
| 429 | struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head); | ||
| 430 | struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head); | ||
| 431 | int diff; | ||
| 432 | |||
| 433 | diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) - | ||
| 434 | ((a->type & DRM_MODE_TYPE_PREFERRED) != 0); | ||
| 435 | if (diff) | ||
| 436 | return diff; | ||
| 437 | diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay; | ||
| 438 | if (diff) | ||
| 439 | return diff; | ||
| 440 | diff = b->clock - a->clock; | ||
| 441 | return diff; | ||
| 442 | } | ||
| 443 | |||
| 444 | /* FIXME: what we don't have a list sort function? */ | ||
| 445 | /* list sort from Mark J Roberts (mjr@znex.org) */ | ||
| 446 | void list_sort(struct list_head *head, | ||
| 447 | int (*cmp)(struct list_head *a, struct list_head *b)) | ||
| 448 | { | ||
| 449 | struct list_head *p, *q, *e, *list, *tail, *oldhead; | ||
| 450 | int insize, nmerges, psize, qsize, i; | ||
| 451 | |||
| 452 | list = head->next; | ||
| 453 | list_del(head); | ||
| 454 | insize = 1; | ||
| 455 | for (;;) { | ||
| 456 | p = oldhead = list; | ||
| 457 | list = tail = NULL; | ||
| 458 | nmerges = 0; | ||
| 459 | |||
| 460 | while (p) { | ||
| 461 | nmerges++; | ||
| 462 | q = p; | ||
| 463 | psize = 0; | ||
| 464 | for (i = 0; i < insize; i++) { | ||
| 465 | psize++; | ||
| 466 | q = q->next == oldhead ? NULL : q->next; | ||
| 467 | if (!q) | ||
| 468 | break; | ||
| 469 | } | ||
| 470 | |||
| 471 | qsize = insize; | ||
| 472 | while (psize > 0 || (qsize > 0 && q)) { | ||
| 473 | if (!psize) { | ||
| 474 | e = q; | ||
| 475 | q = q->next; | ||
| 476 | qsize--; | ||
| 477 | if (q == oldhead) | ||
| 478 | q = NULL; | ||
| 479 | } else if (!qsize || !q) { | ||
| 480 | e = p; | ||
| 481 | p = p->next; | ||
| 482 | psize--; | ||
| 483 | if (p == oldhead) | ||
| 484 | p = NULL; | ||
| 485 | } else if (cmp(p, q) <= 0) { | ||
| 486 | e = p; | ||
| 487 | p = p->next; | ||
| 488 | psize--; | ||
| 489 | if (p == oldhead) | ||
| 490 | p = NULL; | ||
| 491 | } else { | ||
| 492 | e = q; | ||
| 493 | q = q->next; | ||
| 494 | qsize--; | ||
| 495 | if (q == oldhead) | ||
| 496 | q = NULL; | ||
| 497 | } | ||
| 498 | if (tail) | ||
| 499 | tail->next = e; | ||
| 500 | else | ||
| 501 | list = e; | ||
| 502 | e->prev = tail; | ||
| 503 | tail = e; | ||
| 504 | } | ||
| 505 | p = q; | ||
| 506 | } | ||
| 507 | |||
| 508 | tail->next = list; | ||
| 509 | list->prev = tail; | ||
| 510 | |||
| 511 | if (nmerges <= 1) | ||
| 512 | break; | ||
| 513 | |||
| 514 | insize *= 2; | ||
| 515 | } | ||
| 516 | |||
| 517 | head->next = list; | ||
| 518 | head->prev = list->prev; | ||
| 519 | list->prev->next = head; | ||
| 520 | list->prev = head; | ||
| 521 | } | ||
| 522 | |||
| 523 | /** | ||
| 524 | * drm_mode_sort - sort mode list | ||
| 525 | * @mode_list: list to sort | ||
| 526 | * | ||
| 527 | * LOCKING: | ||
| 528 | * Caller must hold a lock protecting @mode_list. | ||
| 529 | * | ||
| 530 | * Sort @mode_list by favorability, putting good modes first. | ||
| 531 | */ | ||
| 532 | void drm_mode_sort(struct list_head *mode_list) | ||
| 533 | { | ||
| 534 | list_sort(mode_list, drm_mode_compare); | ||
| 535 | } | ||
| 536 | EXPORT_SYMBOL(drm_mode_sort); | ||
| 537 | |||
| 538 | /** | ||
| 539 | * drm_mode_connector_list_update - update the mode list for the connector | ||
| 540 | * @connector: the connector to update | ||
| 541 | * | ||
| 542 | * LOCKING: | ||
| 543 | * Caller must hold a lock protecting @mode_list. | ||
| 544 | * | ||
| 545 | * This moves the modes from the @connector probed_modes list | ||
| 546 | * to the actual mode list. It compares the probed mode against the current | ||
| 547 | * list and only adds different modes. All modes unverified after this point | ||
| 548 | * will be removed by the prune invalid modes. | ||
| 549 | */ | ||
| 550 | void drm_mode_connector_list_update(struct drm_connector *connector) | ||
| 551 | { | ||
| 552 | struct drm_display_mode *mode; | ||
| 553 | struct drm_display_mode *pmode, *pt; | ||
| 554 | int found_it; | ||
| 555 | |||
| 556 | list_for_each_entry_safe(pmode, pt, &connector->probed_modes, | ||
| 557 | head) { | ||
| 558 | found_it = 0; | ||
| 559 | /* go through current modes checking for the new probed mode */ | ||
| 560 | list_for_each_entry(mode, &connector->modes, head) { | ||
| 561 | if (drm_mode_equal(pmode, mode)) { | ||
| 562 | found_it = 1; | ||
| 563 | /* if equal delete the probed mode */ | ||
| 564 | mode->status = pmode->status; | ||
| 565 | list_del(&pmode->head); | ||
| 566 | drm_mode_destroy(connector->dev, pmode); | ||
| 567 | break; | ||
| 568 | } | ||
| 569 | } | ||
| 570 | |||
| 571 | if (!found_it) { | ||
| 572 | list_move_tail(&pmode->head, &connector->modes); | ||
| 573 | } | ||
| 574 | } | ||
| 575 | } | ||
| 576 | EXPORT_SYMBOL(drm_mode_connector_list_update); | ||
diff --git a/drivers/gpu/drm/drm_proc.c b/drivers/gpu/drm/drm_proc.c index ae73b7f7249a..8df849f66830 100644 --- a/drivers/gpu/drm/drm_proc.c +++ b/drivers/gpu/drm/drm_proc.c | |||
| @@ -49,6 +49,8 @@ static int drm_queues_info(char *buf, char **start, off_t offset, | |||
| 49 | int request, int *eof, void *data); | 49 | int request, int *eof, void *data); |
| 50 | static int drm_bufs_info(char *buf, char **start, off_t offset, | 50 | static int drm_bufs_info(char *buf, char **start, off_t offset, |
| 51 | int request, int *eof, void *data); | 51 | int request, int *eof, void *data); |
| 52 | static int drm_vblank_info(char *buf, char **start, off_t offset, | ||
| 53 | int request, int *eof, void *data); | ||
| 52 | static int drm_gem_name_info(char *buf, char **start, off_t offset, | 54 | static int drm_gem_name_info(char *buf, char **start, off_t offset, |
| 53 | int request, int *eof, void *data); | 55 | int request, int *eof, void *data); |
| 54 | static int drm_gem_object_info(char *buf, char **start, off_t offset, | 56 | static int drm_gem_object_info(char *buf, char **start, off_t offset, |
| @@ -72,6 +74,7 @@ static struct drm_proc_list { | |||
| 72 | {"clients", drm_clients_info, 0}, | 74 | {"clients", drm_clients_info, 0}, |
| 73 | {"queues", drm_queues_info, 0}, | 75 | {"queues", drm_queues_info, 0}, |
| 74 | {"bufs", drm_bufs_info, 0}, | 76 | {"bufs", drm_bufs_info, 0}, |
| 77 | {"vblank", drm_vblank_info, 0}, | ||
| 75 | {"gem_names", drm_gem_name_info, DRIVER_GEM}, | 78 | {"gem_names", drm_gem_name_info, DRIVER_GEM}, |
| 76 | {"gem_objects", drm_gem_object_info, DRIVER_GEM}, | 79 | {"gem_objects", drm_gem_object_info, DRIVER_GEM}, |
| 77 | #if DRM_DEBUG_CODE | 80 | #if DRM_DEBUG_CODE |
| @@ -195,6 +198,7 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request, | |||
| 195 | int *eof, void *data) | 198 | int *eof, void *data) |
| 196 | { | 199 | { |
| 197 | struct drm_minor *minor = (struct drm_minor *) data; | 200 | struct drm_minor *minor = (struct drm_minor *) data; |
| 201 | struct drm_master *master = minor->master; | ||
| 198 | struct drm_device *dev = minor->dev; | 202 | struct drm_device *dev = minor->dev; |
| 199 | int len = 0; | 203 | int len = 0; |
| 200 | 204 | ||
| @@ -203,13 +207,16 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request, | |||
| 203 | return 0; | 207 | return 0; |
| 204 | } | 208 | } |
| 205 | 209 | ||
| 210 | if (!master) | ||
| 211 | return 0; | ||
| 212 | |||
| 206 | *start = &buf[offset]; | 213 | *start = &buf[offset]; |
| 207 | *eof = 0; | 214 | *eof = 0; |
| 208 | 215 | ||
| 209 | if (dev->unique) { | 216 | if (master->unique) { |
| 210 | DRM_PROC_PRINT("%s %s %s\n", | 217 | DRM_PROC_PRINT("%s %s %s\n", |
| 211 | dev->driver->pci_driver.name, | 218 | dev->driver->pci_driver.name, |
| 212 | pci_name(dev->pdev), dev->unique); | 219 | pci_name(dev->pdev), master->unique); |
| 213 | } else { | 220 | } else { |
| 214 | DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name, | 221 | DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name, |
| 215 | pci_name(dev->pdev)); | 222 | pci_name(dev->pdev)); |
| @@ -454,6 +461,66 @@ static int drm_bufs_info(char *buf, char **start, off_t offset, int request, | |||
| 454 | } | 461 | } |
| 455 | 462 | ||
| 456 | /** | 463 | /** |
| 464 | * Called when "/proc/dri/.../vblank" is read. | ||
| 465 | * | ||
| 466 | * \param buf output buffer. | ||
| 467 | * \param start start of output data. | ||
| 468 | * \param offset requested start offset. | ||
| 469 | * \param request requested number of bytes. | ||
| 470 | * \param eof whether there is no more data to return. | ||
| 471 | * \param data private data. | ||
| 472 | * \return number of written bytes. | ||
| 473 | */ | ||
| 474 | static int drm__vblank_info(char *buf, char **start, off_t offset, int request, | ||
| 475 | int *eof, void *data) | ||
| 476 | { | ||
| 477 | struct drm_minor *minor = (struct drm_minor *) data; | ||
| 478 | struct drm_device *dev = minor->dev; | ||
| 479 | int len = 0; | ||
| 480 | int crtc; | ||
| 481 | |||
| 482 | if (offset > DRM_PROC_LIMIT) { | ||
| 483 | *eof = 1; | ||
| 484 | return 0; | ||
| 485 | } | ||
| 486 | |||
| 487 | *start = &buf[offset]; | ||
| 488 | *eof = 0; | ||
| 489 | |||
| 490 | for (crtc = 0; crtc < dev->num_crtcs; crtc++) { | ||
| 491 | DRM_PROC_PRINT("CRTC %d enable: %d\n", | ||
| 492 | crtc, atomic_read(&dev->vblank_refcount[crtc])); | ||
| 493 | DRM_PROC_PRINT("CRTC %d counter: %d\n", | ||
| 494 | crtc, drm_vblank_count(dev, crtc)); | ||
| 495 | DRM_PROC_PRINT("CRTC %d last wait: %d\n", | ||
| 496 | crtc, dev->last_vblank_wait[crtc]); | ||
| 497 | DRM_PROC_PRINT("CRTC %d in modeset: %d\n", | ||
| 498 | crtc, dev->vblank_inmodeset[crtc]); | ||
| 499 | } | ||
| 500 | |||
| 501 | if (len > request + offset) | ||
| 502 | return request; | ||
| 503 | *eof = 1; | ||
| 504 | return len - offset; | ||
| 505 | } | ||
| 506 | |||
| 507 | /** | ||
| 508 | * Simply calls _vblank_info() while holding the drm_device::struct_mutex lock. | ||
| 509 | */ | ||
| 510 | static int drm_vblank_info(char *buf, char **start, off_t offset, int request, | ||
| 511 | int *eof, void *data) | ||
| 512 | { | ||
| 513 | struct drm_minor *minor = (struct drm_minor *) data; | ||
| 514 | struct drm_device *dev = minor->dev; | ||
| 515 | int ret; | ||
| 516 | |||
| 517 | mutex_lock(&dev->struct_mutex); | ||
| 518 | ret = drm__vblank_info(buf, start, offset, request, eof, data); | ||
| 519 | mutex_unlock(&dev->struct_mutex); | ||
| 520 | return ret; | ||
| 521 | } | ||
| 522 | |||
| 523 | /** | ||
| 457 | * Called when "/proc/dri/.../clients" is read. | 524 | * Called when "/proc/dri/.../clients" is read. |
| 458 | * | 525 | * |
| 459 | * \param buf output buffer. | 526 | * \param buf output buffer. |
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 66c96ec66672..5ca132afa4f2 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c | |||
| @@ -57,6 +57,14 @@ static int drm_minor_get_id(struct drm_device *dev, int type) | |||
| 57 | int ret; | 57 | int ret; |
| 58 | int base = 0, limit = 63; | 58 | int base = 0, limit = 63; |
| 59 | 59 | ||
| 60 | if (type == DRM_MINOR_CONTROL) { | ||
| 61 | base += 64; | ||
| 62 | limit = base + 127; | ||
| 63 | } else if (type == DRM_MINOR_RENDER) { | ||
| 64 | base += 128; | ||
| 65 | limit = base + 255; | ||
| 66 | } | ||
| 67 | |||
| 60 | again: | 68 | again: |
| 61 | if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) { | 69 | if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) { |
| 62 | DRM_ERROR("Out of memory expanding drawable idr\n"); | 70 | DRM_ERROR("Out of memory expanding drawable idr\n"); |
| @@ -79,6 +87,104 @@ again: | |||
| 79 | return new_id; | 87 | return new_id; |
| 80 | } | 88 | } |
| 81 | 89 | ||
| 90 | struct drm_master *drm_master_create(struct drm_minor *minor) | ||
| 91 | { | ||
| 92 | struct drm_master *master; | ||
| 93 | |||
| 94 | master = drm_calloc(1, sizeof(*master), DRM_MEM_DRIVER); | ||
| 95 | if (!master) | ||
| 96 | return NULL; | ||
| 97 | |||
| 98 | kref_init(&master->refcount); | ||
| 99 | spin_lock_init(&master->lock.spinlock); | ||
| 100 | init_waitqueue_head(&master->lock.lock_queue); | ||
| 101 | drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER); | ||
| 102 | INIT_LIST_HEAD(&master->magicfree); | ||
| 103 | master->minor = minor; | ||
| 104 | |||
| 105 | list_add_tail(&master->head, &minor->master_list); | ||
| 106 | |||
| 107 | return master; | ||
| 108 | } | ||
| 109 | |||
| 110 | struct drm_master *drm_master_get(struct drm_master *master) | ||
| 111 | { | ||
| 112 | kref_get(&master->refcount); | ||
| 113 | return master; | ||
| 114 | } | ||
| 115 | |||
| 116 | static void drm_master_destroy(struct kref *kref) | ||
| 117 | { | ||
| 118 | struct drm_master *master = container_of(kref, struct drm_master, refcount); | ||
| 119 | struct drm_magic_entry *pt, *next; | ||
| 120 | struct drm_device *dev = master->minor->dev; | ||
| 121 | |||
| 122 | list_del(&master->head); | ||
| 123 | |||
| 124 | if (dev->driver->master_destroy) | ||
| 125 | dev->driver->master_destroy(dev, master); | ||
| 126 | |||
| 127 | if (master->unique) { | ||
| 128 | drm_free(master->unique, master->unique_size, DRM_MEM_DRIVER); | ||
| 129 | master->unique = NULL; | ||
| 130 | master->unique_len = 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | list_for_each_entry_safe(pt, next, &master->magicfree, head) { | ||
| 134 | list_del(&pt->head); | ||
| 135 | drm_ht_remove_item(&master->magiclist, &pt->hash_item); | ||
| 136 | drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); | ||
| 137 | } | ||
| 138 | |||
| 139 | drm_ht_remove(&master->magiclist); | ||
| 140 | |||
| 141 | if (master->lock.hw_lock) { | ||
| 142 | if (dev->sigdata.lock == master->lock.hw_lock) | ||
| 143 | dev->sigdata.lock = NULL; | ||
| 144 | master->lock.hw_lock = NULL; | ||
| 145 | master->lock.file_priv = NULL; | ||
| 146 | wake_up_interruptible(&master->lock.lock_queue); | ||
| 147 | } | ||
| 148 | |||
| 149 | drm_free(master, sizeof(*master), DRM_MEM_DRIVER); | ||
| 150 | } | ||
| 151 | |||
| 152 | void drm_master_put(struct drm_master **master) | ||
| 153 | { | ||
| 154 | kref_put(&(*master)->refcount, drm_master_destroy); | ||
| 155 | *master = NULL; | ||
| 156 | } | ||
| 157 | |||
| 158 | int drm_setmaster_ioctl(struct drm_device *dev, void *data, | ||
| 159 | struct drm_file *file_priv) | ||
| 160 | { | ||
| 161 | if (file_priv->minor->master && file_priv->minor->master != file_priv->master) | ||
| 162 | return -EINVAL; | ||
| 163 | |||
| 164 | if (!file_priv->master) | ||
| 165 | return -EINVAL; | ||
| 166 | |||
| 167 | if (!file_priv->minor->master && | ||
| 168 | file_priv->minor->master != file_priv->master) { | ||
| 169 | mutex_lock(&dev->struct_mutex); | ||
| 170 | file_priv->minor->master = drm_master_get(file_priv->master); | ||
| 171 | mutex_lock(&dev->struct_mutex); | ||
| 172 | } | ||
| 173 | |||
| 174 | return 0; | ||
| 175 | } | ||
| 176 | |||
| 177 | int drm_dropmaster_ioctl(struct drm_device *dev, void *data, | ||
| 178 | struct drm_file *file_priv) | ||
| 179 | { | ||
| 180 | if (!file_priv->master) | ||
| 181 | return -EINVAL; | ||
| 182 | mutex_lock(&dev->struct_mutex); | ||
| 183 | drm_master_put(&file_priv->minor->master); | ||
| 184 | mutex_unlock(&dev->struct_mutex); | ||
| 185 | return 0; | ||
| 186 | } | ||
| 187 | |||
| 82 | static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, | 188 | static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, |
| 83 | const struct pci_device_id *ent, | 189 | const struct pci_device_id *ent, |
| 84 | struct drm_driver *driver) | 190 | struct drm_driver *driver) |
| @@ -92,7 +198,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, | |||
| 92 | 198 | ||
| 93 | spin_lock_init(&dev->count_lock); | 199 | spin_lock_init(&dev->count_lock); |
| 94 | spin_lock_init(&dev->drw_lock); | 200 | spin_lock_init(&dev->drw_lock); |
| 95 | spin_lock_init(&dev->lock.spinlock); | ||
| 96 | init_timer(&dev->timer); | 201 | init_timer(&dev->timer); |
| 97 | mutex_init(&dev->struct_mutex); | 202 | mutex_init(&dev->struct_mutex); |
| 98 | mutex_init(&dev->ctxlist_mutex); | 203 | mutex_init(&dev->ctxlist_mutex); |
| @@ -140,9 +245,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, | |||
| 140 | } | 245 | } |
| 141 | } | 246 | } |
| 142 | 247 | ||
| 143 | if (dev->driver->load) | ||
| 144 | if ((retcode = dev->driver->load(dev, ent->driver_data))) | ||
| 145 | goto error_out_unreg; | ||
| 146 | 248 | ||
| 147 | retcode = drm_ctxbitmap_init(dev); | 249 | retcode = drm_ctxbitmap_init(dev); |
| 148 | if (retcode) { | 250 | if (retcode) { |
| @@ -200,6 +302,7 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t | |||
| 200 | new_minor->device = MKDEV(DRM_MAJOR, minor_id); | 302 | new_minor->device = MKDEV(DRM_MAJOR, minor_id); |
| 201 | new_minor->dev = dev; | 303 | new_minor->dev = dev; |
| 202 | new_minor->index = minor_id; | 304 | new_minor->index = minor_id; |
| 305 | INIT_LIST_HEAD(&new_minor->master_list); | ||
| 203 | 306 | ||
| 204 | idr_replace(&drm_minors_idr, new_minor, minor_id); | 307 | idr_replace(&drm_minors_idr, new_minor, minor_id); |
| 205 | 308 | ||
| @@ -267,8 +370,30 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, | |||
| 267 | printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); | 370 | printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); |
| 268 | goto err_g2; | 371 | goto err_g2; |
| 269 | } | 372 | } |
| 373 | |||
| 374 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
| 375 | ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); | ||
| 376 | if (ret) | ||
| 377 | goto err_g2; | ||
| 378 | } | ||
| 379 | |||
| 270 | if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) | 380 | if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) |
| 271 | goto err_g2; | 381 | goto err_g3; |
| 382 | |||
| 383 | if (dev->driver->load) { | ||
| 384 | ret = dev->driver->load(dev, ent->driver_data); | ||
| 385 | if (ret) | ||
| 386 | goto err_g3; | ||
| 387 | } | ||
| 388 | |||
| 389 | /* setup the grouping for the legacy output */ | ||
| 390 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
| 391 | ret = drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group); | ||
| 392 | if (ret) | ||
| 393 | goto err_g3; | ||
| 394 | } | ||
| 395 | |||
| 396 | list_add_tail(&dev->driver_item, &driver->device_list); | ||
| 272 | 397 | ||
| 273 | DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", | 398 | DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", |
| 274 | driver->name, driver->major, driver->minor, driver->patchlevel, | 399 | driver->name, driver->major, driver->minor, driver->patchlevel, |
| @@ -276,6 +401,8 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, | |||
| 276 | 401 | ||
| 277 | return 0; | 402 | return 0; |
| 278 | 403 | ||
| 404 | err_g3: | ||
| 405 | drm_put_minor(&dev->primary); | ||
| 279 | err_g2: | 406 | err_g2: |
| 280 | pci_disable_device(pdev); | 407 | pci_disable_device(pdev); |
| 281 | err_g1: | 408 | err_g1: |
| @@ -297,11 +424,6 @@ int drm_put_dev(struct drm_device * dev) | |||
| 297 | { | 424 | { |
| 298 | DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name); | 425 | DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name); |
| 299 | 426 | ||
| 300 | if (dev->unique) { | ||
| 301 | drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER); | ||
| 302 | dev->unique = NULL; | ||
| 303 | dev->unique_len = 0; | ||
| 304 | } | ||
| 305 | if (dev->devname) { | 427 | if (dev->devname) { |
| 306 | drm_free(dev->devname, strlen(dev->devname) + 1, | 428 | drm_free(dev->devname, strlen(dev->devname) + 1, |
| 307 | DRM_MEM_DRIVER); | 429 | DRM_MEM_DRIVER); |
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 1611b9bcbe7f..65d72d094c81 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include "drmP.h" | 20 | #include "drmP.h" |
| 21 | 21 | ||
| 22 | #define to_drm_minor(d) container_of(d, struct drm_minor, kdev) | 22 | #define to_drm_minor(d) container_of(d, struct drm_minor, kdev) |
| 23 | #define to_drm_connector(d) container_of(d, struct drm_connector, kdev) | ||
| 23 | 24 | ||
| 24 | /** | 25 | /** |
| 25 | * drm_sysfs_suspend - DRM class suspend hook | 26 | * drm_sysfs_suspend - DRM class suspend hook |
| @@ -34,7 +35,7 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) | |||
| 34 | struct drm_minor *drm_minor = to_drm_minor(dev); | 35 | struct drm_minor *drm_minor = to_drm_minor(dev); |
| 35 | struct drm_device *drm_dev = drm_minor->dev; | 36 | struct drm_device *drm_dev = drm_minor->dev; |
| 36 | 37 | ||
| 37 | if (drm_dev->driver->suspend) | 38 | if (drm_minor->type == DRM_MINOR_LEGACY && drm_dev->driver->suspend) |
| 38 | return drm_dev->driver->suspend(drm_dev, state); | 39 | return drm_dev->driver->suspend(drm_dev, state); |
| 39 | 40 | ||
| 40 | return 0; | 41 | return 0; |
| @@ -52,7 +53,7 @@ static int drm_sysfs_resume(struct device *dev) | |||
| 52 | struct drm_minor *drm_minor = to_drm_minor(dev); | 53 | struct drm_minor *drm_minor = to_drm_minor(dev); |
| 53 | struct drm_device *drm_dev = drm_minor->dev; | 54 | struct drm_device *drm_dev = drm_minor->dev; |
| 54 | 55 | ||
| 55 | if (drm_dev->driver->resume) | 56 | if (drm_minor->type == DRM_MINOR_LEGACY && drm_dev->driver->resume) |
| 56 | return drm_dev->driver->resume(drm_dev); | 57 | return drm_dev->driver->resume(drm_dev); |
| 57 | 58 | ||
| 58 | return 0; | 59 | return 0; |
| @@ -144,6 +145,323 @@ static void drm_sysfs_device_release(struct device *dev) | |||
| 144 | return; | 145 | return; |
| 145 | } | 146 | } |
| 146 | 147 | ||
| 148 | /* | ||
| 149 | * Connector properties | ||
| 150 | */ | ||
| 151 | static ssize_t status_show(struct device *device, | ||
| 152 | struct device_attribute *attr, | ||
| 153 | char *buf) | ||
| 154 | { | ||
| 155 | struct drm_connector *connector = to_drm_connector(device); | ||
| 156 | enum drm_connector_status status; | ||
| 157 | |||
| 158 | status = connector->funcs->detect(connector); | ||
| 159 | return snprintf(buf, PAGE_SIZE, "%s", | ||
| 160 | drm_get_connector_status_name(status)); | ||
| 161 | } | ||
| 162 | |||
| 163 | static ssize_t dpms_show(struct device *device, | ||
| 164 | struct device_attribute *attr, | ||
| 165 | char *buf) | ||
| 166 | { | ||
| 167 | struct drm_connector *connector = to_drm_connector(device); | ||
| 168 | struct drm_device *dev = connector->dev; | ||
| 169 | uint64_t dpms_status; | ||
| 170 | int ret; | ||
| 171 | |||
| 172 | ret = drm_connector_property_get_value(connector, | ||
| 173 | dev->mode_config.dpms_property, | ||
| 174 | &dpms_status); | ||
| 175 | if (ret) | ||
| 176 | return 0; | ||
| 177 | |||
| 178 | return snprintf(buf, PAGE_SIZE, "%s", | ||
| 179 | drm_get_dpms_name((int)dpms_status)); | ||
| 180 | } | ||
| 181 | |||
| 182 | static ssize_t enabled_show(struct device *device, | ||
| 183 | struct device_attribute *attr, | ||
| 184 | char *buf) | ||
| 185 | { | ||
| 186 | struct drm_connector *connector = to_drm_connector(device); | ||
| 187 | |||
| 188 | return snprintf(buf, PAGE_SIZE, connector->encoder ? "enabled" : | ||
| 189 | "disabled"); | ||
| 190 | } | ||
| 191 | |||
| 192 | static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr, | ||
| 193 | char *buf, loff_t off, size_t count) | ||
| 194 | { | ||
| 195 | struct device *connector_dev = container_of(kobj, struct device, kobj); | ||
| 196 | struct drm_connector *connector = to_drm_connector(connector_dev); | ||
| 197 | unsigned char *edid; | ||
| 198 | size_t size; | ||
| 199 | |||
| 200 | if (!connector->edid_blob_ptr) | ||
| 201 | return 0; | ||
| 202 | |||
| 203 | edid = connector->edid_blob_ptr->data; | ||
| 204 | size = connector->edid_blob_ptr->length; | ||
| 205 | if (!edid) | ||
| 206 | return 0; | ||
| 207 | |||
| 208 | if (off >= size) | ||
| 209 | return 0; | ||
| 210 | |||
| 211 | if (off + count > size) | ||
| 212 | count = size - off; | ||
| 213 | memcpy(buf, edid + off, count); | ||
| 214 | |||
| 215 | return count; | ||
| 216 | } | ||
| 217 | |||
| 218 | static ssize_t modes_show(struct device *device, | ||
| 219 | struct device_attribute *attr, | ||
| 220 | char *buf) | ||
| 221 | { | ||
| 222 | struct drm_connector *connector = to_drm_connector(device); | ||
| 223 | struct drm_display_mode *mode; | ||
| 224 | int written = 0; | ||
| 225 | |||
| 226 | list_for_each_entry(mode, &connector->modes, head) { | ||
| 227 | written += snprintf(buf + written, PAGE_SIZE - written, "%s\n", | ||
| 228 | mode->name); | ||
| 229 | } | ||
| 230 | |||
| 231 | return written; | ||
| 232 | } | ||
| 233 | |||
| 234 | static ssize_t subconnector_show(struct device *device, | ||
| 235 | struct device_attribute *attr, | ||
| 236 | char *buf) | ||
| 237 | { | ||
| 238 | struct drm_connector *connector = to_drm_connector(device); | ||
| 239 | struct drm_device *dev = connector->dev; | ||
| 240 | struct drm_property *prop = NULL; | ||
| 241 | uint64_t subconnector; | ||
| 242 | int is_tv = 0; | ||
| 243 | int ret; | ||
| 244 | |||
| 245 | switch (connector->connector_type) { | ||
| 246 | case DRM_MODE_CONNECTOR_DVII: | ||
| 247 | prop = dev->mode_config.dvi_i_subconnector_property; | ||
| 248 | break; | ||
| 249 | case DRM_MODE_CONNECTOR_Composite: | ||
| 250 | case DRM_MODE_CONNECTOR_SVIDEO: | ||
| 251 | case DRM_MODE_CONNECTOR_Component: | ||
| 252 | prop = dev->mode_config.tv_subconnector_property; | ||
| 253 | is_tv = 1; | ||
| 254 | break; | ||
| 255 | default: | ||
| 256 | DRM_ERROR("Wrong connector type for this property\n"); | ||
| 257 | return 0; | ||
| 258 | } | ||
| 259 | |||
| 260 | if (!prop) { | ||
| 261 | DRM_ERROR("Unable to find subconnector property\n"); | ||
| 262 | return 0; | ||
| 263 | } | ||
| 264 | |||
| 265 | ret = drm_connector_property_get_value(connector, prop, &subconnector); | ||
| 266 | if (ret) | ||
| 267 | return 0; | ||
| 268 | |||
| 269 | return snprintf(buf, PAGE_SIZE, "%s", is_tv ? | ||
| 270 | drm_get_tv_subconnector_name((int)subconnector) : | ||
| 271 | drm_get_dvi_i_subconnector_name((int)subconnector)); | ||
| 272 | } | ||
| 273 | |||
| 274 | static ssize_t select_subconnector_show(struct device *device, | ||
| 275 | struct device_attribute *attr, | ||
| 276 | char *buf) | ||
| 277 | { | ||
| 278 | struct drm_connector *connector = to_drm_connector(device); | ||
| 279 | struct drm_device *dev = connector->dev; | ||
| 280 | struct drm_property *prop = NULL; | ||
| 281 | uint64_t subconnector; | ||
| 282 | int is_tv = 0; | ||
| 283 | int ret; | ||
| 284 | |||
| 285 | switch (connector->connector_type) { | ||
| 286 | case DRM_MODE_CONNECTOR_DVII: | ||
| 287 | prop = dev->mode_config.dvi_i_select_subconnector_property; | ||
| 288 | break; | ||
| 289 | case DRM_MODE_CONNECTOR_Composite: | ||
| 290 | case DRM_MODE_CONNECTOR_SVIDEO: | ||
| 291 | case DRM_MODE_CONNECTOR_Component: | ||
| 292 | prop = dev->mode_config.tv_select_subconnector_property; | ||
| 293 | is_tv = 1; | ||
| 294 | break; | ||
| 295 | default: | ||
| 296 | DRM_ERROR("Wrong connector type for this property\n"); | ||
| 297 | return 0; | ||
| 298 | } | ||
| 299 | |||
| 300 | if (!prop) { | ||
| 301 | DRM_ERROR("Unable to find select subconnector property\n"); | ||
| 302 | return 0; | ||
| 303 | } | ||
| 304 | |||
| 305 | ret = drm_connector_property_get_value(connector, prop, &subconnector); | ||
| 306 | if (ret) | ||
| 307 | return 0; | ||
| 308 | |||
| 309 | return snprintf(buf, PAGE_SIZE, "%s", is_tv ? | ||
| 310 | drm_get_tv_select_name((int)subconnector) : | ||
| 311 | drm_get_dvi_i_select_name((int)subconnector)); | ||
| 312 | } | ||
| 313 | |||
| 314 | static struct device_attribute connector_attrs[] = { | ||
| 315 | __ATTR_RO(status), | ||
| 316 | __ATTR_RO(enabled), | ||
| 317 | __ATTR_RO(dpms), | ||
| 318 | __ATTR_RO(modes), | ||
| 319 | }; | ||
| 320 | |||
| 321 | /* These attributes are for both DVI-I connectors and all types of tv-out. */ | ||
| 322 | static struct device_attribute connector_attrs_opt1[] = { | ||
| 323 | __ATTR_RO(subconnector), | ||
| 324 | __ATTR_RO(select_subconnector), | ||
| 325 | }; | ||
| 326 | |||
| 327 | static struct bin_attribute edid_attr = { | ||
| 328 | .attr.name = "edid", | ||
| 329 | .size = 128, | ||
| 330 | .read = edid_show, | ||
| 331 | }; | ||
| 332 | |||
| 333 | /** | ||
| 334 | * drm_sysfs_connector_add - add an connector to sysfs | ||
| 335 | * @connector: connector to add | ||
| 336 | * | ||
| 337 | * Create an connector device in sysfs, along with its associated connector | ||
| 338 | * properties (so far, connection status, dpms, mode list & edid) and | ||
| 339 | * generate a hotplug event so userspace knows there's a new connector | ||
| 340 | * available. | ||
| 341 | * | ||
| 342 | * Note: | ||
| 343 | * This routine should only be called *once* for each DRM minor registered. | ||
| 344 | * A second call for an already registered device will trigger the BUG_ON | ||
| 345 | * below. | ||
| 346 | */ | ||
| 347 | int drm_sysfs_connector_add(struct drm_connector *connector) | ||
| 348 | { | ||
| 349 | struct drm_device *dev = connector->dev; | ||
| 350 | int ret = 0, i, j; | ||
| 351 | |||
| 352 | /* We shouldn't get called more than once for the same connector */ | ||
| 353 | BUG_ON(device_is_registered(&connector->kdev)); | ||
| 354 | |||
| 355 | connector->kdev.parent = &dev->primary->kdev; | ||
| 356 | connector->kdev.class = drm_class; | ||
| 357 | connector->kdev.release = drm_sysfs_device_release; | ||
| 358 | |||
| 359 | DRM_DEBUG("adding \"%s\" to sysfs\n", | ||
| 360 | drm_get_connector_name(connector)); | ||
| 361 | |||
| 362 | snprintf(connector->kdev.bus_id, BUS_ID_SIZE, "card%d-%s", | ||
| 363 | dev->primary->index, drm_get_connector_name(connector)); | ||
| 364 | ret = device_register(&connector->kdev); | ||
| 365 | |||
| 366 | if (ret) { | ||
| 367 | DRM_ERROR("failed to register connector device: %d\n", ret); | ||
| 368 | goto out; | ||
| 369 | } | ||
| 370 | |||
| 371 | /* Standard attributes */ | ||
| 372 | |||
| 373 | for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) { | ||
| 374 | ret = device_create_file(&connector->kdev, &connector_attrs[i]); | ||
| 375 | if (ret) | ||
| 376 | goto err_out_files; | ||
| 377 | } | ||
| 378 | |||
| 379 | /* Optional attributes */ | ||
| 380 | /* | ||
| 381 | * In the long run it maybe a good idea to make one set of | ||
| 382 | * optionals per connector type. | ||
| 383 | */ | ||
| 384 | switch (connector->connector_type) { | ||
| 385 | case DRM_MODE_CONNECTOR_DVII: | ||
| 386 | case DRM_MODE_CONNECTOR_Composite: | ||
| 387 | case DRM_MODE_CONNECTOR_SVIDEO: | ||
| 388 | case DRM_MODE_CONNECTOR_Component: | ||
| 389 | for (i = 0; i < ARRAY_SIZE(connector_attrs_opt1); i++) { | ||
| 390 | ret = device_create_file(&connector->kdev, &connector_attrs_opt1[i]); | ||
| 391 | if (ret) | ||
| 392 | goto err_out_files; | ||
| 393 | } | ||
| 394 | break; | ||
| 395 | default: | ||
| 396 | break; | ||
| 397 | } | ||
| 398 | |||
| 399 | ret = sysfs_create_bin_file(&connector->kdev.kobj, &edid_attr); | ||
| 400 | if (ret) | ||
| 401 | goto err_out_files; | ||
| 402 | |||
| 403 | /* Let userspace know we have a new connector */ | ||
| 404 | drm_sysfs_hotplug_event(dev); | ||
| 405 | |||
| 406 | return 0; | ||
| 407 | |||
| 408 | err_out_files: | ||
| 409 | if (i > 0) | ||
| 410 | for (j = 0; j < i; j++) | ||
| 411 | device_remove_file(&connector->kdev, | ||
| 412 | &connector_attrs[i]); | ||
| 413 | device_unregister(&connector->kdev); | ||
| 414 | |||
| 415 | out: | ||
| 416 | return ret; | ||
| 417 | } | ||
| 418 | EXPORT_SYMBOL(drm_sysfs_connector_add); | ||
| 419 | |||
| 420 | /** | ||
| 421 | * drm_sysfs_connector_remove - remove an connector device from sysfs | ||
| 422 | * @connector: connector to remove | ||
| 423 | * | ||
| 424 | * Remove @connector and its associated attributes from sysfs. Note that | ||
| 425 | * the device model core will take care of sending the "remove" uevent | ||
| 426 | * at this time, so we don't need to do it. | ||
| 427 | * | ||
| 428 | * Note: | ||
| 429 | * This routine should only be called if the connector was previously | ||
| 430 | * successfully registered. If @connector hasn't been registered yet, | ||
| 431 | * you'll likely see a panic somewhere deep in sysfs code when called. | ||
| 432 | */ | ||
| 433 | void drm_sysfs_connector_remove(struct drm_connector *connector) | ||
| 434 | { | ||
| 435 | int i; | ||
| 436 | |||
| 437 | DRM_DEBUG("removing \"%s\" from sysfs\n", | ||
| 438 | drm_get_connector_name(connector)); | ||
| 439 | |||
| 440 | for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) | ||
| 441 | device_remove_file(&connector->kdev, &connector_attrs[i]); | ||
| 442 | sysfs_remove_bin_file(&connector->kdev.kobj, &edid_attr); | ||
| 443 | device_unregister(&connector->kdev); | ||
| 444 | } | ||
| 445 | EXPORT_SYMBOL(drm_sysfs_connector_remove); | ||
| 446 | |||
| 447 | /** | ||
| 448 | * drm_sysfs_hotplug_event - generate a DRM uevent | ||
| 449 | * @dev: DRM device | ||
| 450 | * | ||
| 451 | * Send a uevent for the DRM device specified by @dev. Currently we only | ||
| 452 | * set HOTPLUG=1 in the uevent environment, but this could be expanded to | ||
| 453 | * deal with other types of events. | ||
| 454 | */ | ||
| 455 | void drm_sysfs_hotplug_event(struct drm_device *dev) | ||
| 456 | { | ||
| 457 | char *event_string = "HOTPLUG=1"; | ||
| 458 | char *envp[] = { event_string, NULL }; | ||
| 459 | |||
| 460 | DRM_DEBUG("generating hotplug event\n"); | ||
| 461 | |||
| 462 | kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); | ||
| 463 | } | ||
| 464 | |||
| 147 | /** | 465 | /** |
| 148 | * drm_sysfs_device_add - adds a class device to sysfs for a character driver | 466 | * drm_sysfs_device_add - adds a class device to sysfs for a character driver |
| 149 | * @dev: DRM device to be added | 467 | * @dev: DRM device to be added |
| @@ -163,7 +481,12 @@ int drm_sysfs_device_add(struct drm_minor *minor) | |||
| 163 | minor->kdev.class = drm_class; | 481 | minor->kdev.class = drm_class; |
| 164 | minor->kdev.release = drm_sysfs_device_release; | 482 | minor->kdev.release = drm_sysfs_device_release; |
| 165 | minor->kdev.devt = minor->device; | 483 | minor->kdev.devt = minor->device; |
| 166 | minor_str = "card%d"; | 484 | if (minor->type == DRM_MINOR_CONTROL) |
| 485 | minor_str = "controlD%d"; | ||
| 486 | else if (minor->type == DRM_MINOR_RENDER) | ||
| 487 | minor_str = "renderD%d"; | ||
| 488 | else | ||
| 489 | minor_str = "card%d"; | ||
| 167 | 490 | ||
| 168 | snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index); | 491 | snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index); |
| 169 | 492 | ||
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index c234c6f24a8d..3ffae021d280 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c | |||
| @@ -267,6 +267,9 @@ static void drm_vm_shm_close(struct vm_area_struct *vma) | |||
| 267 | dmah.size = map->size; | 267 | dmah.size = map->size; |
| 268 | __drm_pci_free(dev, &dmah); | 268 | __drm_pci_free(dev, &dmah); |
| 269 | break; | 269 | break; |
| 270 | case _DRM_GEM: | ||
| 271 | DRM_ERROR("tried to rmmap GEM object\n"); | ||
| 272 | break; | ||
| 270 | } | 273 | } |
| 271 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); | 274 | drm_free(map, sizeof(*map), DRM_MEM_MAPS); |
| 272 | } | 275 | } |
| @@ -399,7 +402,7 @@ static struct vm_operations_struct drm_vm_sg_ops = { | |||
| 399 | * Create a new drm_vma_entry structure as the \p vma private data entry and | 402 | * Create a new drm_vma_entry structure as the \p vma private data entry and |
| 400 | * add it to drm_device::vmalist. | 403 | * add it to drm_device::vmalist. |
| 401 | */ | 404 | */ |
| 402 | static void drm_vm_open_locked(struct vm_area_struct *vma) | 405 | void drm_vm_open_locked(struct vm_area_struct *vma) |
| 403 | { | 406 | { |
| 404 | struct drm_file *priv = vma->vm_file->private_data; | 407 | struct drm_file *priv = vma->vm_file->private_data; |
| 405 | struct drm_device *dev = priv->minor->dev; | 408 | struct drm_device *dev = priv->minor->dev; |
| @@ -540,7 +543,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs); | |||
| 540 | * according to the mapping type and remaps the pages. Finally sets the file | 543 | * according to the mapping type and remaps the pages. Finally sets the file |
| 541 | * pointer and calls vm_open(). | 544 | * pointer and calls vm_open(). |
| 542 | */ | 545 | */ |
| 543 | static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) | 546 | int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) |
| 544 | { | 547 | { |
| 545 | struct drm_file *priv = filp->private_data; | 548 | struct drm_file *priv = filp->private_data; |
| 546 | struct drm_device *dev = priv->minor->dev; | 549 | struct drm_device *dev = priv->minor->dev; |
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index d8fb5d8ee7ea..dd57a5bd4572 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile | |||
| @@ -8,7 +8,22 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ | |||
| 8 | i915_gem.o \ | 8 | i915_gem.o \ |
| 9 | i915_gem_debug.o \ | 9 | i915_gem_debug.o \ |
| 10 | i915_gem_proc.o \ | 10 | i915_gem_proc.o \ |
| 11 | i915_gem_tiling.o | 11 | i915_gem_tiling.o \ |
| 12 | intel_display.o \ | ||
| 13 | intel_crt.o \ | ||
| 14 | intel_lvds.o \ | ||
| 15 | intel_bios.o \ | ||
| 16 | intel_sdvo.o \ | ||
| 17 | intel_modes.o \ | ||
| 18 | intel_i2c.o \ | ||
| 19 | intel_fb.o \ | ||
| 20 | intel_tv.o \ | ||
| 21 | intel_dvo.o \ | ||
| 22 | dvo_ch7xxx.o \ | ||
| 23 | dvo_ch7017.o \ | ||
| 24 | dvo_ivch.o \ | ||
| 25 | dvo_tfp410.o \ | ||
| 26 | dvo_sil164.o | ||
| 12 | 27 | ||
| 13 | i915-$(CONFIG_ACPI) += i915_opregion.o | 28 | i915-$(CONFIG_ACPI) += i915_opregion.o |
| 14 | i915-$(CONFIG_COMPAT) += i915_ioc32.o | 29 | i915-$(CONFIG_COMPAT) += i915_ioc32.o |
diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h new file mode 100644 index 000000000000..e747ac42fe3a --- /dev/null +++ b/drivers/gpu/drm/i915/dvo.h | |||
| @@ -0,0 +1,157 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2006 Eric Anholt | ||
| 3 | * | ||
| 4 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
| 5 | * documentation for any purpose is hereby granted without fee, provided that | ||
| 6 | * the above copyright notice appear in all copies and that both that copyright | ||
| 7 | * notice and this permission notice appear in supporting documentation, and | ||
| 8 | * that the name of the copyright holders not be used in advertising or | ||
| 9 | * publicity pertaining to distribution of the software without specific, | ||
| 10 | * written prior permission. The copyright holders make no representations | ||
| 11 | * about the suitability of this software for any purpose. It is provided "as | ||
| 12 | * is" without express or implied warranty. | ||
| 13 | * | ||
| 14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
| 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
| 16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
| 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
| 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
| 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
| 20 | * OF THIS SOFTWARE. | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef _INTEL_DVO_H | ||
| 24 | #define _INTEL_DVO_H | ||
| 25 | |||
| 26 | #include <linux/i2c.h> | ||
| 27 | #include "drmP.h" | ||
| 28 | #include "drm.h" | ||
| 29 | #include "drm_crtc.h" | ||
| 30 | #include "intel_drv.h" | ||
| 31 | |||
| 32 | struct intel_dvo_device { | ||
| 33 | char *name; | ||
| 34 | int type; | ||
| 35 | /* DVOA/B/C output register */ | ||
| 36 | u32 dvo_reg; | ||
| 37 | /* GPIO register used for i2c bus to control this device */ | ||
| 38 | u32 gpio; | ||
| 39 | int slave_addr; | ||
| 40 | struct intel_i2c_chan *i2c_bus; | ||
| 41 | |||
| 42 | const struct intel_dvo_dev_ops *dev_ops; | ||
| 43 | void *dev_priv; | ||
| 44 | |||
| 45 | struct drm_display_mode *panel_fixed_mode; | ||
| 46 | bool panel_wants_dither; | ||
| 47 | }; | ||
| 48 | |||
| 49 | struct intel_dvo_dev_ops { | ||
| 50 | /* | ||
| 51 | * Initialize the device at startup time. | ||
| 52 | * Returns NULL if the device does not exist. | ||
| 53 | */ | ||
| 54 | bool (*init)(struct intel_dvo_device *dvo, | ||
| 55 | struct intel_i2c_chan *i2cbus); | ||
| 56 | |||
| 57 | /* | ||
| 58 | * Called to allow the output a chance to create properties after the | ||
| 59 | * RandR objects have been created. | ||
| 60 | */ | ||
| 61 | void (*create_resources)(struct intel_dvo_device *dvo); | ||
| 62 | |||
| 63 | /* | ||
| 64 | * Turn on/off output or set intermediate power levels if available. | ||
| 65 | * | ||
| 66 | * Unsupported intermediate modes drop to the lower power setting. | ||
| 67 | * If the mode is DPMSModeOff, the output must be disabled, | ||
| 68 | * as the DPLL may be disabled afterwards. | ||
| 69 | */ | ||
| 70 | void (*dpms)(struct intel_dvo_device *dvo, int mode); | ||
| 71 | |||
| 72 | /* | ||
| 73 | * Saves the output's state for restoration on VT switch. | ||
| 74 | */ | ||
| 75 | void (*save)(struct intel_dvo_device *dvo); | ||
| 76 | |||
| 77 | /* | ||
| 78 | * Restore's the output's state at VT switch. | ||
| 79 | */ | ||
| 80 | void (*restore)(struct intel_dvo_device *dvo); | ||
| 81 | |||
| 82 | /* | ||
| 83 | * Callback for testing a video mode for a given output. | ||
| 84 | * | ||
| 85 | * This function should only check for cases where a mode can't | ||
| 86 | * be supported on the output specifically, and not represent | ||
| 87 | * generic CRTC limitations. | ||
| 88 | * | ||
| 89 | * \return MODE_OK if the mode is valid, or another MODE_* otherwise. | ||
| 90 | */ | ||
| 91 | int (*mode_valid)(struct intel_dvo_device *dvo, | ||
| 92 | struct drm_display_mode *mode); | ||
| 93 | |||
| 94 | /* | ||
| 95 | * Callback to adjust the mode to be set in the CRTC. | ||
| 96 | * | ||
| 97 | * This allows an output to adjust the clock or even the entire set of | ||
| 98 | * timings, which is used for panels with fixed timings or for | ||
| 99 | * buses with clock limitations. | ||
| 100 | */ | ||
| 101 | bool (*mode_fixup)(struct intel_dvo_device *dvo, | ||
| 102 | struct drm_display_mode *mode, | ||
| 103 | struct drm_display_mode *adjusted_mode); | ||
| 104 | |||
| 105 | /* | ||
| 106 | * Callback for preparing mode changes on an output | ||
| 107 | */ | ||
| 108 | void (*prepare)(struct intel_dvo_device *dvo); | ||
| 109 | |||
| 110 | /* | ||
| 111 | * Callback for committing mode changes on an output | ||
| 112 | */ | ||
| 113 | void (*commit)(struct intel_dvo_device *dvo); | ||
| 114 | |||
| 115 | /* | ||
| 116 | * Callback for setting up a video mode after fixups have been made. | ||
| 117 | * | ||
| 118 | * This is only called while the output is disabled. The dpms callback | ||
| 119 | * must be all that's necessary for the output, to turn the output on | ||
| 120 | * after this function is called. | ||
| 121 | */ | ||
| 122 | void (*mode_set)(struct intel_dvo_device *dvo, | ||
| 123 | struct drm_display_mode *mode, | ||
| 124 | struct drm_display_mode *adjusted_mode); | ||
| 125 | |||
| 126 | /* | ||
| 127 | * Probe for a connected output, and return detect_status. | ||
| 128 | */ | ||
| 129 | enum drm_connector_status (*detect)(struct intel_dvo_device *dvo); | ||
| 130 | |||
| 131 | /** | ||
| 132 | * Query the device for the modes it provides. | ||
| 133 | * | ||
| 134 | * This function may also update MonInfo, mm_width, and mm_height. | ||
| 135 | * | ||
| 136 | * \return singly-linked list of modes or NULL if no modes found. | ||
| 137 | */ | ||
| 138 | struct drm_display_mode *(*get_modes)(struct intel_dvo_device *dvo); | ||
| 139 | |||
| 140 | /** | ||
| 141 | * Clean up driver-specific bits of the output | ||
| 142 | */ | ||
| 143 | void (*destroy) (struct intel_dvo_device *dvo); | ||
| 144 | |||
| 145 | /** | ||
| 146 | * Debugging hook to dump device registers to log file | ||
| 147 | */ | ||
| 148 | void (*dump_regs)(struct intel_dvo_device *dvo); | ||
| 149 | }; | ||
| 150 | |||
| 151 | extern struct intel_dvo_dev_ops sil164_ops; | ||
| 152 | extern struct intel_dvo_dev_ops ch7xxx_ops; | ||
| 153 | extern struct intel_dvo_dev_ops ivch_ops; | ||
| 154 | extern struct intel_dvo_dev_ops tfp410_ops; | ||
| 155 | extern struct intel_dvo_dev_ops ch7017_ops; | ||
| 156 | |||
| 157 | #endif /* _INTEL_DVO_H */ | ||
diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c new file mode 100644 index 000000000000..03d4b4973b02 --- /dev/null +++ b/drivers/gpu/drm/i915/dvo_ch7017.c | |||
| @@ -0,0 +1,454 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2006 Intel Corporation | ||
| 3 | * | ||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 5 | * copy of this software and associated documentation files (the "Software"), | ||
| 6 | * to deal in the Software without restriction, including without limitation | ||
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 9 | * Software is furnished to do so, subject to the following conditions: | ||
| 10 | * | ||
| 11 | * The above copyright notice and this permission notice (including the next | ||
| 12 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 13 | * Software. | ||
| 14 | * | ||
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 21 | * DEALINGS IN THE SOFTWARE. | ||
| 22 | * | ||
| 23 | * Authors: | ||
| 24 | * Eric Anholt <eric@anholt.net> | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include "dvo.h" | ||
| 29 | |||
| 30 | #define CH7017_TV_DISPLAY_MODE 0x00 | ||
| 31 | #define CH7017_FLICKER_FILTER 0x01 | ||
| 32 | #define CH7017_VIDEO_BANDWIDTH 0x02 | ||
| 33 | #define CH7017_TEXT_ENHANCEMENT 0x03 | ||
| 34 | #define CH7017_START_ACTIVE_VIDEO 0x04 | ||
| 35 | #define CH7017_HORIZONTAL_POSITION 0x05 | ||
| 36 | #define CH7017_VERTICAL_POSITION 0x06 | ||
| 37 | #define CH7017_BLACK_LEVEL 0x07 | ||
| 38 | #define CH7017_CONTRAST_ENHANCEMENT 0x08 | ||
| 39 | #define CH7017_TV_PLL 0x09 | ||
| 40 | #define CH7017_TV_PLL_M 0x0a | ||
| 41 | #define CH7017_TV_PLL_N 0x0b | ||
| 42 | #define CH7017_SUB_CARRIER_0 0x0c | ||
| 43 | #define CH7017_CIV_CONTROL 0x10 | ||
| 44 | #define CH7017_CIV_0 0x11 | ||
| 45 | #define CH7017_CHROMA_BOOST 0x14 | ||
| 46 | #define CH7017_CLOCK_MODE 0x1c | ||
| 47 | #define CH7017_INPUT_CLOCK 0x1d | ||
| 48 | #define CH7017_GPIO_CONTROL 0x1e | ||
| 49 | #define CH7017_INPUT_DATA_FORMAT 0x1f | ||
| 50 | #define CH7017_CONNECTION_DETECT 0x20 | ||
| 51 | #define CH7017_DAC_CONTROL 0x21 | ||
| 52 | #define CH7017_BUFFERED_CLOCK_OUTPUT 0x22 | ||
| 53 | #define CH7017_DEFEAT_VSYNC 0x47 | ||
| 54 | #define CH7017_TEST_PATTERN 0x48 | ||
| 55 | |||
| 56 | #define CH7017_POWER_MANAGEMENT 0x49 | ||
| 57 | /** Enables the TV output path. */ | ||
| 58 | #define CH7017_TV_EN (1 << 0) | ||
| 59 | #define CH7017_DAC0_POWER_DOWN (1 << 1) | ||
| 60 | #define CH7017_DAC1_POWER_DOWN (1 << 2) | ||
| 61 | #define CH7017_DAC2_POWER_DOWN (1 << 3) | ||
| 62 | #define CH7017_DAC3_POWER_DOWN (1 << 4) | ||
| 63 | /** Powers down the TV out block, and DAC0-3 */ | ||
| 64 | #define CH7017_TV_POWER_DOWN_EN (1 << 5) | ||
| 65 | |||
| 66 | #define CH7017_VERSION_ID 0x4a | ||
| 67 | |||
| 68 | #define CH7017_DEVICE_ID 0x4b | ||
| 69 | #define CH7017_DEVICE_ID_VALUE 0x1b | ||
| 70 | #define CH7018_DEVICE_ID_VALUE 0x1a | ||
| 71 | #define CH7019_DEVICE_ID_VALUE 0x19 | ||
| 72 | |||
| 73 | #define CH7017_XCLK_D2_ADJUST 0x53 | ||
| 74 | #define CH7017_UP_SCALER_COEFF_0 0x55 | ||
| 75 | #define CH7017_UP_SCALER_COEFF_1 0x56 | ||
| 76 | #define CH7017_UP_SCALER_COEFF_2 0x57 | ||
| 77 | #define CH7017_UP_SCALER_COEFF_3 0x58 | ||
| 78 | #define CH7017_UP_SCALER_COEFF_4 0x59 | ||
| 79 | #define CH7017_UP_SCALER_VERTICAL_INC_0 0x5a | ||
| 80 | #define CH7017_UP_SCALER_VERTICAL_INC_1 0x5b | ||
| 81 | #define CH7017_GPIO_INVERT 0x5c | ||
| 82 | #define CH7017_UP_SCALER_HORIZONTAL_INC_0 0x5d | ||
| 83 | #define CH7017_UP_SCALER_HORIZONTAL_INC_1 0x5e | ||
| 84 | |||
| 85 | #define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT 0x5f | ||
| 86 | /**< Low bits of horizontal active pixel input */ | ||
| 87 | |||
| 88 | #define CH7017_ACTIVE_INPUT_LINE_OUTPUT 0x60 | ||
| 89 | /** High bits of horizontal active pixel input */ | ||
| 90 | #define CH7017_LVDS_HAP_INPUT_MASK (0x7 << 0) | ||
| 91 | /** High bits of vertical active line output */ | ||
| 92 | #define CH7017_LVDS_VAL_HIGH_MASK (0x7 << 3) | ||
| 93 | |||
| 94 | #define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT 0x61 | ||
| 95 | /**< Low bits of vertical active line output */ | ||
| 96 | |||
| 97 | #define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT 0x62 | ||
| 98 | /**< Low bits of horizontal active pixel output */ | ||
| 99 | |||
| 100 | #define CH7017_LVDS_POWER_DOWN 0x63 | ||
| 101 | /** High bits of horizontal active pixel output */ | ||
| 102 | #define CH7017_LVDS_HAP_HIGH_MASK (0x7 << 0) | ||
| 103 | /** Enables the LVDS power down state transition */ | ||
| 104 | #define CH7017_LVDS_POWER_DOWN_EN (1 << 6) | ||
| 105 | /** Enables the LVDS upscaler */ | ||
| 106 | #define CH7017_LVDS_UPSCALER_EN (1 << 7) | ||
| 107 | #define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08 | ||
| 108 | |||
| 109 | #define CH7017_LVDS_ENCODING 0x64 | ||
| 110 | #define CH7017_LVDS_DITHER_2D (1 << 2) | ||
| 111 | #define CH7017_LVDS_DITHER_DIS (1 << 3) | ||
| 112 | #define CH7017_LVDS_DUAL_CHANNEL_EN (1 << 4) | ||
| 113 | #define CH7017_LVDS_24_BIT (1 << 5) | ||
| 114 | |||
| 115 | #define CH7017_LVDS_ENCODING_2 0x65 | ||
| 116 | |||
| 117 | #define CH7017_LVDS_PLL_CONTROL 0x66 | ||
| 118 | /** Enables the LVDS panel output path */ | ||
| 119 | #define CH7017_LVDS_PANEN (1 << 0) | ||
| 120 | /** Enables the LVDS panel backlight */ | ||
| 121 | #define CH7017_LVDS_BKLEN (1 << 3) | ||
| 122 | |||
| 123 | #define CH7017_POWER_SEQUENCING_T1 0x67 | ||
| 124 | #define CH7017_POWER_SEQUENCING_T2 0x68 | ||
| 125 | #define CH7017_POWER_SEQUENCING_T3 0x69 | ||
| 126 | #define CH7017_POWER_SEQUENCING_T4 0x6a | ||
| 127 | #define CH7017_POWER_SEQUENCING_T5 0x6b | ||
| 128 | #define CH7017_GPIO_DRIVER_TYPE 0x6c | ||
| 129 | #define CH7017_GPIO_DATA 0x6d | ||
| 130 | #define CH7017_GPIO_DIRECTION_CONTROL 0x6e | ||
| 131 | |||
| 132 | #define CH7017_LVDS_PLL_FEEDBACK_DIV 0x71 | ||
| 133 | # define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4 | ||
| 134 | # define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0 | ||
| 135 | # define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80 | ||
| 136 | |||
| 137 | #define CH7017_LVDS_PLL_VCO_CONTROL 0x72 | ||
| 138 | # define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80 | ||
| 139 | # define CH7017_LVDS_PLL_VCO_SHIFT 4 | ||
| 140 | # define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0 | ||
| 141 | |||
| 142 | #define CH7017_OUTPUTS_ENABLE 0x73 | ||
| 143 | # define CH7017_CHARGE_PUMP_LOW 0x0 | ||
| 144 | # define CH7017_CHARGE_PUMP_HIGH 0x3 | ||
| 145 | # define CH7017_LVDS_CHANNEL_A (1 << 3) | ||
| 146 | # define CH7017_LVDS_CHANNEL_B (1 << 4) | ||
| 147 | # define CH7017_TV_DAC_A (1 << 5) | ||
| 148 | # define CH7017_TV_DAC_B (1 << 6) | ||
| 149 | # define CH7017_DDC_SELECT_DC2 (1 << 7) | ||
| 150 | |||
| 151 | #define CH7017_LVDS_OUTPUT_AMPLITUDE 0x74 | ||
| 152 | #define CH7017_LVDS_PLL_EMI_REDUCTION 0x75 | ||
| 153 | #define CH7017_LVDS_POWER_DOWN_FLICKER 0x76 | ||
| 154 | |||
| 155 | #define CH7017_LVDS_CONTROL_2 0x78 | ||
| 156 | # define CH7017_LOOP_FILTER_SHIFT 5 | ||
| 157 | # define CH7017_PHASE_DETECTOR_SHIFT 0 | ||
| 158 | |||
| 159 | #define CH7017_BANG_LIMIT_CONTROL 0x7f | ||
| 160 | |||
| 161 | struct ch7017_priv { | ||
| 162 | uint8_t save_hapi; | ||
| 163 | uint8_t save_vali; | ||
| 164 | uint8_t save_valo; | ||
| 165 | uint8_t save_ailo; | ||
| 166 | uint8_t save_lvds_pll_vco; | ||
| 167 | uint8_t save_feedback_div; | ||
| 168 | uint8_t save_lvds_control_2; | ||
| 169 | uint8_t save_outputs_enable; | ||
| 170 | uint8_t save_lvds_power_down; | ||
| 171 | uint8_t save_power_management; | ||
| 172 | }; | ||
| 173 | |||
| 174 | static void ch7017_dump_regs(struct intel_dvo_device *dvo); | ||
| 175 | static void ch7017_dpms(struct intel_dvo_device *dvo, int mode); | ||
| 176 | |||
| 177 | static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val) | ||
| 178 | { | ||
| 179 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
| 180 | u8 out_buf[2]; | ||
| 181 | u8 in_buf[2]; | ||
| 182 | |||
| 183 | struct i2c_msg msgs[] = { | ||
| 184 | { | ||
| 185 | .addr = i2cbus->slave_addr, | ||
| 186 | .flags = 0, | ||
| 187 | .len = 1, | ||
| 188 | .buf = out_buf, | ||
| 189 | }, | ||
| 190 | { | ||
| 191 | .addr = i2cbus->slave_addr, | ||
| 192 | .flags = I2C_M_RD, | ||
| 193 | .len = 1, | ||
| 194 | .buf = in_buf, | ||
| 195 | } | ||
| 196 | }; | ||
| 197 | |||
| 198 | out_buf[0] = addr; | ||
| 199 | out_buf[1] = 0; | ||
| 200 | |||
| 201 | if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { | ||
| 202 | *val= in_buf[0]; | ||
| 203 | return true; | ||
| 204 | }; | ||
| 205 | |||
| 206 | return false; | ||
| 207 | } | ||
| 208 | |||
| 209 | static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val) | ||
| 210 | { | ||
| 211 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
| 212 | uint8_t out_buf[2]; | ||
| 213 | struct i2c_msg msg = { | ||
| 214 | .addr = i2cbus->slave_addr, | ||
| 215 | .flags = 0, | ||
| 216 | .len = 2, | ||
| 217 | .buf = out_buf, | ||
| 218 | }; | ||
| 219 | |||
| 220 | out_buf[0] = addr; | ||
| 221 | out_buf[1] = val; | ||
| 222 | |||
| 223 | if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) | ||
| 224 | return true; | ||
| 225 | |||
| 226 | return false; | ||
| 227 | } | ||
| 228 | |||
| 229 | /** Probes for a CH7017 on the given bus and slave address. */ | ||
| 230 | static bool ch7017_init(struct intel_dvo_device *dvo, | ||
| 231 | struct intel_i2c_chan *i2cbus) | ||
| 232 | { | ||
| 233 | struct ch7017_priv *priv; | ||
| 234 | uint8_t val; | ||
| 235 | |||
| 236 | priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL); | ||
| 237 | if (priv == NULL) | ||
| 238 | return false; | ||
| 239 | |||
| 240 | dvo->i2c_bus = i2cbus; | ||
| 241 | dvo->i2c_bus->slave_addr = dvo->slave_addr; | ||
| 242 | dvo->dev_priv = priv; | ||
| 243 | |||
| 244 | if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val)) | ||
| 245 | goto fail; | ||
| 246 | |||
| 247 | if (val != CH7017_DEVICE_ID_VALUE && | ||
| 248 | val != CH7018_DEVICE_ID_VALUE && | ||
| 249 | val != CH7019_DEVICE_ID_VALUE) { | ||
| 250 | DRM_DEBUG("ch701x not detected, got %d: from %s Slave %d.\n", | ||
| 251 | val, i2cbus->adapter.name,i2cbus->slave_addr); | ||
| 252 | goto fail; | ||
| 253 | } | ||
| 254 | |||
| 255 | return true; | ||
| 256 | fail: | ||
| 257 | kfree(priv); | ||
| 258 | return false; | ||
| 259 | } | ||
| 260 | |||
| 261 | static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo) | ||
| 262 | { | ||
| 263 | return connector_status_unknown; | ||
| 264 | } | ||
| 265 | |||
| 266 | static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo, | ||
| 267 | struct drm_display_mode *mode) | ||
| 268 | { | ||
| 269 | if (mode->clock > 160000) | ||
| 270 | return MODE_CLOCK_HIGH; | ||
| 271 | |||
| 272 | return MODE_OK; | ||
| 273 | } | ||
| 274 | |||
| 275 | static void ch7017_mode_set(struct intel_dvo_device *dvo, | ||
| 276 | struct drm_display_mode *mode, | ||
| 277 | struct drm_display_mode *adjusted_mode) | ||
| 278 | { | ||
| 279 | uint8_t lvds_pll_feedback_div, lvds_pll_vco_control; | ||
| 280 | uint8_t outputs_enable, lvds_control_2, lvds_power_down; | ||
| 281 | uint8_t horizontal_active_pixel_input; | ||
| 282 | uint8_t horizontal_active_pixel_output, vertical_active_line_output; | ||
| 283 | uint8_t active_input_line_output; | ||
| 284 | |||
| 285 | DRM_DEBUG("Registers before mode setting\n"); | ||
| 286 | ch7017_dump_regs(dvo); | ||
| 287 | |||
| 288 | /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/ | ||
| 289 | if (mode->clock < 100000) { | ||
| 290 | outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW; | ||
| 291 | lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | | ||
| 292 | (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | | ||
| 293 | (13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); | ||
| 294 | lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | | ||
| 295 | (2 << CH7017_LVDS_PLL_VCO_SHIFT) | | ||
| 296 | (3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); | ||
| 297 | lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) | | ||
| 298 | (0 << CH7017_PHASE_DETECTOR_SHIFT); | ||
| 299 | } else { | ||
| 300 | outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH; | ||
| 301 | lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | | ||
| 302 | (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | | ||
| 303 | (3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); | ||
| 304 | lvds_pll_feedback_div = 35; | ||
| 305 | lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) | | ||
| 306 | (0 << CH7017_PHASE_DETECTOR_SHIFT); | ||
| 307 | if (1) { /* XXX: dual channel panel detection. Assume yes for now. */ | ||
| 308 | outputs_enable |= CH7017_LVDS_CHANNEL_B; | ||
| 309 | lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | | ||
| 310 | (2 << CH7017_LVDS_PLL_VCO_SHIFT) | | ||
| 311 | (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); | ||
| 312 | } else { | ||
| 313 | lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | | ||
| 314 | (1 << CH7017_LVDS_PLL_VCO_SHIFT) | | ||
| 315 | (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | horizontal_active_pixel_input = mode->hdisplay & 0x00ff; | ||
| 320 | |||
| 321 | vertical_active_line_output = mode->vdisplay & 0x00ff; | ||
| 322 | horizontal_active_pixel_output = mode->hdisplay & 0x00ff; | ||
| 323 | |||
| 324 | active_input_line_output = ((mode->hdisplay & 0x0700) >> 8) | | ||
| 325 | (((mode->vdisplay & 0x0700) >> 8) << 3); | ||
| 326 | |||
| 327 | lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED | | ||
| 328 | (mode->hdisplay & 0x0700) >> 8; | ||
| 329 | |||
| 330 | ch7017_dpms(dvo, DRM_MODE_DPMS_OFF); | ||
| 331 | ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, | ||
| 332 | horizontal_active_pixel_input); | ||
| 333 | ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT, | ||
| 334 | horizontal_active_pixel_output); | ||
| 335 | ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, | ||
| 336 | vertical_active_line_output); | ||
| 337 | ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, | ||
| 338 | active_input_line_output); | ||
| 339 | ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control); | ||
| 340 | ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div); | ||
| 341 | ch7017_write(dvo, CH7017_LVDS_CONTROL_2, lvds_control_2); | ||
| 342 | ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, outputs_enable); | ||
| 343 | |||
| 344 | /* Turn the LVDS back on with new settings. */ | ||
| 345 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, lvds_power_down); | ||
| 346 | |||
| 347 | DRM_DEBUG("Registers after mode setting\n"); | ||
| 348 | ch7017_dump_regs(dvo); | ||
| 349 | } | ||
| 350 | |||
| 351 | /* set the CH7017 power state */ | ||
| 352 | static void ch7017_dpms(struct intel_dvo_device *dvo, int mode) | ||
| 353 | { | ||
| 354 | uint8_t val; | ||
| 355 | |||
| 356 | ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val); | ||
| 357 | |||
| 358 | /* Turn off TV/VGA, and never turn it on since we don't support it. */ | ||
| 359 | ch7017_write(dvo, CH7017_POWER_MANAGEMENT, | ||
| 360 | CH7017_DAC0_POWER_DOWN | | ||
| 361 | CH7017_DAC1_POWER_DOWN | | ||
| 362 | CH7017_DAC2_POWER_DOWN | | ||
| 363 | CH7017_DAC3_POWER_DOWN | | ||
| 364 | CH7017_TV_POWER_DOWN_EN); | ||
| 365 | |||
| 366 | if (mode == DRM_MODE_DPMS_ON) { | ||
| 367 | /* Turn on the LVDS */ | ||
| 368 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, | ||
| 369 | val & ~CH7017_LVDS_POWER_DOWN_EN); | ||
| 370 | } else { | ||
| 371 | /* Turn off the LVDS */ | ||
| 372 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, | ||
| 373 | val | CH7017_LVDS_POWER_DOWN_EN); | ||
| 374 | } | ||
| 375 | |||
| 376 | /* XXX: Should actually wait for update power status somehow */ | ||
| 377 | udelay(20000); | ||
| 378 | } | ||
| 379 | |||
| 380 | static void ch7017_dump_regs(struct intel_dvo_device *dvo) | ||
| 381 | { | ||
| 382 | uint8_t val; | ||
| 383 | |||
| 384 | #define DUMP(reg) \ | ||
| 385 | do { \ | ||
| 386 | ch7017_read(dvo, reg, &val); \ | ||
| 387 | DRM_DEBUG(#reg ": %02x\n", val); \ | ||
| 388 | } while (0) | ||
| 389 | |||
| 390 | DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT); | ||
| 391 | DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT); | ||
| 392 | DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT); | ||
| 393 | DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT); | ||
| 394 | DUMP(CH7017_LVDS_PLL_VCO_CONTROL); | ||
| 395 | DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV); | ||
| 396 | DUMP(CH7017_LVDS_CONTROL_2); | ||
| 397 | DUMP(CH7017_OUTPUTS_ENABLE); | ||
| 398 | DUMP(CH7017_LVDS_POWER_DOWN); | ||
| 399 | } | ||
| 400 | |||
| 401 | static void ch7017_save(struct intel_dvo_device *dvo) | ||
| 402 | { | ||
| 403 | struct ch7017_priv *priv = dvo->dev_priv; | ||
| 404 | |||
| 405 | ch7017_read(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, &priv->save_hapi); | ||
| 406 | ch7017_read(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, &priv->save_valo); | ||
| 407 | ch7017_read(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, &priv->save_ailo); | ||
| 408 | ch7017_read(dvo, CH7017_LVDS_PLL_VCO_CONTROL, &priv->save_lvds_pll_vco); | ||
| 409 | ch7017_read(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, &priv->save_feedback_div); | ||
| 410 | ch7017_read(dvo, CH7017_LVDS_CONTROL_2, &priv->save_lvds_control_2); | ||
| 411 | ch7017_read(dvo, CH7017_OUTPUTS_ENABLE, &priv->save_outputs_enable); | ||
| 412 | ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &priv->save_lvds_power_down); | ||
| 413 | ch7017_read(dvo, CH7017_POWER_MANAGEMENT, &priv->save_power_management); | ||
| 414 | } | ||
| 415 | |||
| 416 | static void ch7017_restore(struct intel_dvo_device *dvo) | ||
| 417 | { | ||
| 418 | struct ch7017_priv *priv = dvo->dev_priv; | ||
| 419 | |||
| 420 | /* Power down before changing mode */ | ||
| 421 | ch7017_dpms(dvo, DRM_MODE_DPMS_OFF); | ||
| 422 | |||
| 423 | ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, priv->save_hapi); | ||
| 424 | ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, priv->save_valo); | ||
| 425 | ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, priv->save_ailo); | ||
| 426 | ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, priv->save_lvds_pll_vco); | ||
| 427 | ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, priv->save_feedback_div); | ||
| 428 | ch7017_write(dvo, CH7017_LVDS_CONTROL_2, priv->save_lvds_control_2); | ||
| 429 | ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, priv->save_outputs_enable); | ||
| 430 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, priv->save_lvds_power_down); | ||
| 431 | ch7017_write(dvo, CH7017_POWER_MANAGEMENT, priv->save_power_management); | ||
| 432 | } | ||
| 433 | |||
| 434 | static void ch7017_destroy(struct intel_dvo_device *dvo) | ||
| 435 | { | ||
| 436 | struct ch7017_priv *priv = dvo->dev_priv; | ||
| 437 | |||
| 438 | if (priv) { | ||
| 439 | kfree(priv); | ||
| 440 | dvo->dev_priv = NULL; | ||
| 441 | } | ||
| 442 | } | ||
| 443 | |||
| 444 | struct intel_dvo_dev_ops ch7017_ops = { | ||
| 445 | .init = ch7017_init, | ||
| 446 | .detect = ch7017_detect, | ||
| 447 | .mode_valid = ch7017_mode_valid, | ||
| 448 | .mode_set = ch7017_mode_set, | ||
| 449 | .dpms = ch7017_dpms, | ||
| 450 | .dump_regs = ch7017_dump_regs, | ||
| 451 | .save = ch7017_save, | ||
| 452 | .restore = ch7017_restore, | ||
| 453 | .destroy = ch7017_destroy, | ||
| 454 | }; | ||
diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c new file mode 100644 index 000000000000..d2fd95dbd034 --- /dev/null +++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c | |||
| @@ -0,0 +1,368 @@ | |||
| 1 | /************************************************************************** | ||
| 2 | |||
| 3 | Copyright © 2006 Dave Airlie | ||
| 4 | |||
| 5 | All Rights Reserved. | ||
| 6 | |||
| 7 | Permission is hereby granted, free of charge, to any person obtaining a | ||
| 8 | copy of this software and associated documentation files (the | ||
| 9 | "Software"), to deal in the Software without restriction, including | ||
| 10 | without limitation the rights to use, copy, modify, merge, publish, | ||
| 11 | distribute, sub license, and/or sell copies of the Software, and to | ||
| 12 | permit persons to whom the Software is furnished to do so, subject to | ||
| 13 | the following conditions: | ||
| 14 | |||
| 15 | The above copyright notice and this permission notice (including the | ||
| 16 | next paragraph) shall be included in all copies or substantial portions | ||
| 17 | of the Software. | ||
| 18 | |||
| 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| 20 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. | ||
| 22 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 23 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
| 24 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
| 25 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 26 | |||
| 27 | **************************************************************************/ | ||
| 28 | |||
| 29 | #include "dvo.h" | ||
| 30 | |||
| 31 | #define CH7xxx_REG_VID 0x4a | ||
| 32 | #define CH7xxx_REG_DID 0x4b | ||
| 33 | |||
| 34 | #define CH7011_VID 0x83 /* 7010 as well */ | ||
| 35 | #define CH7009A_VID 0x84 | ||
| 36 | #define CH7009B_VID 0x85 | ||
| 37 | #define CH7301_VID 0x95 | ||
| 38 | |||
| 39 | #define CH7xxx_VID 0x84 | ||
| 40 | #define CH7xxx_DID 0x17 | ||
| 41 | |||
| 42 | #define CH7xxx_NUM_REGS 0x4c | ||
| 43 | |||
| 44 | #define CH7xxx_CM 0x1c | ||
| 45 | #define CH7xxx_CM_XCM (1<<0) | ||
| 46 | #define CH7xxx_CM_MCP (1<<2) | ||
| 47 | #define CH7xxx_INPUT_CLOCK 0x1d | ||
| 48 | #define CH7xxx_GPIO 0x1e | ||
| 49 | #define CH7xxx_GPIO_HPIR (1<<3) | ||
| 50 | #define CH7xxx_IDF 0x1f | ||
| 51 | |||
| 52 | #define CH7xxx_IDF_HSP (1<<3) | ||
| 53 | #define CH7xxx_IDF_VSP (1<<4) | ||
| 54 | |||
| 55 | #define CH7xxx_CONNECTION_DETECT 0x20 | ||
| 56 | #define CH7xxx_CDET_DVI (1<<5) | ||
| 57 | |||
| 58 | #define CH7301_DAC_CNTL 0x21 | ||
| 59 | #define CH7301_HOTPLUG 0x23 | ||
| 60 | #define CH7xxx_TCTL 0x31 | ||
| 61 | #define CH7xxx_TVCO 0x32 | ||
| 62 | #define CH7xxx_TPCP 0x33 | ||
| 63 | #define CH7xxx_TPD 0x34 | ||
| 64 | #define CH7xxx_TPVT 0x35 | ||
| 65 | #define CH7xxx_TLPF 0x36 | ||
| 66 | #define CH7xxx_TCT 0x37 | ||
| 67 | #define CH7301_TEST_PATTERN 0x48 | ||
| 68 | |||
| 69 | #define CH7xxx_PM 0x49 | ||
| 70 | #define CH7xxx_PM_FPD (1<<0) | ||
| 71 | #define CH7301_PM_DACPD0 (1<<1) | ||
| 72 | #define CH7301_PM_DACPD1 (1<<2) | ||
| 73 | #define CH7301_PM_DACPD2 (1<<3) | ||
| 74 | #define CH7xxx_PM_DVIL (1<<6) | ||
| 75 | #define CH7xxx_PM_DVIP (1<<7) | ||
| 76 | |||
| 77 | #define CH7301_SYNC_POLARITY 0x56 | ||
| 78 | #define CH7301_SYNC_RGB_YUV (1<<0) | ||
| 79 | #define CH7301_SYNC_POL_DVI (1<<5) | ||
| 80 | |||
| 81 | /** @file | ||
| 82 | * driver for the Chrontel 7xxx DVI chip over DVO. | ||
| 83 | */ | ||
| 84 | |||
| 85 | static struct ch7xxx_id_struct { | ||
| 86 | uint8_t vid; | ||
| 87 | char *name; | ||
| 88 | } ch7xxx_ids[] = { | ||
| 89 | { CH7011_VID, "CH7011" }, | ||
| 90 | { CH7009A_VID, "CH7009A" }, | ||
| 91 | { CH7009B_VID, "CH7009B" }, | ||
| 92 | { CH7301_VID, "CH7301" }, | ||
| 93 | }; | ||
| 94 | |||
| 95 | struct ch7xxx_reg_state { | ||
| 96 | uint8_t regs[CH7xxx_NUM_REGS]; | ||
| 97 | }; | ||
| 98 | |||
| 99 | struct ch7xxx_priv { | ||
| 100 | bool quiet; | ||
| 101 | |||
| 102 | struct ch7xxx_reg_state save_reg; | ||
| 103 | struct ch7xxx_reg_state mode_reg; | ||
| 104 | uint8_t save_TCTL, save_TPCP, save_TPD, save_TPVT; | ||
| 105 | uint8_t save_TLPF, save_TCT, save_PM, save_IDF; | ||
| 106 | }; | ||
| 107 | |||
| 108 | static void ch7xxx_save(struct intel_dvo_device *dvo); | ||
| 109 | |||
| 110 | static char *ch7xxx_get_id(uint8_t vid) | ||
| 111 | { | ||
| 112 | int i; | ||
| 113 | |||
| 114 | for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) { | ||
| 115 | if (ch7xxx_ids[i].vid == vid) | ||
| 116 | return ch7xxx_ids[i].name; | ||
| 117 | } | ||
| 118 | |||
| 119 | return NULL; | ||
| 120 | } | ||
| 121 | |||
| 122 | /** Reads an 8 bit register */ | ||
| 123 | static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) | ||
| 124 | { | ||
| 125 | struct ch7xxx_priv *ch7xxx= dvo->dev_priv; | ||
| 126 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
| 127 | u8 out_buf[2]; | ||
| 128 | u8 in_buf[2]; | ||
| 129 | |||
| 130 | struct i2c_msg msgs[] = { | ||
| 131 | { | ||
| 132 | .addr = i2cbus->slave_addr, | ||
| 133 | .flags = 0, | ||
| 134 | .len = 1, | ||
| 135 | .buf = out_buf, | ||
| 136 | }, | ||
| 137 | { | ||
| 138 | .addr = i2cbus->slave_addr, | ||
| 139 | .flags = I2C_M_RD, | ||
| 140 | .len = 1, | ||
| 141 | .buf = in_buf, | ||
| 142 | } | ||
| 143 | }; | ||
| 144 | |||
| 145 | out_buf[0] = addr; | ||
| 146 | out_buf[1] = 0; | ||
| 147 | |||
| 148 | if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { | ||
| 149 | *ch = in_buf[0]; | ||
| 150 | return true; | ||
| 151 | }; | ||
| 152 | |||
| 153 | if (!ch7xxx->quiet) { | ||
| 154 | DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", | ||
| 155 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
| 156 | } | ||
| 157 | return false; | ||
| 158 | } | ||
| 159 | |||
| 160 | /** Writes an 8 bit register */ | ||
| 161 | static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) | ||
| 162 | { | ||
| 163 | struct ch7xxx_priv *ch7xxx = dvo->dev_priv; | ||
| 164 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
| 165 | uint8_t out_buf[2]; | ||
| 166 | struct i2c_msg msg = { | ||
| 167 | .addr = i2cbus->slave_addr, | ||
| 168 | .flags = 0, | ||
| 169 | .len = 2, | ||
| 170 | .buf = out_buf, | ||
| 171 | }; | ||
| 172 | |||
| 173 | out_buf[0] = addr; | ||
| 174 | out_buf[1] = ch; | ||
| 175 | |||
| 176 | if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) | ||
| 177 | return true; | ||
| 178 | |||
| 179 | if (!ch7xxx->quiet) { | ||
| 180 | DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", | ||
| 181 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
| 182 | } | ||
| 183 | |||
| 184 | return false; | ||
| 185 | } | ||
| 186 | |||
| 187 | static bool ch7xxx_init(struct intel_dvo_device *dvo, | ||
| 188 | struct intel_i2c_chan *i2cbus) | ||
| 189 | { | ||
| 190 | /* this will detect the CH7xxx chip on the specified i2c bus */ | ||
| 191 | struct ch7xxx_priv *ch7xxx; | ||
| 192 | uint8_t vendor, device; | ||
| 193 | char *name; | ||
| 194 | |||
| 195 | ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL); | ||
| 196 | if (ch7xxx == NULL) | ||
| 197 | return false; | ||
| 198 | |||
| 199 | dvo->i2c_bus = i2cbus; | ||
| 200 | dvo->i2c_bus->slave_addr = dvo->slave_addr; | ||
| 201 | dvo->dev_priv = ch7xxx; | ||
| 202 | ch7xxx->quiet = true; | ||
| 203 | |||
| 204 | if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor)) | ||
| 205 | goto out; | ||
| 206 | |||
| 207 | name = ch7xxx_get_id(vendor); | ||
| 208 | if (!name) { | ||
| 209 | DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n", | ||
| 210 | vendor, i2cbus->adapter.name, i2cbus->slave_addr); | ||
| 211 | goto out; | ||
| 212 | } | ||
| 213 | |||
| 214 | |||
| 215 | if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device)) | ||
| 216 | goto out; | ||
| 217 | |||
| 218 | if (device != CH7xxx_DID) { | ||
| 219 | DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n", | ||
| 220 | vendor, i2cbus->adapter.name, i2cbus->slave_addr); | ||
| 221 | goto out; | ||
| 222 | } | ||
| 223 | |||
| 224 | ch7xxx->quiet = false; | ||
| 225 | DRM_DEBUG("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n", | ||
| 226 | name, vendor, device); | ||
| 227 | return true; | ||
| 228 | out: | ||
| 229 | kfree(ch7xxx); | ||
| 230 | return false; | ||
| 231 | } | ||
| 232 | |||
| 233 | static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo) | ||
| 234 | { | ||
| 235 | uint8_t cdet, orig_pm, pm; | ||
| 236 | |||
| 237 | ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm); | ||
| 238 | |||
| 239 | pm = orig_pm; | ||
| 240 | pm &= ~CH7xxx_PM_FPD; | ||
| 241 | pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP; | ||
| 242 | |||
| 243 | ch7xxx_writeb(dvo, CH7xxx_PM, pm); | ||
| 244 | |||
| 245 | ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet); | ||
| 246 | |||
| 247 | ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm); | ||
| 248 | |||
| 249 | if (cdet & CH7xxx_CDET_DVI) | ||
| 250 | return connector_status_connected; | ||
| 251 | return connector_status_disconnected; | ||
| 252 | } | ||
| 253 | |||
| 254 | static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo, | ||
| 255 | struct drm_display_mode *mode) | ||
| 256 | { | ||
| 257 | if (mode->clock > 165000) | ||
| 258 | return MODE_CLOCK_HIGH; | ||
| 259 | |||
| 260 | return MODE_OK; | ||
| 261 | } | ||
| 262 | |||
| 263 | static void ch7xxx_mode_set(struct intel_dvo_device *dvo, | ||
| 264 | struct drm_display_mode *mode, | ||
| 265 | struct drm_display_mode *adjusted_mode) | ||
| 266 | { | ||
| 267 | uint8_t tvco, tpcp, tpd, tlpf, idf; | ||
| 268 | |||
| 269 | if (mode->clock <= 65000) { | ||
| 270 | tvco = 0x23; | ||
| 271 | tpcp = 0x08; | ||
| 272 | tpd = 0x16; | ||
| 273 | tlpf = 0x60; | ||
| 274 | } else { | ||
| 275 | tvco = 0x2d; | ||
| 276 | tpcp = 0x06; | ||
| 277 | tpd = 0x26; | ||
| 278 | tlpf = 0xa0; | ||
| 279 | } | ||
| 280 | |||
| 281 | ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00); | ||
| 282 | ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco); | ||
| 283 | ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp); | ||
| 284 | ch7xxx_writeb(dvo, CH7xxx_TPD, tpd); | ||
| 285 | ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30); | ||
| 286 | ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf); | ||
| 287 | ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00); | ||
| 288 | |||
| 289 | ch7xxx_readb(dvo, CH7xxx_IDF, &idf); | ||
| 290 | |||
| 291 | idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP); | ||
| 292 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
| 293 | idf |= CH7xxx_IDF_HSP; | ||
| 294 | |||
| 295 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
| 296 | idf |= CH7xxx_IDF_HSP; | ||
| 297 | |||
| 298 | ch7xxx_writeb(dvo, CH7xxx_IDF, idf); | ||
| 299 | } | ||
| 300 | |||
| 301 | /* set the CH7xxx power state */ | ||
| 302 | static void ch7xxx_dpms(struct intel_dvo_device *dvo, int mode) | ||
| 303 | { | ||
| 304 | if (mode == DRM_MODE_DPMS_ON) | ||
| 305 | ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP); | ||
| 306 | else | ||
| 307 | ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD); | ||
| 308 | } | ||
| 309 | |||
| 310 | static void ch7xxx_dump_regs(struct intel_dvo_device *dvo) | ||
| 311 | { | ||
| 312 | struct ch7xxx_priv *ch7xxx = dvo->dev_priv; | ||
| 313 | int i; | ||
| 314 | |||
| 315 | for (i = 0; i < CH7xxx_NUM_REGS; i++) { | ||
| 316 | if ((i % 8) == 0 ) | ||
| 317 | DRM_DEBUG("\n %02X: ", i); | ||
| 318 | DRM_DEBUG("%02X ", ch7xxx->mode_reg.regs[i]); | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | static void ch7xxx_save(struct intel_dvo_device *dvo) | ||
| 323 | { | ||
| 324 | struct ch7xxx_priv *ch7xxx= dvo->dev_priv; | ||
| 325 | |||
| 326 | ch7xxx_readb(dvo, CH7xxx_TCTL, &ch7xxx->save_TCTL); | ||
| 327 | ch7xxx_readb(dvo, CH7xxx_TPCP, &ch7xxx->save_TPCP); | ||
| 328 | ch7xxx_readb(dvo, CH7xxx_TPD, &ch7xxx->save_TPD); | ||
| 329 | ch7xxx_readb(dvo, CH7xxx_TPVT, &ch7xxx->save_TPVT); | ||
| 330 | ch7xxx_readb(dvo, CH7xxx_TLPF, &ch7xxx->save_TLPF); | ||
| 331 | ch7xxx_readb(dvo, CH7xxx_PM, &ch7xxx->save_PM); | ||
| 332 | ch7xxx_readb(dvo, CH7xxx_IDF, &ch7xxx->save_IDF); | ||
| 333 | } | ||
| 334 | |||
| 335 | static void ch7xxx_restore(struct intel_dvo_device *dvo) | ||
| 336 | { | ||
| 337 | struct ch7xxx_priv *ch7xxx = dvo->dev_priv; | ||
| 338 | |||
| 339 | ch7xxx_writeb(dvo, CH7xxx_TCTL, ch7xxx->save_TCTL); | ||
| 340 | ch7xxx_writeb(dvo, CH7xxx_TPCP, ch7xxx->save_TPCP); | ||
| 341 | ch7xxx_writeb(dvo, CH7xxx_TPD, ch7xxx->save_TPD); | ||
| 342 | ch7xxx_writeb(dvo, CH7xxx_TPVT, ch7xxx->save_TPVT); | ||
| 343 | ch7xxx_writeb(dvo, CH7xxx_TLPF, ch7xxx->save_TLPF); | ||
| 344 | ch7xxx_writeb(dvo, CH7xxx_IDF, ch7xxx->save_IDF); | ||
| 345 | ch7xxx_writeb(dvo, CH7xxx_PM, ch7xxx->save_PM); | ||
| 346 | } | ||
| 347 | |||
| 348 | static void ch7xxx_destroy(struct intel_dvo_device *dvo) | ||
| 349 | { | ||
| 350 | struct ch7xxx_priv *ch7xxx = dvo->dev_priv; | ||
| 351 | |||
| 352 | if (ch7xxx) { | ||
| 353 | kfree(ch7xxx); | ||
| 354 | dvo->dev_priv = NULL; | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | struct intel_dvo_dev_ops ch7xxx_ops = { | ||
| 359 | .init = ch7xxx_init, | ||
| 360 | .detect = ch7xxx_detect, | ||
| 361 | .mode_valid = ch7xxx_mode_valid, | ||
| 362 | .mode_set = ch7xxx_mode_set, | ||
| 363 | .dpms = ch7xxx_dpms, | ||
| 364 | .dump_regs = ch7xxx_dump_regs, | ||
| 365 | .save = ch7xxx_save, | ||
| 366 | .restore = ch7xxx_restore, | ||
| 367 | .destroy = ch7xxx_destroy, | ||
| 368 | }; | ||
diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c new file mode 100644 index 000000000000..0c8d375e8e37 --- /dev/null +++ b/drivers/gpu/drm/i915/dvo_ivch.c | |||
| @@ -0,0 +1,442 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2006 Intel Corporation | ||
| 3 | * | ||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 5 | * copy of this software and associated documentation files (the "Software"), | ||
| 6 | * to deal in the Software without restriction, including without limitation | ||
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 9 | * Software is furnished to do so, subject to the following conditions: | ||
| 10 | * | ||
| 11 | * The above copyright notice and this permission notice (including the next | ||
| 12 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 13 | * Software. | ||
| 14 | * | ||
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 21 | * DEALINGS IN THE SOFTWARE. | ||
| 22 | * | ||
| 23 | * Authors: | ||
| 24 | * Eric Anholt <eric@anholt.net> | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include "dvo.h" | ||
| 29 | |||
| 30 | /* | ||
| 31 | * register definitions for the i82807aa. | ||
| 32 | * | ||
| 33 | * Documentation on this chipset can be found in datasheet #29069001 at | ||
| 34 | * intel.com. | ||
| 35 | */ | ||
| 36 | |||
| 37 | /* | ||
| 38 | * VCH Revision & GMBus Base Addr | ||
| 39 | */ | ||
| 40 | #define VR00 0x00 | ||
| 41 | # define VR00_BASE_ADDRESS_MASK 0x007f | ||
| 42 | |||
| 43 | /* | ||
| 44 | * Functionality Enable | ||
| 45 | */ | ||
| 46 | #define VR01 0x01 | ||
| 47 | |||
| 48 | /* | ||
| 49 | * Enable the panel fitter | ||
| 50 | */ | ||
| 51 | # define VR01_PANEL_FIT_ENABLE (1 << 3) | ||
| 52 | /* | ||
| 53 | * Enables the LCD display. | ||
| 54 | * | ||
| 55 | * This must not be set while VR01_DVO_BYPASS_ENABLE is set. | ||
| 56 | */ | ||
| 57 | # define VR01_LCD_ENABLE (1 << 2) | ||
| 58 | /** Enables the DVO repeater. */ | ||
| 59 | # define VR01_DVO_BYPASS_ENABLE (1 << 1) | ||
| 60 | /** Enables the DVO clock */ | ||
| 61 | # define VR01_DVO_ENABLE (1 << 0) | ||
| 62 | |||
| 63 | /* | ||
| 64 | * LCD Interface Format | ||
| 65 | */ | ||
| 66 | #define VR10 0x10 | ||
| 67 | /** Enables LVDS output instead of CMOS */ | ||
| 68 | # define VR10_LVDS_ENABLE (1 << 4) | ||
| 69 | /** Enables 18-bit LVDS output. */ | ||
| 70 | # define VR10_INTERFACE_1X18 (0 << 2) | ||
| 71 | /** Enables 24-bit LVDS or CMOS output */ | ||
| 72 | # define VR10_INTERFACE_1X24 (1 << 2) | ||
| 73 | /** Enables 2x18-bit LVDS or CMOS output. */ | ||
| 74 | # define VR10_INTERFACE_2X18 (2 << 2) | ||
| 75 | /** Enables 2x24-bit LVDS output */ | ||
| 76 | # define VR10_INTERFACE_2X24 (3 << 2) | ||
| 77 | |||
| 78 | /* | ||
| 79 | * VR20 LCD Horizontal Display Size | ||
| 80 | */ | ||
| 81 | #define VR20 0x20 | ||
| 82 | |||
| 83 | /* | ||
| 84 | * LCD Vertical Display Size | ||
| 85 | */ | ||
| 86 | #define VR21 0x20 | ||
| 87 | |||
| 88 | /* | ||
| 89 | * Panel power down status | ||
| 90 | */ | ||
| 91 | #define VR30 0x30 | ||
| 92 | /** Read only bit indicating that the panel is not in a safe poweroff state. */ | ||
| 93 | # define VR30_PANEL_ON (1 << 15) | ||
| 94 | |||
| 95 | #define VR40 0x40 | ||
| 96 | # define VR40_STALL_ENABLE (1 << 13) | ||
| 97 | # define VR40_VERTICAL_INTERP_ENABLE (1 << 12) | ||
| 98 | # define VR40_ENHANCED_PANEL_FITTING (1 << 11) | ||
| 99 | # define VR40_HORIZONTAL_INTERP_ENABLE (1 << 10) | ||
| 100 | # define VR40_AUTO_RATIO_ENABLE (1 << 9) | ||
| 101 | # define VR40_CLOCK_GATING_ENABLE (1 << 8) | ||
| 102 | |||
| 103 | /* | ||
| 104 | * Panel Fitting Vertical Ratio | ||
| 105 | * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2 | ||
| 106 | */ | ||
| 107 | #define VR41 0x41 | ||
| 108 | |||
| 109 | /* | ||
| 110 | * Panel Fitting Horizontal Ratio | ||
| 111 | * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2 | ||
| 112 | */ | ||
| 113 | #define VR42 0x42 | ||
| 114 | |||
| 115 | /* | ||
| 116 | * Horizontal Image Size | ||
| 117 | */ | ||
| 118 | #define VR43 0x43 | ||
| 119 | |||
| 120 | /* VR80 GPIO 0 | ||
| 121 | */ | ||
| 122 | #define VR80 0x80 | ||
| 123 | #define VR81 0x81 | ||
| 124 | #define VR82 0x82 | ||
| 125 | #define VR83 0x83 | ||
| 126 | #define VR84 0x84 | ||
| 127 | #define VR85 0x85 | ||
| 128 | #define VR86 0x86 | ||
| 129 | #define VR87 0x87 | ||
| 130 | |||
| 131 | /* VR88 GPIO 8 | ||
| 132 | */ | ||
| 133 | #define VR88 0x88 | ||
| 134 | |||
| 135 | /* Graphics BIOS scratch 0 | ||
| 136 | */ | ||
| 137 | #define VR8E 0x8E | ||
| 138 | # define VR8E_PANEL_TYPE_MASK (0xf << 0) | ||
| 139 | # define VR8E_PANEL_INTERFACE_CMOS (0 << 4) | ||
| 140 | # define VR8E_PANEL_INTERFACE_LVDS (1 << 4) | ||
| 141 | # define VR8E_FORCE_DEFAULT_PANEL (1 << 5) | ||
| 142 | |||
| 143 | /* Graphics BIOS scratch 1 | ||
| 144 | */ | ||
| 145 | #define VR8F 0x8F | ||
| 146 | # define VR8F_VCH_PRESENT (1 << 0) | ||
| 147 | # define VR8F_DISPLAY_CONN (1 << 1) | ||
| 148 | # define VR8F_POWER_MASK (0x3c) | ||
| 149 | # define VR8F_POWER_POS (2) | ||
| 150 | |||
| 151 | |||
| 152 | struct ivch_priv { | ||
| 153 | bool quiet; | ||
| 154 | |||
| 155 | uint16_t width, height; | ||
| 156 | |||
| 157 | uint16_t save_VR01; | ||
| 158 | uint16_t save_VR40; | ||
| 159 | }; | ||
| 160 | |||
| 161 | |||
| 162 | static void ivch_dump_regs(struct intel_dvo_device *dvo); | ||
| 163 | |||
| 164 | /** | ||
| 165 | * Reads a register on the ivch. | ||
| 166 | * | ||
| 167 | * Each of the 256 registers are 16 bits long. | ||
| 168 | */ | ||
| 169 | static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) | ||
| 170 | { | ||
| 171 | struct ivch_priv *priv = dvo->dev_priv; | ||
| 172 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
| 173 | u8 out_buf[1]; | ||
| 174 | u8 in_buf[2]; | ||
| 175 | |||
| 176 | struct i2c_msg msgs[] = { | ||
| 177 | { | ||
| 178 | .addr = i2cbus->slave_addr, | ||
| 179 | .flags = I2C_M_RD, | ||
| 180 | .len = 0, | ||
| 181 | }, | ||
| 182 | { | ||
| 183 | .addr = 0, | ||
| 184 | .flags = I2C_M_NOSTART, | ||
| 185 | .len = 1, | ||
| 186 | .buf = out_buf, | ||
| 187 | }, | ||
| 188 | { | ||
| 189 | .addr = i2cbus->slave_addr, | ||
| 190 | .flags = I2C_M_RD | I2C_M_NOSTART, | ||
| 191 | .len = 2, | ||
| 192 | .buf = in_buf, | ||
| 193 | } | ||
| 194 | }; | ||
| 195 | |||
| 196 | out_buf[0] = addr; | ||
| 197 | |||
| 198 | if (i2c_transfer(&i2cbus->adapter, msgs, 3) == 3) { | ||
| 199 | *data = (in_buf[1] << 8) | in_buf[0]; | ||
| 200 | return true; | ||
| 201 | }; | ||
| 202 | |||
| 203 | if (!priv->quiet) { | ||
| 204 | DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", | ||
| 205 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
| 206 | } | ||
| 207 | return false; | ||
| 208 | } | ||
| 209 | |||
| 210 | /** Writes a 16-bit register on the ivch */ | ||
| 211 | static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data) | ||
| 212 | { | ||
| 213 | struct ivch_priv *priv = dvo->dev_priv; | ||
| 214 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
| 215 | u8 out_buf[3]; | ||
| 216 | struct i2c_msg msg = { | ||
| 217 | .addr = i2cbus->slave_addr, | ||
| 218 | .flags = 0, | ||
| 219 | .len = 3, | ||
| 220 | .buf = out_buf, | ||
| 221 | }; | ||
| 222 | |||
| 223 | out_buf[0] = addr; | ||
| 224 | out_buf[1] = data & 0xff; | ||
| 225 | out_buf[2] = data >> 8; | ||
| 226 | |||
| 227 | if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) | ||
| 228 | return true; | ||
| 229 | |||
| 230 | if (!priv->quiet) { | ||
| 231 | DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", | ||
| 232 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
| 233 | } | ||
| 234 | |||
| 235 | return false; | ||
| 236 | } | ||
| 237 | |||
| 238 | /** Probes the given bus and slave address for an ivch */ | ||
| 239 | static bool ivch_init(struct intel_dvo_device *dvo, | ||
| 240 | struct intel_i2c_chan *i2cbus) | ||
| 241 | { | ||
| 242 | struct ivch_priv *priv; | ||
| 243 | uint16_t temp; | ||
| 244 | |||
| 245 | priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL); | ||
| 246 | if (priv == NULL) | ||
| 247 | return false; | ||
| 248 | |||
| 249 | dvo->i2c_bus = i2cbus; | ||
| 250 | dvo->i2c_bus->slave_addr = dvo->slave_addr; | ||
| 251 | dvo->dev_priv = priv; | ||
| 252 | priv->quiet = true; | ||
| 253 | |||
| 254 | if (!ivch_read(dvo, VR00, &temp)) | ||
| 255 | goto out; | ||
| 256 | priv->quiet = false; | ||
| 257 | |||
| 258 | /* Since the identification bits are probably zeroes, which doesn't seem | ||
| 259 | * very unique, check that the value in the base address field matches | ||
| 260 | * the address it's responding on. | ||
| 261 | */ | ||
| 262 | if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) { | ||
| 263 | DRM_DEBUG("ivch detect failed due to address mismatch " | ||
| 264 | "(%d vs %d)\n", | ||
| 265 | (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr); | ||
| 266 | goto out; | ||
| 267 | } | ||
| 268 | |||
| 269 | ivch_read(dvo, VR20, &priv->width); | ||
| 270 | ivch_read(dvo, VR21, &priv->height); | ||
| 271 | |||
| 272 | return true; | ||
| 273 | |||
| 274 | out: | ||
| 275 | kfree(priv); | ||
| 276 | return false; | ||
| 277 | } | ||
| 278 | |||
| 279 | static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo) | ||
| 280 | { | ||
| 281 | return connector_status_connected; | ||
| 282 | } | ||
| 283 | |||
| 284 | static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo, | ||
| 285 | struct drm_display_mode *mode) | ||
| 286 | { | ||
| 287 | if (mode->clock > 112000) | ||
| 288 | return MODE_CLOCK_HIGH; | ||
| 289 | |||
| 290 | return MODE_OK; | ||
| 291 | } | ||
| 292 | |||
| 293 | /** Sets the power state of the panel connected to the ivch */ | ||
| 294 | static void ivch_dpms(struct intel_dvo_device *dvo, int mode) | ||
| 295 | { | ||
| 296 | int i; | ||
| 297 | uint16_t vr01, vr30, backlight; | ||
| 298 | |||
| 299 | /* Set the new power state of the panel. */ | ||
| 300 | if (!ivch_read(dvo, VR01, &vr01)) | ||
| 301 | return; | ||
| 302 | |||
| 303 | if (mode == DRM_MODE_DPMS_ON) | ||
| 304 | backlight = 1; | ||
| 305 | else | ||
| 306 | backlight = 0; | ||
| 307 | ivch_write(dvo, VR80, backlight); | ||
| 308 | |||
| 309 | if (mode == DRM_MODE_DPMS_ON) | ||
| 310 | vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE; | ||
| 311 | else | ||
| 312 | vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE); | ||
| 313 | |||
| 314 | ivch_write(dvo, VR01, vr01); | ||
| 315 | |||
| 316 | /* Wait for the panel to make its state transition */ | ||
| 317 | for (i = 0; i < 100; i++) { | ||
| 318 | if (!ivch_read(dvo, VR30, &vr30)) | ||
| 319 | break; | ||
| 320 | |||
| 321 | if (((vr30 & VR30_PANEL_ON) != 0) == (mode == DRM_MODE_DPMS_ON)) | ||
| 322 | break; | ||
| 323 | udelay(1000); | ||
| 324 | } | ||
| 325 | /* wait some more; vch may fail to resync sometimes without this */ | ||
| 326 | udelay(16 * 1000); | ||
| 327 | } | ||
| 328 | |||
| 329 | static void ivch_mode_set(struct intel_dvo_device *dvo, | ||
| 330 | struct drm_display_mode *mode, | ||
| 331 | struct drm_display_mode *adjusted_mode) | ||
| 332 | { | ||
| 333 | uint16_t vr40 = 0; | ||
| 334 | uint16_t vr01; | ||
| 335 | |||
| 336 | vr01 = 0; | ||
| 337 | vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE | | ||
| 338 | VR40_HORIZONTAL_INTERP_ENABLE); | ||
| 339 | |||
| 340 | if (mode->hdisplay != adjusted_mode->hdisplay || | ||
| 341 | mode->vdisplay != adjusted_mode->vdisplay) { | ||
| 342 | uint16_t x_ratio, y_ratio; | ||
| 343 | |||
| 344 | vr01 |= VR01_PANEL_FIT_ENABLE; | ||
| 345 | vr40 |= VR40_CLOCK_GATING_ENABLE; | ||
| 346 | x_ratio = (((mode->hdisplay - 1) << 16) / | ||
| 347 | (adjusted_mode->hdisplay - 1)) >> 2; | ||
| 348 | y_ratio = (((mode->vdisplay - 1) << 16) / | ||
| 349 | (adjusted_mode->vdisplay - 1)) >> 2; | ||
| 350 | ivch_write (dvo, VR42, x_ratio); | ||
| 351 | ivch_write (dvo, VR41, y_ratio); | ||
| 352 | } else { | ||
| 353 | vr01 &= ~VR01_PANEL_FIT_ENABLE; | ||
| 354 | vr40 &= ~VR40_CLOCK_GATING_ENABLE; | ||
| 355 | } | ||
| 356 | vr40 &= ~VR40_AUTO_RATIO_ENABLE; | ||
| 357 | |||
| 358 | ivch_write(dvo, VR01, vr01); | ||
| 359 | ivch_write(dvo, VR40, vr40); | ||
| 360 | |||
| 361 | ivch_dump_regs(dvo); | ||
| 362 | } | ||
| 363 | |||
| 364 | static void ivch_dump_regs(struct intel_dvo_device *dvo) | ||
| 365 | { | ||
| 366 | uint16_t val; | ||
| 367 | |||
| 368 | ivch_read(dvo, VR00, &val); | ||
| 369 | DRM_DEBUG("VR00: 0x%04x\n", val); | ||
| 370 | ivch_read(dvo, VR01, &val); | ||
| 371 | DRM_DEBUG("VR01: 0x%04x\n", val); | ||
| 372 | ivch_read(dvo, VR30, &val); | ||
| 373 | DRM_DEBUG("VR30: 0x%04x\n", val); | ||
| 374 | ivch_read(dvo, VR40, &val); | ||
| 375 | DRM_DEBUG("VR40: 0x%04x\n", val); | ||
| 376 | |||
| 377 | /* GPIO registers */ | ||
| 378 | ivch_read(dvo, VR80, &val); | ||
| 379 | DRM_DEBUG("VR80: 0x%04x\n", val); | ||
| 380 | ivch_read(dvo, VR81, &val); | ||
| 381 | DRM_DEBUG("VR81: 0x%04x\n", val); | ||
| 382 | ivch_read(dvo, VR82, &val); | ||
| 383 | DRM_DEBUG("VR82: 0x%04x\n", val); | ||
| 384 | ivch_read(dvo, VR83, &val); | ||
| 385 | DRM_DEBUG("VR83: 0x%04x\n", val); | ||
| 386 | ivch_read(dvo, VR84, &val); | ||
| 387 | DRM_DEBUG("VR84: 0x%04x\n", val); | ||
| 388 | ivch_read(dvo, VR85, &val); | ||
| 389 | DRM_DEBUG("VR85: 0x%04x\n", val); | ||
| 390 | ivch_read(dvo, VR86, &val); | ||
| 391 | DRM_DEBUG("VR86: 0x%04x\n", val); | ||
| 392 | ivch_read(dvo, VR87, &val); | ||
| 393 | DRM_DEBUG("VR87: 0x%04x\n", val); | ||
| 394 | ivch_read(dvo, VR88, &val); | ||
| 395 | DRM_DEBUG("VR88: 0x%04x\n", val); | ||
| 396 | |||
| 397 | /* Scratch register 0 - AIM Panel type */ | ||
| 398 | ivch_read(dvo, VR8E, &val); | ||
| 399 | DRM_DEBUG("VR8E: 0x%04x\n", val); | ||
| 400 | |||
| 401 | /* Scratch register 1 - Status register */ | ||
| 402 | ivch_read(dvo, VR8F, &val); | ||
| 403 | DRM_DEBUG("VR8F: 0x%04x\n", val); | ||
| 404 | } | ||
| 405 | |||
| 406 | static void ivch_save(struct intel_dvo_device *dvo) | ||
| 407 | { | ||
| 408 | struct ivch_priv *priv = dvo->dev_priv; | ||
| 409 | |||
| 410 | ivch_read(dvo, VR01, &priv->save_VR01); | ||
| 411 | ivch_read(dvo, VR40, &priv->save_VR40); | ||
| 412 | } | ||
| 413 | |||
| 414 | static void ivch_restore(struct intel_dvo_device *dvo) | ||
| 415 | { | ||
| 416 | struct ivch_priv *priv = dvo->dev_priv; | ||
| 417 | |||
| 418 | ivch_write(dvo, VR01, priv->save_VR01); | ||
| 419 | ivch_write(dvo, VR40, priv->save_VR40); | ||
| 420 | } | ||
| 421 | |||
| 422 | static void ivch_destroy(struct intel_dvo_device *dvo) | ||
| 423 | { | ||
| 424 | struct ivch_priv *priv = dvo->dev_priv; | ||
| 425 | |||
| 426 | if (priv) { | ||
| 427 | kfree(priv); | ||
| 428 | dvo->dev_priv = NULL; | ||
| 429 | } | ||
| 430 | } | ||
| 431 | |||
| 432 | struct intel_dvo_dev_ops ivch_ops= { | ||
| 433 | .init = ivch_init, | ||
| 434 | .dpms = ivch_dpms, | ||
| 435 | .save = ivch_save, | ||
| 436 | .restore = ivch_restore, | ||
| 437 | .mode_valid = ivch_mode_valid, | ||
| 438 | .mode_set = ivch_mode_set, | ||
| 439 | .detect = ivch_detect, | ||
| 440 | .dump_regs = ivch_dump_regs, | ||
| 441 | .destroy = ivch_destroy, | ||
| 442 | }; | ||
diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c new file mode 100644 index 000000000000..033a4bb070b2 --- /dev/null +++ b/drivers/gpu/drm/i915/dvo_sil164.c | |||
| @@ -0,0 +1,302 @@ | |||
| 1 | /************************************************************************** | ||
| 2 | |||
| 3 | Copyright © 2006 Dave Airlie | ||
| 4 | |||
| 5 | All Rights Reserved. | ||
| 6 | |||
| 7 | Permission is hereby granted, free of charge, to any person obtaining a | ||
| 8 | copy of this software and associated documentation files (the | ||
| 9 | "Software"), to deal in the Software without restriction, including | ||
| 10 | without limitation the rights to use, copy, modify, merge, publish, | ||
| 11 | distribute, sub license, and/or sell copies of the Software, and to | ||
| 12 | permit persons to whom the Software is furnished to do so, subject to | ||
| 13 | the following conditions: | ||
| 14 | |||
| 15 | The above copyright notice and this permission notice (including the | ||
| 16 | next paragraph) shall be included in all copies or substantial portions | ||
| 17 | of the Software. | ||
| 18 | |||
| 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| 20 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. | ||
| 22 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 23 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
| 24 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
| 25 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 26 | |||
| 27 | **************************************************************************/ | ||
| 28 | |||
| 29 | #include "dvo.h" | ||
| 30 | |||
| 31 | #define SIL164_VID 0x0001 | ||
| 32 | #define SIL164_DID 0x0006 | ||
| 33 | |||
| 34 | #define SIL164_VID_LO 0x00 | ||
| 35 | #define SIL164_VID_HI 0x01 | ||
| 36 | #define SIL164_DID_LO 0x02 | ||
| 37 | #define SIL164_DID_HI 0x03 | ||
| 38 | #define SIL164_REV 0x04 | ||
| 39 | #define SIL164_RSVD 0x05 | ||
| 40 | #define SIL164_FREQ_LO 0x06 | ||
| 41 | #define SIL164_FREQ_HI 0x07 | ||
| 42 | |||
| 43 | #define SIL164_REG8 0x08 | ||
| 44 | #define SIL164_8_VEN (1<<5) | ||
| 45 | #define SIL164_8_HEN (1<<4) | ||
| 46 | #define SIL164_8_DSEL (1<<3) | ||
| 47 | #define SIL164_8_BSEL (1<<2) | ||
| 48 | #define SIL164_8_EDGE (1<<1) | ||
| 49 | #define SIL164_8_PD (1<<0) | ||
| 50 | |||
| 51 | #define SIL164_REG9 0x09 | ||
| 52 | #define SIL164_9_VLOW (1<<7) | ||
| 53 | #define SIL164_9_MSEL_MASK (0x7<<4) | ||
| 54 | #define SIL164_9_TSEL (1<<3) | ||
| 55 | #define SIL164_9_RSEN (1<<2) | ||
| 56 | #define SIL164_9_HTPLG (1<<1) | ||
| 57 | #define SIL164_9_MDI (1<<0) | ||
| 58 | |||
| 59 | #define SIL164_REGC 0x0c | ||
| 60 | |||
| 61 | struct sil164_save_rec { | ||
| 62 | uint8_t reg8; | ||
| 63 | uint8_t reg9; | ||
| 64 | uint8_t regc; | ||
| 65 | }; | ||
| 66 | |||
| 67 | struct sil164_priv { | ||
| 68 | //I2CDevRec d; | ||
| 69 | bool quiet; | ||
| 70 | struct sil164_save_rec save_regs; | ||
| 71 | struct sil164_save_rec mode_regs; | ||
| 72 | }; | ||
| 73 | |||
| 74 | #define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr)) | ||
| 75 | |||
| 76 | static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) | ||
| 77 | { | ||
| 78 | struct sil164_priv *sil = dvo->dev_priv; | ||
| 79 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
| 80 | u8 out_buf[2]; | ||
| 81 | u8 in_buf[2]; | ||
| 82 | |||
| 83 | struct i2c_msg msgs[] = { | ||
| 84 | { | ||
| 85 | .addr = i2cbus->slave_addr, | ||
| 86 | .flags = 0, | ||
| 87 | .len = 1, | ||
| 88 | .buf = out_buf, | ||
| 89 | }, | ||
| 90 | { | ||
| 91 | .addr = i2cbus->slave_addr, | ||
| 92 | .flags = I2C_M_RD, | ||
| 93 | .len = 1, | ||
| 94 | .buf = in_buf, | ||
| 95 | } | ||
| 96 | }; | ||
| 97 | |||
| 98 | out_buf[0] = addr; | ||
| 99 | out_buf[1] = 0; | ||
| 100 | |||
| 101 | if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { | ||
| 102 | *ch = in_buf[0]; | ||
| 103 | return true; | ||
| 104 | }; | ||
| 105 | |||
| 106 | if (!sil->quiet) { | ||
| 107 | DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", | ||
| 108 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
| 109 | } | ||
| 110 | return false; | ||
| 111 | } | ||
| 112 | |||
| 113 | static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) | ||
| 114 | { | ||
| 115 | struct sil164_priv *sil= dvo->dev_priv; | ||
| 116 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
| 117 | uint8_t out_buf[2]; | ||
| 118 | struct i2c_msg msg = { | ||
| 119 | .addr = i2cbus->slave_addr, | ||
| 120 | .flags = 0, | ||
| 121 | .len = 2, | ||
| 122 | .buf = out_buf, | ||
| 123 | }; | ||
| 124 | |||
| 125 | out_buf[0] = addr; | ||
| 126 | out_buf[1] = ch; | ||
| 127 | |||
| 128 | if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) | ||
| 129 | return true; | ||
| 130 | |||
| 131 | if (!sil->quiet) { | ||
| 132 | DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", | ||
| 133 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
| 134 | } | ||
| 135 | |||
| 136 | return false; | ||
| 137 | } | ||
| 138 | |||
| 139 | /* Silicon Image 164 driver for chip on i2c bus */ | ||
| 140 | static bool sil164_init(struct intel_dvo_device *dvo, | ||
| 141 | struct intel_i2c_chan *i2cbus) | ||
| 142 | { | ||
| 143 | /* this will detect the SIL164 chip on the specified i2c bus */ | ||
| 144 | struct sil164_priv *sil; | ||
| 145 | unsigned char ch; | ||
| 146 | |||
| 147 | sil = kzalloc(sizeof(struct sil164_priv), GFP_KERNEL); | ||
| 148 | if (sil == NULL) | ||
| 149 | return false; | ||
| 150 | |||
| 151 | dvo->i2c_bus = i2cbus; | ||
| 152 | dvo->i2c_bus->slave_addr = dvo->slave_addr; | ||
| 153 | dvo->dev_priv = sil; | ||
| 154 | sil->quiet = true; | ||
| 155 | |||
| 156 | if (!sil164_readb(dvo, SIL164_VID_LO, &ch)) | ||
| 157 | goto out; | ||
| 158 | |||
| 159 | if (ch != (SIL164_VID & 0xff)) { | ||
| 160 | DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n", | ||
| 161 | ch, i2cbus->adapter.name, i2cbus->slave_addr); | ||
| 162 | goto out; | ||
| 163 | } | ||
| 164 | |||
| 165 | if (!sil164_readb(dvo, SIL164_DID_LO, &ch)) | ||
| 166 | goto out; | ||
| 167 | |||
| 168 | if (ch != (SIL164_DID & 0xff)) { | ||
| 169 | DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n", | ||
| 170 | ch, i2cbus->adapter.name, i2cbus->slave_addr); | ||
| 171 | goto out; | ||
| 172 | } | ||
| 173 | sil->quiet = false; | ||
| 174 | |||
| 175 | DRM_DEBUG("init sil164 dvo controller successfully!\n"); | ||
| 176 | return true; | ||
| 177 | |||
| 178 | out: | ||
| 179 | kfree(sil); | ||
| 180 | return false; | ||
| 181 | } | ||
| 182 | |||
| 183 | static enum drm_connector_status sil164_detect(struct intel_dvo_device *dvo) | ||
| 184 | { | ||
| 185 | uint8_t reg9; | ||
| 186 | |||
| 187 | sil164_readb(dvo, SIL164_REG9, ®9); | ||
| 188 | |||
| 189 | if (reg9 & SIL164_9_HTPLG) | ||
| 190 | return connector_status_connected; | ||
| 191 | else | ||
| 192 | return connector_status_disconnected; | ||
| 193 | } | ||
| 194 | |||
| 195 | static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo, | ||
| 196 | struct drm_display_mode *mode) | ||
| 197 | { | ||
| 198 | return MODE_OK; | ||
| 199 | } | ||
| 200 | |||
| 201 | static void sil164_mode_set(struct intel_dvo_device *dvo, | ||
| 202 | struct drm_display_mode *mode, | ||
| 203 | struct drm_display_mode *adjusted_mode) | ||
| 204 | { | ||
| 205 | /* As long as the basics are set up, since we don't have clock | ||
| 206 | * dependencies in the mode setup, we can just leave the | ||
| 207 | * registers alone and everything will work fine. | ||
| 208 | */ | ||
| 209 | /* recommended programming sequence from doc */ | ||
| 210 | /*sil164_writeb(sil, 0x08, 0x30); | ||
| 211 | sil164_writeb(sil, 0x09, 0x00); | ||
| 212 | sil164_writeb(sil, 0x0a, 0x90); | ||
| 213 | sil164_writeb(sil, 0x0c, 0x89); | ||
| 214 | sil164_writeb(sil, 0x08, 0x31);*/ | ||
| 215 | /* don't do much */ | ||
| 216 | return; | ||
| 217 | } | ||
| 218 | |||
| 219 | /* set the SIL164 power state */ | ||
| 220 | static void sil164_dpms(struct intel_dvo_device *dvo, int mode) | ||
| 221 | { | ||
| 222 | int ret; | ||
| 223 | unsigned char ch; | ||
| 224 | |||
| 225 | ret = sil164_readb(dvo, SIL164_REG8, &ch); | ||
| 226 | if (ret == false) | ||
| 227 | return; | ||
| 228 | |||
| 229 | if (mode == DRM_MODE_DPMS_ON) | ||
| 230 | ch |= SIL164_8_PD; | ||
| 231 | else | ||
| 232 | ch &= ~SIL164_8_PD; | ||
| 233 | |||
| 234 | sil164_writeb(dvo, SIL164_REG8, ch); | ||
| 235 | return; | ||
| 236 | } | ||
| 237 | |||
| 238 | static void sil164_dump_regs(struct intel_dvo_device *dvo) | ||
| 239 | { | ||
| 240 | uint8_t val; | ||
| 241 | |||
| 242 | sil164_readb(dvo, SIL164_FREQ_LO, &val); | ||
| 243 | DRM_DEBUG("SIL164_FREQ_LO: 0x%02x\n", val); | ||
| 244 | sil164_readb(dvo, SIL164_FREQ_HI, &val); | ||
| 245 | DRM_DEBUG("SIL164_FREQ_HI: 0x%02x\n", val); | ||
| 246 | sil164_readb(dvo, SIL164_REG8, &val); | ||
| 247 | DRM_DEBUG("SIL164_REG8: 0x%02x\n", val); | ||
| 248 | sil164_readb(dvo, SIL164_REG9, &val); | ||
| 249 | DRM_DEBUG("SIL164_REG9: 0x%02x\n", val); | ||
| 250 | sil164_readb(dvo, SIL164_REGC, &val); | ||
| 251 | DRM_DEBUG("SIL164_REGC: 0x%02x\n", val); | ||
| 252 | } | ||
| 253 | |||
| 254 | static void sil164_save(struct intel_dvo_device *dvo) | ||
| 255 | { | ||
| 256 | struct sil164_priv *sil= dvo->dev_priv; | ||
| 257 | |||
| 258 | if (!sil164_readb(dvo, SIL164_REG8, &sil->save_regs.reg8)) | ||
| 259 | return; | ||
| 260 | |||
| 261 | if (!sil164_readb(dvo, SIL164_REG9, &sil->save_regs.reg9)) | ||
| 262 | return; | ||
| 263 | |||
| 264 | if (!sil164_readb(dvo, SIL164_REGC, &sil->save_regs.regc)) | ||
| 265 | return; | ||
| 266 | |||
| 267 | return; | ||
| 268 | } | ||
| 269 | |||
| 270 | static void sil164_restore(struct intel_dvo_device *dvo) | ||
| 271 | { | ||
| 272 | struct sil164_priv *sil = dvo->dev_priv; | ||
| 273 | |||
| 274 | /* Restore it powered down initially */ | ||
| 275 | sil164_writeb(dvo, SIL164_REG8, sil->save_regs.reg8 & ~0x1); | ||
| 276 | |||
| 277 | sil164_writeb(dvo, SIL164_REG9, sil->save_regs.reg9); | ||
| 278 | sil164_writeb(dvo, SIL164_REGC, sil->save_regs.regc); | ||
| 279 | sil164_writeb(dvo, SIL164_REG8, sil->save_regs.reg8); | ||
| 280 | } | ||
| 281 | |||
| 282 | static void sil164_destroy(struct intel_dvo_device *dvo) | ||
| 283 | { | ||
| 284 | struct sil164_priv *sil = dvo->dev_priv; | ||
| 285 | |||
| 286 | if (sil) { | ||
| 287 | kfree(sil); | ||
| 288 | dvo->dev_priv = NULL; | ||
| 289 | } | ||
| 290 | } | ||
| 291 | |||
| 292 | struct intel_dvo_dev_ops sil164_ops = { | ||
| 293 | .init = sil164_init, | ||
| 294 | .detect = sil164_detect, | ||
| 295 | .mode_valid = sil164_mode_valid, | ||
| 296 | .mode_set = sil164_mode_set, | ||
| 297 | .dpms = sil164_dpms, | ||
| 298 | .dump_regs = sil164_dump_regs, | ||
| 299 | .save = sil164_save, | ||
| 300 | .restore = sil164_restore, | ||
| 301 | .destroy = sil164_destroy, | ||
| 302 | }; | ||
diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c new file mode 100644 index 000000000000..207fda806ebf --- /dev/null +++ b/drivers/gpu/drm/i915/dvo_tfp410.c | |||
| @@ -0,0 +1,335 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2007 Dave Mueller | ||
| 3 | * | ||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 5 | * copy of this software and associated documentation files (the "Software"), | ||
| 6 | * to deal in the Software without restriction, including without limitation | ||
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 9 | * Software is furnished to do so, subject to the following conditions: | ||
| 10 | * | ||
| 11 | * The above copyright notice and this permission notice (including the next | ||
| 12 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 13 | * Software. | ||
| 14 | * | ||
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
| 21 | * IN THE SOFTWARE. | ||
| 22 | * | ||
| 23 | * Authors: | ||
| 24 | * Dave Mueller <dave.mueller@gmx.ch> | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include "dvo.h" | ||
| 29 | |||
| 30 | /* register definitions according to the TFP410 data sheet */ | ||
| 31 | #define TFP410_VID 0x014C | ||
| 32 | #define TFP410_DID 0x0410 | ||
| 33 | |||
| 34 | #define TFP410_VID_LO 0x00 | ||
| 35 | #define TFP410_VID_HI 0x01 | ||
| 36 | #define TFP410_DID_LO 0x02 | ||
| 37 | #define TFP410_DID_HI 0x03 | ||
| 38 | #define TFP410_REV 0x04 | ||
| 39 | |||
| 40 | #define TFP410_CTL_1 0x08 | ||
| 41 | #define TFP410_CTL_1_TDIS (1<<6) | ||
| 42 | #define TFP410_CTL_1_VEN (1<<5) | ||
| 43 | #define TFP410_CTL_1_HEN (1<<4) | ||
| 44 | #define TFP410_CTL_1_DSEL (1<<3) | ||
| 45 | #define TFP410_CTL_1_BSEL (1<<2) | ||
| 46 | #define TFP410_CTL_1_EDGE (1<<1) | ||
| 47 | #define TFP410_CTL_1_PD (1<<0) | ||
| 48 | |||
| 49 | #define TFP410_CTL_2 0x09 | ||
| 50 | #define TFP410_CTL_2_VLOW (1<<7) | ||
| 51 | #define TFP410_CTL_2_MSEL_MASK (0x7<<4) | ||
| 52 | #define TFP410_CTL_2_MSEL (1<<4) | ||
| 53 | #define TFP410_CTL_2_TSEL (1<<3) | ||
| 54 | #define TFP410_CTL_2_RSEN (1<<2) | ||
| 55 | #define TFP410_CTL_2_HTPLG (1<<1) | ||
| 56 | #define TFP410_CTL_2_MDI (1<<0) | ||
| 57 | |||
| 58 | #define TFP410_CTL_3 0x0A | ||
| 59 | #define TFP410_CTL_3_DK_MASK (0x7<<5) | ||
| 60 | #define TFP410_CTL_3_DK (1<<5) | ||
| 61 | #define TFP410_CTL_3_DKEN (1<<4) | ||
| 62 | #define TFP410_CTL_3_CTL_MASK (0x7<<1) | ||
| 63 | #define TFP410_CTL_3_CTL (1<<1) | ||
| 64 | |||
| 65 | #define TFP410_USERCFG 0x0B | ||
| 66 | |||
| 67 | #define TFP410_DE_DLY 0x32 | ||
| 68 | |||
| 69 | #define TFP410_DE_CTL 0x33 | ||
| 70 | #define TFP410_DE_CTL_DEGEN (1<<6) | ||
| 71 | #define TFP410_DE_CTL_VSPOL (1<<5) | ||
| 72 | #define TFP410_DE_CTL_HSPOL (1<<4) | ||
| 73 | #define TFP410_DE_CTL_DEDLY8 (1<<0) | ||
| 74 | |||
| 75 | #define TFP410_DE_TOP 0x34 | ||
| 76 | |||
| 77 | #define TFP410_DE_CNT_LO 0x36 | ||
| 78 | #define TFP410_DE_CNT_HI 0x37 | ||
| 79 | |||
| 80 | #define TFP410_DE_LIN_LO 0x38 | ||
| 81 | #define TFP410_DE_LIN_HI 0x39 | ||
| 82 | |||
| 83 | #define TFP410_H_RES_LO 0x3A | ||
| 84 | #define TFP410_H_RES_HI 0x3B | ||
| 85 | |||
| 86 | #define TFP410_V_RES_LO 0x3C | ||
| 87 | #define TFP410_V_RES_HI 0x3D | ||
| 88 | |||
| 89 | struct tfp410_save_rec { | ||
| 90 | uint8_t ctl1; | ||
| 91 | uint8_t ctl2; | ||
| 92 | }; | ||
| 93 | |||
| 94 | struct tfp410_priv { | ||
| 95 | bool quiet; | ||
| 96 | |||
| 97 | struct tfp410_save_rec saved_reg; | ||
| 98 | struct tfp410_save_rec mode_reg; | ||
| 99 | }; | ||
| 100 | |||
| 101 | static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) | ||
| 102 | { | ||
| 103 | struct tfp410_priv *tfp = dvo->dev_priv; | ||
| 104 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
| 105 | u8 out_buf[2]; | ||
| 106 | u8 in_buf[2]; | ||
| 107 | |||
| 108 | struct i2c_msg msgs[] = { | ||
| 109 | { | ||
| 110 | .addr = i2cbus->slave_addr, | ||
| 111 | .flags = 0, | ||
| 112 | .len = 1, | ||
| 113 | .buf = out_buf, | ||
| 114 | }, | ||
| 115 | { | ||
| 116 | .addr = i2cbus->slave_addr, | ||
| 117 | .flags = I2C_M_RD, | ||
| 118 | .len = 1, | ||
| 119 | .buf = in_buf, | ||
| 120 | } | ||
| 121 | }; | ||
| 122 | |||
| 123 | out_buf[0] = addr; | ||
| 124 | out_buf[1] = 0; | ||
| 125 | |||
| 126 | if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { | ||
| 127 | *ch = in_buf[0]; | ||
| 128 | return true; | ||
| 129 | }; | ||
| 130 | |||
| 131 | if (!tfp->quiet) { | ||
| 132 | DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", | ||
| 133 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
| 134 | } | ||
| 135 | return false; | ||
| 136 | } | ||
| 137 | |||
| 138 | static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) | ||
| 139 | { | ||
| 140 | struct tfp410_priv *tfp = dvo->dev_priv; | ||
| 141 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
| 142 | uint8_t out_buf[2]; | ||
| 143 | struct i2c_msg msg = { | ||
| 144 | .addr = i2cbus->slave_addr, | ||
| 145 | .flags = 0, | ||
| 146 | .len = 2, | ||
| 147 | .buf = out_buf, | ||
| 148 | }; | ||
| 149 | |||
| 150 | out_buf[0] = addr; | ||
| 151 | out_buf[1] = ch; | ||
| 152 | |||
| 153 | if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) | ||
| 154 | return true; | ||
| 155 | |||
| 156 | if (!tfp->quiet) { | ||
| 157 | DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", | ||
| 158 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
| 159 | } | ||
| 160 | |||
| 161 | return false; | ||
| 162 | } | ||
| 163 | |||
| 164 | static int tfp410_getid(struct intel_dvo_device *dvo, int addr) | ||
| 165 | { | ||
| 166 | uint8_t ch1, ch2; | ||
| 167 | |||
| 168 | if (tfp410_readb(dvo, addr+0, &ch1) && | ||
| 169 | tfp410_readb(dvo, addr+1, &ch2)) | ||
| 170 | return ((ch2 << 8) & 0xFF00) | (ch1 & 0x00FF); | ||
| 171 | |||
| 172 | return -1; | ||
| 173 | } | ||
| 174 | |||
| 175 | /* Ti TFP410 driver for chip on i2c bus */ | ||
| 176 | static bool tfp410_init(struct intel_dvo_device *dvo, | ||
| 177 | struct intel_i2c_chan *i2cbus) | ||
| 178 | { | ||
| 179 | /* this will detect the tfp410 chip on the specified i2c bus */ | ||
| 180 | struct tfp410_priv *tfp; | ||
| 181 | int id; | ||
| 182 | |||
| 183 | tfp = kzalloc(sizeof(struct tfp410_priv), GFP_KERNEL); | ||
| 184 | if (tfp == NULL) | ||
| 185 | return false; | ||
| 186 | |||
| 187 | dvo->i2c_bus = i2cbus; | ||
| 188 | dvo->i2c_bus->slave_addr = dvo->slave_addr; | ||
| 189 | dvo->dev_priv = tfp; | ||
| 190 | tfp->quiet = true; | ||
| 191 | |||
| 192 | if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) { | ||
| 193 | DRM_DEBUG("tfp410 not detected got VID %X: from %s Slave %d.\n", | ||
| 194 | id, i2cbus->adapter.name, i2cbus->slave_addr); | ||
| 195 | goto out; | ||
| 196 | } | ||
| 197 | |||
| 198 | if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) { | ||
| 199 | DRM_DEBUG("tfp410 not detected got DID %X: from %s Slave %d.\n", | ||
| 200 | id, i2cbus->adapter.name, i2cbus->slave_addr); | ||
| 201 | goto out; | ||
| 202 | } | ||
| 203 | tfp->quiet = false; | ||
| 204 | return true; | ||
| 205 | out: | ||
| 206 | kfree(tfp); | ||
| 207 | return false; | ||
| 208 | } | ||
| 209 | |||
| 210 | static enum drm_connector_status tfp410_detect(struct intel_dvo_device *dvo) | ||
| 211 | { | ||
| 212 | enum drm_connector_status ret = connector_status_disconnected; | ||
| 213 | uint8_t ctl2; | ||
| 214 | |||
| 215 | if (tfp410_readb(dvo, TFP410_CTL_2, &ctl2)) { | ||
| 216 | if (ctl2 & TFP410_CTL_2_HTPLG) | ||
| 217 | ret = connector_status_connected; | ||
| 218 | else | ||
| 219 | ret = connector_status_disconnected; | ||
| 220 | } | ||
| 221 | |||
| 222 | return ret; | ||
| 223 | } | ||
| 224 | |||
| 225 | static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo, | ||
| 226 | struct drm_display_mode *mode) | ||
| 227 | { | ||
| 228 | return MODE_OK; | ||
| 229 | } | ||
| 230 | |||
| 231 | static void tfp410_mode_set(struct intel_dvo_device *dvo, | ||
| 232 | struct drm_display_mode *mode, | ||
| 233 | struct drm_display_mode *adjusted_mode) | ||
| 234 | { | ||
| 235 | /* As long as the basics are set up, since we don't have clock dependencies | ||
| 236 | * in the mode setup, we can just leave the registers alone and everything | ||
| 237 | * will work fine. | ||
| 238 | */ | ||
| 239 | /* don't do much */ | ||
| 240 | return; | ||
| 241 | } | ||
| 242 | |||
| 243 | /* set the tfp410 power state */ | ||
| 244 | static void tfp410_dpms(struct intel_dvo_device *dvo, int mode) | ||
| 245 | { | ||
| 246 | uint8_t ctl1; | ||
| 247 | |||
| 248 | if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1)) | ||
| 249 | return; | ||
| 250 | |||
| 251 | if (mode == DRM_MODE_DPMS_ON) | ||
| 252 | ctl1 |= TFP410_CTL_1_PD; | ||
| 253 | else | ||
| 254 | ctl1 &= ~TFP410_CTL_1_PD; | ||
| 255 | |||
| 256 | tfp410_writeb(dvo, TFP410_CTL_1, ctl1); | ||
| 257 | } | ||
| 258 | |||
| 259 | static void tfp410_dump_regs(struct intel_dvo_device *dvo) | ||
| 260 | { | ||
| 261 | uint8_t val, val2; | ||
| 262 | |||
| 263 | tfp410_readb(dvo, TFP410_REV, &val); | ||
| 264 | DRM_DEBUG("TFP410_REV: 0x%02X\n", val); | ||
| 265 | tfp410_readb(dvo, TFP410_CTL_1, &val); | ||
| 266 | DRM_DEBUG("TFP410_CTL1: 0x%02X\n", val); | ||
| 267 | tfp410_readb(dvo, TFP410_CTL_2, &val); | ||
| 268 | DRM_DEBUG("TFP410_CTL2: 0x%02X\n", val); | ||
| 269 | tfp410_readb(dvo, TFP410_CTL_3, &val); | ||
| 270 | DRM_DEBUG("TFP410_CTL3: 0x%02X\n", val); | ||
| 271 | tfp410_readb(dvo, TFP410_USERCFG, &val); | ||
| 272 | DRM_DEBUG("TFP410_USERCFG: 0x%02X\n", val); | ||
| 273 | tfp410_readb(dvo, TFP410_DE_DLY, &val); | ||
| 274 | DRM_DEBUG("TFP410_DE_DLY: 0x%02X\n", val); | ||
| 275 | tfp410_readb(dvo, TFP410_DE_CTL, &val); | ||
| 276 | DRM_DEBUG("TFP410_DE_CTL: 0x%02X\n", val); | ||
| 277 | tfp410_readb(dvo, TFP410_DE_TOP, &val); | ||
| 278 | DRM_DEBUG("TFP410_DE_TOP: 0x%02X\n", val); | ||
| 279 | tfp410_readb(dvo, TFP410_DE_CNT_LO, &val); | ||
| 280 | tfp410_readb(dvo, TFP410_DE_CNT_HI, &val2); | ||
| 281 | DRM_DEBUG("TFP410_DE_CNT: 0x%02X%02X\n", val2, val); | ||
| 282 | tfp410_readb(dvo, TFP410_DE_LIN_LO, &val); | ||
| 283 | tfp410_readb(dvo, TFP410_DE_LIN_HI, &val2); | ||
| 284 | DRM_DEBUG("TFP410_DE_LIN: 0x%02X%02X\n", val2, val); | ||
| 285 | tfp410_readb(dvo, TFP410_H_RES_LO, &val); | ||
| 286 | tfp410_readb(dvo, TFP410_H_RES_HI, &val2); | ||
| 287 | DRM_DEBUG("TFP410_H_RES: 0x%02X%02X\n", val2, val); | ||
| 288 | tfp410_readb(dvo, TFP410_V_RES_LO, &val); | ||
| 289 | tfp410_readb(dvo, TFP410_V_RES_HI, &val2); | ||
| 290 | DRM_DEBUG("TFP410_V_RES: 0x%02X%02X\n", val2, val); | ||
| 291 | } | ||
| 292 | |||
| 293 | static void tfp410_save(struct intel_dvo_device *dvo) | ||
| 294 | { | ||
| 295 | struct tfp410_priv *tfp = dvo->dev_priv; | ||
| 296 | |||
| 297 | if (!tfp410_readb(dvo, TFP410_CTL_1, &tfp->saved_reg.ctl1)) | ||
| 298 | return; | ||
| 299 | |||
| 300 | if (!tfp410_readb(dvo, TFP410_CTL_2, &tfp->saved_reg.ctl2)) | ||
| 301 | return; | ||
| 302 | } | ||
| 303 | |||
| 304 | static void tfp410_restore(struct intel_dvo_device *dvo) | ||
| 305 | { | ||
| 306 | struct tfp410_priv *tfp = dvo->dev_priv; | ||
| 307 | |||
| 308 | /* Restore it powered down initially */ | ||
| 309 | tfp410_writeb(dvo, TFP410_CTL_1, tfp->saved_reg.ctl1 & ~0x1); | ||
| 310 | |||
| 311 | tfp410_writeb(dvo, TFP410_CTL_2, tfp->saved_reg.ctl2); | ||
| 312 | tfp410_writeb(dvo, TFP410_CTL_1, tfp->saved_reg.ctl1); | ||
| 313 | } | ||
| 314 | |||
| 315 | static void tfp410_destroy(struct intel_dvo_device *dvo) | ||
| 316 | { | ||
| 317 | struct tfp410_priv *tfp = dvo->dev_priv; | ||
| 318 | |||
| 319 | if (tfp) { | ||
| 320 | kfree(tfp); | ||
| 321 | dvo->dev_priv = NULL; | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | struct intel_dvo_dev_ops tfp410_ops = { | ||
| 326 | .init = tfp410_init, | ||
| 327 | .detect = tfp410_detect, | ||
| 328 | .mode_valid = tfp410_mode_valid, | ||
| 329 | .mode_set = tfp410_mode_set, | ||
| 330 | .dpms = tfp410_dpms, | ||
| 331 | .dump_regs = tfp410_dump_regs, | ||
| 332 | .save = tfp410_save, | ||
| 333 | .restore = tfp410_restore, | ||
| 334 | .destroy = tfp410_destroy, | ||
| 335 | }; | ||
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index afa8a12cd009..3d7082af5b72 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
| @@ -28,6 +28,8 @@ | |||
| 28 | 28 | ||
| 29 | #include "drmP.h" | 29 | #include "drmP.h" |
| 30 | #include "drm.h" | 30 | #include "drm.h" |
| 31 | #include "drm_crtc_helper.h" | ||
| 32 | #include "intel_drv.h" | ||
| 31 | #include "i915_drm.h" | 33 | #include "i915_drm.h" |
| 32 | #include "i915_drv.h" | 34 | #include "i915_drv.h" |
| 33 | 35 | ||
| @@ -39,6 +41,7 @@ | |||
| 39 | int i915_wait_ring(struct drm_device * dev, int n, const char *caller) | 41 | int i915_wait_ring(struct drm_device * dev, int n, const char *caller) |
| 40 | { | 42 | { |
| 41 | drm_i915_private_t *dev_priv = dev->dev_private; | 43 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 44 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; | ||
| 42 | drm_i915_ring_buffer_t *ring = &(dev_priv->ring); | 45 | drm_i915_ring_buffer_t *ring = &(dev_priv->ring); |
| 43 | u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; | 46 | u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; |
| 44 | u32 last_acthd = I915_READ(acthd_reg); | 47 | u32 last_acthd = I915_READ(acthd_reg); |
| @@ -55,8 +58,8 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) | |||
| 55 | if (ring->space >= n) | 58 | if (ring->space >= n) |
| 56 | return 0; | 59 | return 0; |
| 57 | 60 | ||
| 58 | if (dev_priv->sarea_priv) | 61 | if (master_priv->sarea_priv) |
| 59 | dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; | 62 | master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; |
| 60 | 63 | ||
| 61 | if (ring->head != last_head) | 64 | if (ring->head != last_head) |
| 62 | i = 0; | 65 | i = 0; |
| @@ -121,16 +124,28 @@ static void i915_free_hws(struct drm_device *dev) | |||
| 121 | void i915_kernel_lost_context(struct drm_device * dev) | 124 | void i915_kernel_lost_context(struct drm_device * dev) |
| 122 | { | 125 | { |
| 123 | drm_i915_private_t *dev_priv = dev->dev_private; | 126 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 127 | struct drm_i915_master_private *master_priv; | ||
| 124 | drm_i915_ring_buffer_t *ring = &(dev_priv->ring); | 128 | drm_i915_ring_buffer_t *ring = &(dev_priv->ring); |
| 125 | 129 | ||
| 130 | /* | ||
| 131 | * We should never lose context on the ring with modesetting | ||
| 132 | * as we don't expose it to userspace | ||
| 133 | */ | ||
| 134 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
| 135 | return; | ||
| 136 | |||
| 126 | ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; | 137 | ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; |
| 127 | ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; | 138 | ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; |
| 128 | ring->space = ring->head - (ring->tail + 8); | 139 | ring->space = ring->head - (ring->tail + 8); |
| 129 | if (ring->space < 0) | 140 | if (ring->space < 0) |
| 130 | ring->space += ring->Size; | 141 | ring->space += ring->Size; |
| 131 | 142 | ||
| 132 | if (ring->head == ring->tail && dev_priv->sarea_priv) | 143 | if (!dev->primary->master) |
| 133 | dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY; | 144 | return; |
| 145 | |||
| 146 | master_priv = dev->primary->master->driver_priv; | ||
| 147 | if (ring->head == ring->tail && master_priv->sarea_priv) | ||
| 148 | master_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY; | ||
| 134 | } | 149 | } |
| 135 | 150 | ||
| 136 | static int i915_dma_cleanup(struct drm_device * dev) | 151 | static int i915_dma_cleanup(struct drm_device * dev) |
| @@ -154,25 +169,13 @@ static int i915_dma_cleanup(struct drm_device * dev) | |||
| 154 | if (I915_NEED_GFX_HWS(dev)) | 169 | if (I915_NEED_GFX_HWS(dev)) |
| 155 | i915_free_hws(dev); | 170 | i915_free_hws(dev); |
| 156 | 171 | ||
| 157 | dev_priv->sarea = NULL; | ||
| 158 | dev_priv->sarea_priv = NULL; | ||
| 159 | |||
| 160 | return 0; | 172 | return 0; |
| 161 | } | 173 | } |
| 162 | 174 | ||
| 163 | static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) | 175 | static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) |
| 164 | { | 176 | { |
| 165 | drm_i915_private_t *dev_priv = dev->dev_private; | 177 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 166 | 178 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; | |
| 167 | dev_priv->sarea = drm_getsarea(dev); | ||
| 168 | if (!dev_priv->sarea) { | ||
| 169 | DRM_ERROR("can not find sarea!\n"); | ||
| 170 | i915_dma_cleanup(dev); | ||
| 171 | return -EINVAL; | ||
| 172 | } | ||
| 173 | |||
| 174 | dev_priv->sarea_priv = (drm_i915_sarea_t *) | ||
| 175 | ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); | ||
| 176 | 179 | ||
| 177 | if (init->ring_size != 0) { | 180 | if (init->ring_size != 0) { |
| 178 | if (dev_priv->ring.ring_obj != NULL) { | 181 | if (dev_priv->ring.ring_obj != NULL) { |
| @@ -207,7 +210,8 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) | |||
| 207 | dev_priv->back_offset = init->back_offset; | 210 | dev_priv->back_offset = init->back_offset; |
| 208 | dev_priv->front_offset = init->front_offset; | 211 | dev_priv->front_offset = init->front_offset; |
| 209 | dev_priv->current_page = 0; | 212 | dev_priv->current_page = 0; |
| 210 | dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; | 213 | if (master_priv->sarea_priv) |
| 214 | master_priv->sarea_priv->pf_current_page = 0; | ||
| 211 | 215 | ||
| 212 | /* Allow hardware batchbuffers unless told otherwise. | 216 | /* Allow hardware batchbuffers unless told otherwise. |
| 213 | */ | 217 | */ |
| @@ -222,11 +226,6 @@ static int i915_dma_resume(struct drm_device * dev) | |||
| 222 | 226 | ||
| 223 | DRM_DEBUG("%s\n", __func__); | 227 | DRM_DEBUG("%s\n", __func__); |
| 224 | 228 | ||
| 225 | if (!dev_priv->sarea) { | ||
| 226 | DRM_ERROR("can not find sarea!\n"); | ||
| 227 | return -EINVAL; | ||
| 228 | } | ||
| 229 | |||
| 230 | if (dev_priv->ring.map.handle == NULL) { | 229 | if (dev_priv->ring.map.handle == NULL) { |
| 231 | DRM_ERROR("can not ioremap virtual address for" | 230 | DRM_ERROR("can not ioremap virtual address for" |
| 232 | " ring buffer\n"); | 231 | " ring buffer\n"); |
| @@ -435,13 +434,14 @@ i915_emit_box(struct drm_device *dev, | |||
| 435 | static void i915_emit_breadcrumb(struct drm_device *dev) | 434 | static void i915_emit_breadcrumb(struct drm_device *dev) |
| 436 | { | 435 | { |
| 437 | drm_i915_private_t *dev_priv = dev->dev_private; | 436 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 437 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; | ||
| 438 | RING_LOCALS; | 438 | RING_LOCALS; |
| 439 | 439 | ||
| 440 | dev_priv->counter++; | 440 | dev_priv->counter++; |
| 441 | if (dev_priv->counter > 0x7FFFFFFFUL) | 441 | if (dev_priv->counter > 0x7FFFFFFFUL) |
| 442 | dev_priv->counter = 0; | 442 | dev_priv->counter = 0; |
| 443 | if (dev_priv->sarea_priv) | 443 | if (master_priv->sarea_priv) |
| 444 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter; | 444 | master_priv->sarea_priv->last_enqueue = dev_priv->counter; |
| 445 | 445 | ||
| 446 | BEGIN_LP_RING(4); | 446 | BEGIN_LP_RING(4); |
| 447 | OUT_RING(MI_STORE_DWORD_INDEX); | 447 | OUT_RING(MI_STORE_DWORD_INDEX); |
| @@ -537,15 +537,17 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, | |||
| 537 | static int i915_dispatch_flip(struct drm_device * dev) | 537 | static int i915_dispatch_flip(struct drm_device * dev) |
| 538 | { | 538 | { |
| 539 | drm_i915_private_t *dev_priv = dev->dev_private; | 539 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 540 | struct drm_i915_master_private *master_priv = | ||
| 541 | dev->primary->master->driver_priv; | ||
| 540 | RING_LOCALS; | 542 | RING_LOCALS; |
| 541 | 543 | ||
| 542 | if (!dev_priv->sarea_priv) | 544 | if (!master_priv->sarea_priv) |
| 543 | return -EINVAL; | 545 | return -EINVAL; |
| 544 | 546 | ||
| 545 | DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", | 547 | DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", |
| 546 | __func__, | 548 | __func__, |
| 547 | dev_priv->current_page, | 549 | dev_priv->current_page, |
| 548 | dev_priv->sarea_priv->pf_current_page); | 550 | master_priv->sarea_priv->pf_current_page); |
| 549 | 551 | ||
| 550 | i915_kernel_lost_context(dev); | 552 | i915_kernel_lost_context(dev); |
| 551 | 553 | ||
| @@ -572,7 +574,7 @@ static int i915_dispatch_flip(struct drm_device * dev) | |||
| 572 | OUT_RING(0); | 574 | OUT_RING(0); |
| 573 | ADVANCE_LP_RING(); | 575 | ADVANCE_LP_RING(); |
| 574 | 576 | ||
| 575 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; | 577 | master_priv->sarea_priv->last_enqueue = dev_priv->counter++; |
| 576 | 578 | ||
| 577 | BEGIN_LP_RING(4); | 579 | BEGIN_LP_RING(4); |
| 578 | OUT_RING(MI_STORE_DWORD_INDEX); | 580 | OUT_RING(MI_STORE_DWORD_INDEX); |
| @@ -581,7 +583,7 @@ static int i915_dispatch_flip(struct drm_device * dev) | |||
| 581 | OUT_RING(0); | 583 | OUT_RING(0); |
| 582 | ADVANCE_LP_RING(); | 584 | ADVANCE_LP_RING(); |
| 583 | 585 | ||
| 584 | dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; | 586 | master_priv->sarea_priv->pf_current_page = dev_priv->current_page; |
| 585 | return 0; | 587 | return 0; |
| 586 | } | 588 | } |
| 587 | 589 | ||
| @@ -611,8 +613,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, | |||
| 611 | struct drm_file *file_priv) | 613 | struct drm_file *file_priv) |
| 612 | { | 614 | { |
| 613 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 615 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 616 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; | ||
| 614 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) | 617 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) |
| 615 | dev_priv->sarea_priv; | 618 | master_priv->sarea_priv; |
| 616 | drm_i915_batchbuffer_t *batch = data; | 619 | drm_i915_batchbuffer_t *batch = data; |
| 617 | int ret; | 620 | int ret; |
| 618 | 621 | ||
| @@ -644,8 +647,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, | |||
| 644 | struct drm_file *file_priv) | 647 | struct drm_file *file_priv) |
| 645 | { | 648 | { |
| 646 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 649 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 650 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; | ||
| 647 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) | 651 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) |
| 648 | dev_priv->sarea_priv; | 652 | master_priv->sarea_priv; |
| 649 | drm_i915_cmdbuffer_t *cmdbuf = data; | 653 | drm_i915_cmdbuffer_t *cmdbuf = data; |
| 650 | int ret; | 654 | int ret; |
| 651 | 655 | ||
| @@ -774,6 +778,11 @@ static int i915_set_status_page(struct drm_device *dev, void *data, | |||
| 774 | return -EINVAL; | 778 | return -EINVAL; |
| 775 | } | 779 | } |
| 776 | 780 | ||
| 781 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
| 782 | WARN(1, "tried to set status page when mode setting active\n"); | ||
| 783 | return 0; | ||
| 784 | } | ||
| 785 | |||
| 777 | printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr); | 786 | printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr); |
| 778 | 787 | ||
| 779 | dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); | 788 | dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); |
| @@ -802,6 +811,214 @@ static int i915_set_status_page(struct drm_device *dev, void *data, | |||
| 802 | return 0; | 811 | return 0; |
| 803 | } | 812 | } |
| 804 | 813 | ||
| 814 | /** | ||
| 815 | * i915_probe_agp - get AGP bootup configuration | ||
| 816 | * @pdev: PCI device | ||
| 817 | * @aperture_size: returns AGP aperture configured size | ||
| 818 | * @preallocated_size: returns size of BIOS preallocated AGP space | ||
| 819 | * | ||
| 820 | * Since Intel integrated graphics are UMA, the BIOS has to set aside | ||
| 821 | * some RAM for the framebuffer at early boot. This code figures out | ||
| 822 | * how much was set aside so we can use it for our own purposes. | ||
| 823 | */ | ||
| 824 | static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size, | ||
| 825 | unsigned long *preallocated_size) | ||
| 826 | { | ||
| 827 | struct pci_dev *bridge_dev; | ||
| 828 | u16 tmp = 0; | ||
| 829 | unsigned long overhead; | ||
| 830 | |||
| 831 | bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); | ||
| 832 | if (!bridge_dev) { | ||
| 833 | DRM_ERROR("bridge device not found\n"); | ||
| 834 | return -1; | ||
| 835 | } | ||
| 836 | |||
| 837 | /* Get the fb aperture size and "stolen" memory amount. */ | ||
| 838 | pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp); | ||
| 839 | pci_dev_put(bridge_dev); | ||
| 840 | |||
| 841 | *aperture_size = 1024 * 1024; | ||
| 842 | *preallocated_size = 1024 * 1024; | ||
| 843 | |||
| 844 | switch (dev->pdev->device) { | ||
| 845 | case PCI_DEVICE_ID_INTEL_82830_CGC: | ||
| 846 | case PCI_DEVICE_ID_INTEL_82845G_IG: | ||
| 847 | case PCI_DEVICE_ID_INTEL_82855GM_IG: | ||
| 848 | case PCI_DEVICE_ID_INTEL_82865_IG: | ||
| 849 | if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M) | ||
| 850 | *aperture_size *= 64; | ||
| 851 | else | ||
| 852 | *aperture_size *= 128; | ||
| 853 | break; | ||
| 854 | default: | ||
| 855 | /* 9xx supports large sizes, just look at the length */ | ||
| 856 | *aperture_size = pci_resource_len(dev->pdev, 2); | ||
| 857 | break; | ||
| 858 | } | ||
| 859 | |||
| 860 | /* | ||
| 861 | * Some of the preallocated space is taken by the GTT | ||
| 862 | * and popup. GTT is 1K per MB of aperture size, and popup is 4K. | ||
| 863 | */ | ||
| 864 | if (IS_G4X(dev)) | ||
| 865 | overhead = 4096; | ||
| 866 | else | ||
| 867 | overhead = (*aperture_size / 1024) + 4096; | ||
| 868 | |||
| 869 | switch (tmp & INTEL_855_GMCH_GMS_MASK) { | ||
| 870 | case INTEL_855_GMCH_GMS_STOLEN_1M: | ||
| 871 | break; /* 1M already */ | ||
| 872 | case INTEL_855_GMCH_GMS_STOLEN_4M: | ||
| 873 | *preallocated_size *= 4; | ||
| 874 | break; | ||
| 875 | case INTEL_855_GMCH_GMS_STOLEN_8M: | ||
| 876 | *preallocated_size *= 8; | ||
| 877 | break; | ||
| 878 | case INTEL_855_GMCH_GMS_STOLEN_16M: | ||
| 879 | *preallocated_size *= 16; | ||
| 880 | break; | ||
| 881 | case INTEL_855_GMCH_GMS_STOLEN_32M: | ||
| 882 | *preallocated_size *= 32; | ||
| 883 | break; | ||
| 884 | case INTEL_915G_GMCH_GMS_STOLEN_48M: | ||
| 885 | *preallocated_size *= 48; | ||
| 886 | break; | ||
| 887 | case INTEL_915G_GMCH_GMS_STOLEN_64M: | ||
| 888 | *preallocated_size *= 64; | ||
| 889 | break; | ||
| 890 | case INTEL_855_GMCH_GMS_DISABLED: | ||
| 891 | DRM_ERROR("video memory is disabled\n"); | ||
| 892 | return -1; | ||
| 893 | default: | ||
| 894 | DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n", | ||
| 895 | tmp & INTEL_855_GMCH_GMS_MASK); | ||
| 896 | return -1; | ||
| 897 | } | ||
| 898 | *preallocated_size -= overhead; | ||
| 899 | |||
| 900 | return 0; | ||
| 901 | } | ||
| 902 | |||
| 903 | static int i915_load_modeset_init(struct drm_device *dev) | ||
| 904 | { | ||
| 905 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 906 | unsigned long agp_size, prealloc_size; | ||
| 907 | int fb_bar = IS_I9XX(dev) ? 2 : 0; | ||
| 908 | int ret = 0; | ||
| 909 | |||
| 910 | dev->devname = kstrdup(DRIVER_NAME, GFP_KERNEL); | ||
| 911 | if (!dev->devname) { | ||
| 912 | ret = -ENOMEM; | ||
| 913 | goto out; | ||
| 914 | } | ||
| 915 | |||
| 916 | dev->mode_config.fb_base = drm_get_resource_start(dev, fb_bar) & | ||
| 917 | 0xff000000; | ||
| 918 | |||
| 919 | DRM_DEBUG("*** fb base 0x%08lx\n", dev->mode_config.fb_base); | ||
| 920 | |||
| 921 | if (IS_MOBILE(dev) || (IS_I9XX(dev) && !IS_I965G(dev) && !IS_G33(dev))) | ||
| 922 | dev_priv->cursor_needs_physical = true; | ||
| 923 | else | ||
| 924 | dev_priv->cursor_needs_physical = false; | ||
| 925 | |||
| 926 | ret = i915_probe_agp(dev, &agp_size, &prealloc_size); | ||
| 927 | if (ret) | ||
| 928 | goto kfree_devname; | ||
| 929 | |||
| 930 | /* Basic memrange allocator for stolen space (aka vram) */ | ||
| 931 | drm_mm_init(&dev_priv->vram, 0, prealloc_size); | ||
| 932 | |||
| 933 | /* Let GEM Manage from end of prealloc space to end of aperture */ | ||
| 934 | i915_gem_do_init(dev, prealloc_size, agp_size); | ||
| 935 | |||
| 936 | ret = i915_gem_init_ringbuffer(dev); | ||
| 937 | if (ret) | ||
| 938 | goto kfree_devname; | ||
| 939 | |||
| 940 | dev_priv->mm.gtt_mapping = | ||
| 941 | io_mapping_create_wc(dev->agp->base, | ||
| 942 | dev->agp->agp_info.aper_size * 1024*1024); | ||
| 943 | |||
| 944 | /* Allow hardware batchbuffers unless told otherwise. | ||
| 945 | */ | ||
| 946 | dev_priv->allow_batchbuffer = 1; | ||
| 947 | |||
| 948 | ret = intel_init_bios(dev); | ||
| 949 | if (ret) | ||
| 950 | DRM_INFO("failed to find VBIOS tables\n"); | ||
| 951 | |||
| 952 | ret = drm_irq_install(dev); | ||
| 953 | if (ret) | ||
| 954 | goto destroy_ringbuffer; | ||
| 955 | |||
| 956 | /* FIXME: re-add hotplug support */ | ||
| 957 | #if 0 | ||
| 958 | ret = drm_hotplug_init(dev); | ||
| 959 | if (ret) | ||
| 960 | goto destroy_ringbuffer; | ||
| 961 | #endif | ||
| 962 | |||
| 963 | /* Always safe in the mode setting case. */ | ||
| 964 | /* FIXME: do pre/post-mode set stuff in core KMS code */ | ||
| 965 | dev->vblank_disable_allowed = 1; | ||
| 966 | |||
| 967 | /* | ||
| 968 | * Initialize the hardware status page IRQ location. | ||
| 969 | */ | ||
| 970 | |||
| 971 | I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); | ||
| 972 | |||
| 973 | intel_modeset_init(dev); | ||
| 974 | |||
| 975 | drm_helper_initial_config(dev, false); | ||
| 976 | |||
| 977 | return 0; | ||
| 978 | |||
| 979 | destroy_ringbuffer: | ||
| 980 | i915_gem_cleanup_ringbuffer(dev); | ||
| 981 | kfree_devname: | ||
| 982 | kfree(dev->devname); | ||
| 983 | out: | ||
| 984 | return ret; | ||
| 985 | } | ||
| 986 | |||
| 987 | int i915_master_create(struct drm_device *dev, struct drm_master *master) | ||
| 988 | { | ||
| 989 | struct drm_i915_master_private *master_priv; | ||
| 990 | |||
| 991 | master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER); | ||
| 992 | if (!master_priv) | ||
| 993 | return -ENOMEM; | ||
| 994 | |||
| 995 | master->driver_priv = master_priv; | ||
| 996 | return 0; | ||
| 997 | } | ||
| 998 | |||
| 999 | void i915_master_destroy(struct drm_device *dev, struct drm_master *master) | ||
| 1000 | { | ||
| 1001 | struct drm_i915_master_private *master_priv = master->driver_priv; | ||
| 1002 | |||
| 1003 | if (!master_priv) | ||
| 1004 | return; | ||
| 1005 | |||
| 1006 | drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); | ||
| 1007 | |||
| 1008 | master->driver_priv = NULL; | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | /** | ||
| 1012 | * i915_driver_load - setup chip and create an initial config | ||
| 1013 | * @dev: DRM device | ||
| 1014 | * @flags: startup flags | ||
| 1015 | * | ||
| 1016 | * The driver load routine has to do several things: | ||
| 1017 | * - drive output discovery via intel_modeset_init() | ||
| 1018 | * - initialize the memory manager | ||
| 1019 | * - allocate initial config memory | ||
| 1020 | * - setup the DRM framebuffer with the allocated memory | ||
| 1021 | */ | ||
| 805 | int i915_driver_load(struct drm_device *dev, unsigned long flags) | 1022 | int i915_driver_load(struct drm_device *dev, unsigned long flags) |
| 806 | { | 1023 | { |
| 807 | struct drm_i915_private *dev_priv = dev->dev_private; | 1024 | struct drm_i915_private *dev_priv = dev->dev_private; |
| @@ -829,6 +1046,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
| 829 | size = drm_get_resource_len(dev, mmio_bar); | 1046 | size = drm_get_resource_len(dev, mmio_bar); |
| 830 | 1047 | ||
| 831 | dev_priv->regs = ioremap(base, size); | 1048 | dev_priv->regs = ioremap(base, size); |
| 1049 | if (!dev_priv->regs) { | ||
| 1050 | DRM_ERROR("failed to map registers\n"); | ||
| 1051 | ret = -EIO; | ||
| 1052 | goto free_priv; | ||
| 1053 | } | ||
| 832 | 1054 | ||
| 833 | #ifdef CONFIG_HIGHMEM64G | 1055 | #ifdef CONFIG_HIGHMEM64G |
| 834 | /* don't enable GEM on PAE - needs agp + set_memory_* interface fixes */ | 1056 | /* don't enable GEM on PAE - needs agp + set_memory_* interface fixes */ |
| @@ -844,7 +1066,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
| 844 | if (!I915_NEED_GFX_HWS(dev)) { | 1066 | if (!I915_NEED_GFX_HWS(dev)) { |
| 845 | ret = i915_init_phys_hws(dev); | 1067 | ret = i915_init_phys_hws(dev); |
| 846 | if (ret != 0) | 1068 | if (ret != 0) |
| 847 | return ret; | 1069 | goto out_rmmap; |
| 848 | } | 1070 | } |
| 849 | 1071 | ||
| 850 | /* On the 945G/GM, the chipset reports the MSI capability on the | 1072 | /* On the 945G/GM, the chipset reports the MSI capability on the |
| @@ -864,6 +1086,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
| 864 | intel_opregion_init(dev); | 1086 | intel_opregion_init(dev); |
| 865 | 1087 | ||
| 866 | spin_lock_init(&dev_priv->user_irq_lock); | 1088 | spin_lock_init(&dev_priv->user_irq_lock); |
| 1089 | dev_priv->user_irq_refcount = 0; | ||
| 867 | 1090 | ||
| 868 | ret = drm_vblank_init(dev, I915_NUM_PIPE); | 1091 | ret = drm_vblank_init(dev, I915_NUM_PIPE); |
| 869 | 1092 | ||
| @@ -872,6 +1095,20 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
| 872 | return ret; | 1095 | return ret; |
| 873 | } | 1096 | } |
| 874 | 1097 | ||
| 1098 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
| 1099 | ret = i915_load_modeset_init(dev); | ||
| 1100 | if (ret < 0) { | ||
| 1101 | DRM_ERROR("failed to init modeset\n"); | ||
| 1102 | goto out_rmmap; | ||
| 1103 | } | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | return 0; | ||
| 1107 | |||
| 1108 | out_rmmap: | ||
| 1109 | iounmap(dev_priv->regs); | ||
| 1110 | free_priv: | ||
| 1111 | drm_free(dev_priv, sizeof(struct drm_i915_private), DRM_MEM_DRIVER); | ||
| 875 | return ret; | 1112 | return ret; |
| 876 | } | 1113 | } |
| 877 | 1114 | ||
| @@ -879,16 +1116,29 @@ int i915_driver_unload(struct drm_device *dev) | |||
| 879 | { | 1116 | { |
| 880 | struct drm_i915_private *dev_priv = dev->dev_private; | 1117 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 881 | 1118 | ||
| 1119 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
| 1120 | io_mapping_free(dev_priv->mm.gtt_mapping); | ||
| 1121 | drm_irq_uninstall(dev); | ||
| 1122 | } | ||
| 1123 | |||
| 882 | if (dev->pdev->msi_enabled) | 1124 | if (dev->pdev->msi_enabled) |
| 883 | pci_disable_msi(dev->pdev); | 1125 | pci_disable_msi(dev->pdev); |
| 884 | 1126 | ||
| 885 | i915_free_hws(dev); | ||
| 886 | |||
| 887 | if (dev_priv->regs != NULL) | 1127 | if (dev_priv->regs != NULL) |
| 888 | iounmap(dev_priv->regs); | 1128 | iounmap(dev_priv->regs); |
| 889 | 1129 | ||
| 890 | intel_opregion_free(dev); | 1130 | intel_opregion_free(dev); |
| 891 | 1131 | ||
| 1132 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
| 1133 | intel_modeset_cleanup(dev); | ||
| 1134 | |||
| 1135 | mutex_lock(&dev->struct_mutex); | ||
| 1136 | i915_gem_cleanup_ringbuffer(dev); | ||
| 1137 | mutex_unlock(&dev->struct_mutex); | ||
| 1138 | drm_mm_takedown(&dev_priv->vram); | ||
| 1139 | i915_gem_lastclose(dev); | ||
| 1140 | } | ||
| 1141 | |||
| 892 | drm_free(dev->dev_private, sizeof(drm_i915_private_t), | 1142 | drm_free(dev->dev_private, sizeof(drm_i915_private_t), |
| 893 | DRM_MEM_DRIVER); | 1143 | DRM_MEM_DRIVER); |
| 894 | 1144 | ||
| @@ -914,12 +1164,26 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv) | |||
| 914 | return 0; | 1164 | return 0; |
| 915 | } | 1165 | } |
| 916 | 1166 | ||
| 1167 | /** | ||
| 1168 | * i915_driver_lastclose - clean up after all DRM clients have exited | ||
| 1169 | * @dev: DRM device | ||
| 1170 | * | ||
| 1171 | * Take care of cleaning up after all DRM clients have exited. In the | ||
| 1172 | * mode setting case, we want to restore the kernel's initial mode (just | ||
| 1173 | * in case the last client left us in a bad state). | ||
| 1174 | * | ||
| 1175 | * Additionally, in the non-mode setting case, we'll tear down the AGP | ||
| 1176 | * and DMA structures, since the kernel won't be using them, and clea | ||
| 1177 | * up any GEM state. | ||
| 1178 | */ | ||
| 917 | void i915_driver_lastclose(struct drm_device * dev) | 1179 | void i915_driver_lastclose(struct drm_device * dev) |
| 918 | { | 1180 | { |
| 919 | drm_i915_private_t *dev_priv = dev->dev_private; | 1181 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 920 | 1182 | ||
| 921 | if (!dev_priv) | 1183 | if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) { |
| 1184 | intelfb_restore(); | ||
| 922 | return; | 1185 | return; |
| 1186 | } | ||
| 923 | 1187 | ||
| 924 | i915_gem_lastclose(dev); | 1188 | i915_gem_lastclose(dev); |
| 925 | 1189 | ||
| @@ -932,7 +1196,8 @@ void i915_driver_lastclose(struct drm_device * dev) | |||
| 932 | void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) | 1196 | void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) |
| 933 | { | 1197 | { |
| 934 | drm_i915_private_t *dev_priv = dev->dev_private; | 1198 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 935 | i915_mem_release(dev, file_priv, dev_priv->agp_heap); | 1199 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| 1200 | i915_mem_release(dev, file_priv, dev_priv->agp_heap); | ||
| 936 | } | 1201 | } |
| 937 | 1202 | ||
| 938 | void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) | 1203 | void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) |
| @@ -972,6 +1237,7 @@ struct drm_ioctl_desc i915_ioctls[] = { | |||
| 972 | DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0), | 1237 | DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0), |
| 973 | DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0), | 1238 | DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0), |
| 974 | DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0), | 1239 | DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0), |
| 1240 | DRM_IOCTL_DEF(DRM_I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, 0), | ||
| 975 | DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0), | 1241 | DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0), |
| 976 | DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0), | 1242 | DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0), |
| 977 | DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0), | 1243 | DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0), |
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a80ead215282..f8b3df0926c0 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
| @@ -33,11 +33,22 @@ | |||
| 33 | #include "i915_drv.h" | 33 | #include "i915_drv.h" |
| 34 | 34 | ||
| 35 | #include "drm_pciids.h" | 35 | #include "drm_pciids.h" |
| 36 | #include <linux/console.h> | ||
| 37 | |||
| 38 | static unsigned int i915_modeset = -1; | ||
| 39 | module_param_named(modeset, i915_modeset, int, 0400); | ||
| 40 | |||
| 41 | unsigned int i915_fbpercrtc = 0; | ||
| 42 | module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); | ||
| 36 | 43 | ||
| 37 | static struct pci_device_id pciidlist[] = { | 44 | static struct pci_device_id pciidlist[] = { |
| 38 | i915_PCI_IDS | 45 | i915_PCI_IDS |
| 39 | }; | 46 | }; |
| 40 | 47 | ||
| 48 | #if defined(CONFIG_DRM_I915_KMS) | ||
| 49 | MODULE_DEVICE_TABLE(pci, pciidlist); | ||
| 50 | #endif | ||
| 51 | |||
| 41 | static int i915_suspend(struct drm_device *dev, pm_message_t state) | 52 | static int i915_suspend(struct drm_device *dev, pm_message_t state) |
| 42 | { | 53 | { |
| 43 | struct drm_i915_private *dev_priv = dev->dev_private; | 54 | struct drm_i915_private *dev_priv = dev->dev_private; |
| @@ -81,6 +92,10 @@ static int i915_resume(struct drm_device *dev) | |||
| 81 | return 0; | 92 | return 0; |
| 82 | } | 93 | } |
| 83 | 94 | ||
| 95 | static struct vm_operations_struct i915_gem_vm_ops = { | ||
| 96 | .fault = i915_gem_fault, | ||
| 97 | }; | ||
| 98 | |||
| 84 | static struct drm_driver driver = { | 99 | static struct drm_driver driver = { |
| 85 | /* don't use mtrr's here, the Xserver or user space app should | 100 | /* don't use mtrr's here, the Xserver or user space app should |
| 86 | * deal with them for intel hardware. | 101 | * deal with them for intel hardware. |
| @@ -107,17 +122,20 @@ static struct drm_driver driver = { | |||
| 107 | .reclaim_buffers = drm_core_reclaim_buffers, | 122 | .reclaim_buffers = drm_core_reclaim_buffers, |
| 108 | .get_map_ofs = drm_core_get_map_ofs, | 123 | .get_map_ofs = drm_core_get_map_ofs, |
| 109 | .get_reg_ofs = drm_core_get_reg_ofs, | 124 | .get_reg_ofs = drm_core_get_reg_ofs, |
| 125 | .master_create = i915_master_create, | ||
| 126 | .master_destroy = i915_master_destroy, | ||
| 110 | .proc_init = i915_gem_proc_init, | 127 | .proc_init = i915_gem_proc_init, |
| 111 | .proc_cleanup = i915_gem_proc_cleanup, | 128 | .proc_cleanup = i915_gem_proc_cleanup, |
| 112 | .gem_init_object = i915_gem_init_object, | 129 | .gem_init_object = i915_gem_init_object, |
| 113 | .gem_free_object = i915_gem_free_object, | 130 | .gem_free_object = i915_gem_free_object, |
| 131 | .gem_vm_ops = &i915_gem_vm_ops, | ||
| 114 | .ioctls = i915_ioctls, | 132 | .ioctls = i915_ioctls, |
| 115 | .fops = { | 133 | .fops = { |
| 116 | .owner = THIS_MODULE, | 134 | .owner = THIS_MODULE, |
| 117 | .open = drm_open, | 135 | .open = drm_open, |
| 118 | .release = drm_release, | 136 | .release = drm_release, |
| 119 | .ioctl = drm_ioctl, | 137 | .ioctl = drm_ioctl, |
| 120 | .mmap = drm_mmap, | 138 | .mmap = drm_gem_mmap, |
| 121 | .poll = drm_poll, | 139 | .poll = drm_poll, |
| 122 | .fasync = drm_fasync, | 140 | .fasync = drm_fasync, |
| 123 | #ifdef CONFIG_COMPAT | 141 | #ifdef CONFIG_COMPAT |
| @@ -141,6 +159,28 @@ static struct drm_driver driver = { | |||
| 141 | static int __init i915_init(void) | 159 | static int __init i915_init(void) |
| 142 | { | 160 | { |
| 143 | driver.num_ioctls = i915_max_ioctl; | 161 | driver.num_ioctls = i915_max_ioctl; |
| 162 | |||
| 163 | /* | ||
| 164 | * If CONFIG_DRM_I915_KMS is set, default to KMS unless | ||
| 165 | * explicitly disabled with the module pararmeter. | ||
| 166 | * | ||
| 167 | * Otherwise, just follow the parameter (defaulting to off). | ||
| 168 | * | ||
| 169 | * Allow optional vga_text_mode_force boot option to override | ||
| 170 | * the default behavior. | ||
| 171 | */ | ||
| 172 | #if defined(CONFIG_DRM_I915_KMS) | ||
| 173 | if (i915_modeset != 0) | ||
| 174 | driver.driver_features |= DRIVER_MODESET; | ||
| 175 | #endif | ||
| 176 | if (i915_modeset == 1) | ||
| 177 | driver.driver_features |= DRIVER_MODESET; | ||
| 178 | |||
| 179 | #ifdef CONFIG_VGA_CONSOLE | ||
| 180 | if (vgacon_text_force() && i915_modeset == -1) | ||
| 181 | driver.driver_features &= ~DRIVER_MODESET; | ||
| 182 | #endif | ||
| 183 | |||
| 144 | return drm_init(&driver); | 184 | return drm_init(&driver); |
| 145 | } | 185 | } |
| 146 | 186 | ||
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b3cc4731aa7c..4756e5cd6b5e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #define _I915_DRV_H_ | 31 | #define _I915_DRV_H_ |
| 32 | 32 | ||
| 33 | #include "i915_reg.h" | 33 | #include "i915_reg.h" |
| 34 | #include "intel_bios.h" | ||
| 34 | #include <linux/io-mapping.h> | 35 | #include <linux/io-mapping.h> |
| 35 | 36 | ||
| 36 | /* General customization: | 37 | /* General customization: |
| @@ -103,15 +104,23 @@ struct intel_opregion { | |||
| 103 | int enabled; | 104 | int enabled; |
| 104 | }; | 105 | }; |
| 105 | 106 | ||
| 107 | struct drm_i915_master_private { | ||
| 108 | drm_local_map_t *sarea; | ||
| 109 | struct _drm_i915_sarea *sarea_priv; | ||
| 110 | }; | ||
| 111 | #define I915_FENCE_REG_NONE -1 | ||
| 112 | |||
| 113 | struct drm_i915_fence_reg { | ||
| 114 | struct drm_gem_object *obj; | ||
| 115 | }; | ||
| 116 | |||
| 106 | typedef struct drm_i915_private { | 117 | typedef struct drm_i915_private { |
| 107 | struct drm_device *dev; | 118 | struct drm_device *dev; |
| 108 | 119 | ||
| 109 | int has_gem; | 120 | int has_gem; |
| 110 | 121 | ||
| 111 | void __iomem *regs; | 122 | void __iomem *regs; |
| 112 | drm_local_map_t *sarea; | ||
| 113 | 123 | ||
| 114 | drm_i915_sarea_t *sarea_priv; | ||
| 115 | drm_i915_ring_buffer_t ring; | 124 | drm_i915_ring_buffer_t ring; |
| 116 | 125 | ||
| 117 | drm_dma_handle_t *status_page_dmah; | 126 | drm_dma_handle_t *status_page_dmah; |
| @@ -144,8 +153,30 @@ typedef struct drm_i915_private { | |||
| 144 | unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; | 153 | unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; |
| 145 | int vblank_pipe; | 154 | int vblank_pipe; |
| 146 | 155 | ||
| 156 | bool cursor_needs_physical; | ||
| 157 | |||
| 158 | struct drm_mm vram; | ||
| 159 | |||
| 160 | int irq_enabled; | ||
| 161 | |||
| 147 | struct intel_opregion opregion; | 162 | struct intel_opregion opregion; |
| 148 | 163 | ||
| 164 | /* LVDS info */ | ||
| 165 | int backlight_duty_cycle; /* restore backlight to this value */ | ||
| 166 | bool panel_wants_dither; | ||
| 167 | struct drm_display_mode *panel_fixed_mode; | ||
| 168 | struct drm_display_mode *vbt_mode; /* if any */ | ||
| 169 | |||
| 170 | /* Feature bits from the VBIOS */ | ||
| 171 | unsigned int int_tv_support:1; | ||
| 172 | unsigned int lvds_dither:1; | ||
| 173 | unsigned int lvds_vbt:1; | ||
| 174 | unsigned int int_crt_support:1; | ||
| 175 | |||
| 176 | struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */ | ||
| 177 | int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ | ||
| 178 | int num_fence_regs; /* 8 on pre-965, 16 otherwise */ | ||
| 179 | |||
| 149 | /* Register state */ | 180 | /* Register state */ |
| 150 | u8 saveLBB; | 181 | u8 saveLBB; |
| 151 | u32 saveDSPACNTR; | 182 | u32 saveDSPACNTR; |
| @@ -364,6 +395,21 @@ struct drm_i915_gem_object { | |||
| 364 | * This is the same as gtt_space->start | 395 | * This is the same as gtt_space->start |
| 365 | */ | 396 | */ |
| 366 | uint32_t gtt_offset; | 397 | uint32_t gtt_offset; |
| 398 | /** | ||
| 399 | * Required alignment for the object | ||
| 400 | */ | ||
| 401 | uint32_t gtt_alignment; | ||
| 402 | /** | ||
| 403 | * Fake offset for use by mmap(2) | ||
| 404 | */ | ||
| 405 | uint64_t mmap_offset; | ||
| 406 | |||
| 407 | /** | ||
| 408 | * Fence register bits (if any) for this object. Will be set | ||
| 409 | * as needed when mapped into the GTT. | ||
| 410 | * Protected by dev->struct_mutex. | ||
| 411 | */ | ||
| 412 | int fence_reg; | ||
| 367 | 413 | ||
| 368 | /** Boolean whether this object has a valid gtt offset. */ | 414 | /** Boolean whether this object has a valid gtt offset. */ |
| 369 | int gtt_bound; | 415 | int gtt_bound; |
| @@ -376,6 +422,7 @@ struct drm_i915_gem_object { | |||
| 376 | 422 | ||
| 377 | /** Current tiling mode for the object. */ | 423 | /** Current tiling mode for the object. */ |
| 378 | uint32_t tiling_mode; | 424 | uint32_t tiling_mode; |
| 425 | uint32_t stride; | ||
| 379 | 426 | ||
| 380 | /** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */ | 427 | /** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */ |
| 381 | uint32_t agp_type; | 428 | uint32_t agp_type; |
| @@ -385,6 +432,10 @@ struct drm_i915_gem_object { | |||
| 385 | * flags which individual pages are valid. | 432 | * flags which individual pages are valid. |
| 386 | */ | 433 | */ |
| 387 | uint8_t *page_cpu_valid; | 434 | uint8_t *page_cpu_valid; |
| 435 | |||
| 436 | /** User space pin count and filp owning the pin */ | ||
| 437 | uint32_t user_pin_count; | ||
| 438 | struct drm_file *pin_filp; | ||
| 388 | }; | 439 | }; |
| 389 | 440 | ||
| 390 | /** | 441 | /** |
| @@ -414,8 +465,19 @@ struct drm_i915_file_private { | |||
| 414 | } mm; | 465 | } mm; |
| 415 | }; | 466 | }; |
| 416 | 467 | ||
| 468 | enum intel_chip_family { | ||
| 469 | CHIP_I8XX = 0x01, | ||
| 470 | CHIP_I9XX = 0x02, | ||
| 471 | CHIP_I915 = 0x04, | ||
| 472 | CHIP_I965 = 0x08, | ||
| 473 | }; | ||
| 474 | |||
| 417 | extern struct drm_ioctl_desc i915_ioctls[]; | 475 | extern struct drm_ioctl_desc i915_ioctls[]; |
| 418 | extern int i915_max_ioctl; | 476 | extern int i915_max_ioctl; |
| 477 | extern unsigned int i915_fbpercrtc; | ||
| 478 | |||
| 479 | extern int i915_master_create(struct drm_device *dev, struct drm_master *master); | ||
| 480 | extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master); | ||
| 419 | 481 | ||
| 420 | /* i915_dma.c */ | 482 | /* i915_dma.c */ |
| 421 | extern void i915_kernel_lost_context(struct drm_device * dev); | 483 | extern void i915_kernel_lost_context(struct drm_device * dev); |
| @@ -441,6 +503,7 @@ extern int i915_irq_wait(struct drm_device *dev, void *data, | |||
| 441 | struct drm_file *file_priv); | 503 | struct drm_file *file_priv); |
| 442 | void i915_user_irq_get(struct drm_device *dev); | 504 | void i915_user_irq_get(struct drm_device *dev); |
| 443 | void i915_user_irq_put(struct drm_device *dev); | 505 | void i915_user_irq_put(struct drm_device *dev); |
| 506 | extern void i915_enable_interrupt (struct drm_device *dev); | ||
| 444 | 507 | ||
| 445 | extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); | 508 | extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); |
| 446 | extern void i915_driver_irq_preinstall(struct drm_device * dev); | 509 | extern void i915_driver_irq_preinstall(struct drm_device * dev); |
| @@ -487,6 +550,8 @@ int i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, | |||
| 487 | struct drm_file *file_priv); | 550 | struct drm_file *file_priv); |
| 488 | int i915_gem_mmap_ioctl(struct drm_device *dev, void *data, | 551 | int i915_gem_mmap_ioctl(struct drm_device *dev, void *data, |
| 489 | struct drm_file *file_priv); | 552 | struct drm_file *file_priv); |
| 553 | int i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, | ||
| 554 | struct drm_file *file_priv); | ||
| 490 | int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, | 555 | int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, |
| 491 | struct drm_file *file_priv); | 556 | struct drm_file *file_priv); |
| 492 | int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, | 557 | int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, |
| @@ -523,6 +588,16 @@ uint32_t i915_get_gem_seqno(struct drm_device *dev); | |||
| 523 | void i915_gem_retire_requests(struct drm_device *dev); | 588 | void i915_gem_retire_requests(struct drm_device *dev); |
| 524 | void i915_gem_retire_work_handler(struct work_struct *work); | 589 | void i915_gem_retire_work_handler(struct work_struct *work); |
| 525 | void i915_gem_clflush_object(struct drm_gem_object *obj); | 590 | void i915_gem_clflush_object(struct drm_gem_object *obj); |
| 591 | int i915_gem_object_set_domain(struct drm_gem_object *obj, | ||
| 592 | uint32_t read_domains, | ||
| 593 | uint32_t write_domain); | ||
| 594 | int i915_gem_init_ringbuffer(struct drm_device *dev); | ||
| 595 | void i915_gem_cleanup_ringbuffer(struct drm_device *dev); | ||
| 596 | int i915_gem_do_init(struct drm_device *dev, unsigned long start, | ||
| 597 | unsigned long end); | ||
| 598 | int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); | ||
| 599 | int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, | ||
| 600 | int write); | ||
| 526 | 601 | ||
| 527 | /* i915_gem_tiling.c */ | 602 | /* i915_gem_tiling.c */ |
| 528 | void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); | 603 | void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); |
| @@ -561,6 +636,10 @@ static inline void opregion_asle_intr(struct drm_device *dev) { return; } | |||
| 561 | static inline void opregion_enable_asle(struct drm_device *dev) { return; } | 636 | static inline void opregion_enable_asle(struct drm_device *dev) { return; } |
| 562 | #endif | 637 | #endif |
| 563 | 638 | ||
| 639 | /* modesetting */ | ||
| 640 | extern void intel_modeset_init(struct drm_device *dev); | ||
| 641 | extern void intel_modeset_cleanup(struct drm_device *dev); | ||
| 642 | |||
| 564 | /** | 643 | /** |
| 565 | * Lock test for when it's just for synchronization of ring access. | 644 | * Lock test for when it's just for synchronization of ring access. |
| 566 | * | 645 | * |
| @@ -578,6 +657,13 @@ static inline void opregion_enable_asle(struct drm_device *dev) { return; } | |||
| 578 | #define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg)) | 657 | #define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg)) |
| 579 | #define I915_READ8(reg) readb(dev_priv->regs + (reg)) | 658 | #define I915_READ8(reg) readb(dev_priv->regs + (reg)) |
| 580 | #define I915_WRITE8(reg, val) writeb(val, dev_priv->regs + (reg)) | 659 | #define I915_WRITE8(reg, val) writeb(val, dev_priv->regs + (reg)) |
| 660 | #ifdef writeq | ||
| 661 | #define I915_WRITE64(reg, val) writeq(val, dev_priv->regs + (reg)) | ||
| 662 | #else | ||
| 663 | #define I915_WRITE64(reg, val) (writel(val, dev_priv->regs + (reg)), \ | ||
| 664 | writel(upper_32_bits(val), dev_priv->regs + \ | ||
| 665 | (reg) + 4)) | ||
| 666 | #endif | ||
| 581 | 667 | ||
| 582 | #define I915_VERBOSE 0 | 668 | #define I915_VERBOSE 0 |
| 583 | 669 | ||
| @@ -660,7 +746,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); | |||
| 660 | 746 | ||
| 661 | #define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \ | 747 | #define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \ |
| 662 | (dev)->pci_device == 0x2E12 || \ | 748 | (dev)->pci_device == 0x2E12 || \ |
| 663 | (dev)->pci_device == 0x2E22) | 749 | (dev)->pci_device == 0x2E22 || \ |
| 750 | IS_GM45(dev)) | ||
| 664 | 751 | ||
| 665 | #define IS_G33(dev) ((dev)->pci_device == 0x29C2 || \ | 752 | #define IS_G33(dev) ((dev)->pci_device == 0x29C2 || \ |
| 666 | (dev)->pci_device == 0x29B2 || \ | 753 | (dev)->pci_device == 0x29B2 || \ |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 24fe8c10b4b2..cc2ca5561feb 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include "i915_drm.h" | 30 | #include "i915_drm.h" |
| 31 | #include "i915_drv.h" | 31 | #include "i915_drv.h" |
| 32 | #include <linux/swap.h> | 32 | #include <linux/swap.h> |
| 33 | #include <linux/pci.h> | ||
| 33 | 34 | ||
| 34 | #define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) | 35 | #define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) |
| 35 | 36 | ||
| @@ -40,8 +41,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, | |||
| 40 | static void i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); | 41 | static void i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); |
| 41 | static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj); | 42 | static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj); |
| 42 | static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj); | 43 | static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj); |
| 43 | static int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, | ||
| 44 | int write); | ||
| 45 | static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, | 44 | static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, |
| 46 | int write); | 45 | int write); |
| 47 | static int i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, | 46 | static int i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, |
| @@ -51,34 +50,43 @@ static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *o | |||
| 51 | static int i915_gem_object_get_page_list(struct drm_gem_object *obj); | 50 | static int i915_gem_object_get_page_list(struct drm_gem_object *obj); |
| 52 | static void i915_gem_object_free_page_list(struct drm_gem_object *obj); | 51 | static void i915_gem_object_free_page_list(struct drm_gem_object *obj); |
| 53 | static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); | 52 | static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); |
| 53 | static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, | ||
| 54 | unsigned alignment); | ||
| 55 | static void i915_gem_object_get_fence_reg(struct drm_gem_object *obj); | ||
| 56 | static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); | ||
| 57 | static int i915_gem_evict_something(struct drm_device *dev); | ||
| 58 | |||
| 59 | int i915_gem_do_init(struct drm_device *dev, unsigned long start, | ||
| 60 | unsigned long end) | ||
| 61 | { | ||
| 62 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 54 | 63 | ||
| 55 | static void | 64 | if (start >= end || |
| 56 | i915_gem_cleanup_ringbuffer(struct drm_device *dev); | 65 | (start & (PAGE_SIZE - 1)) != 0 || |
| 66 | (end & (PAGE_SIZE - 1)) != 0) { | ||
| 67 | return -EINVAL; | ||
| 68 | } | ||
| 69 | |||
| 70 | drm_mm_init(&dev_priv->mm.gtt_space, start, | ||
| 71 | end - start); | ||
| 72 | |||
| 73 | dev->gtt_total = (uint32_t) (end - start); | ||
| 74 | |||
| 75 | return 0; | ||
| 76 | } | ||
| 57 | 77 | ||
| 58 | int | 78 | int |
| 59 | i915_gem_init_ioctl(struct drm_device *dev, void *data, | 79 | i915_gem_init_ioctl(struct drm_device *dev, void *data, |
| 60 | struct drm_file *file_priv) | 80 | struct drm_file *file_priv) |
| 61 | { | 81 | { |
| 62 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 63 | struct drm_i915_gem_init *args = data; | 82 | struct drm_i915_gem_init *args = data; |
| 83 | int ret; | ||
| 64 | 84 | ||
| 65 | mutex_lock(&dev->struct_mutex); | 85 | mutex_lock(&dev->struct_mutex); |
| 66 | 86 | ret = i915_gem_do_init(dev, args->gtt_start, args->gtt_end); | |
| 67 | if (args->gtt_start >= args->gtt_end || | ||
| 68 | (args->gtt_start & (PAGE_SIZE - 1)) != 0 || | ||
| 69 | (args->gtt_end & (PAGE_SIZE - 1)) != 0) { | ||
| 70 | mutex_unlock(&dev->struct_mutex); | ||
| 71 | return -EINVAL; | ||
| 72 | } | ||
| 73 | |||
| 74 | drm_mm_init(&dev_priv->mm.gtt_space, args->gtt_start, | ||
| 75 | args->gtt_end - args->gtt_start); | ||
| 76 | |||
| 77 | dev->gtt_total = (uint32_t) (args->gtt_end - args->gtt_start); | ||
| 78 | |||
| 79 | mutex_unlock(&dev->struct_mutex); | 87 | mutex_unlock(&dev->struct_mutex); |
| 80 | 88 | ||
| 81 | return 0; | 89 | return ret; |
| 82 | } | 90 | } |
| 83 | 91 | ||
| 84 | int | 92 | int |
| @@ -529,6 +537,252 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, | |||
| 529 | return 0; | 537 | return 0; |
| 530 | } | 538 | } |
| 531 | 539 | ||
| 540 | /** | ||
| 541 | * i915_gem_fault - fault a page into the GTT | ||
| 542 | * vma: VMA in question | ||
| 543 | * vmf: fault info | ||
| 544 | * | ||
| 545 | * The fault handler is set up by drm_gem_mmap() when a object is GTT mapped | ||
| 546 | * from userspace. The fault handler takes care of binding the object to | ||
| 547 | * the GTT (if needed), allocating and programming a fence register (again, | ||
| 548 | * only if needed based on whether the old reg is still valid or the object | ||
| 549 | * is tiled) and inserting a new PTE into the faulting process. | ||
| 550 | * | ||
| 551 | * Note that the faulting process may involve evicting existing objects | ||
| 552 | * from the GTT and/or fence registers to make room. So performance may | ||
| 553 | * suffer if the GTT working set is large or there are few fence registers | ||
| 554 | * left. | ||
| 555 | */ | ||
| 556 | int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
| 557 | { | ||
| 558 | struct drm_gem_object *obj = vma->vm_private_data; | ||
| 559 | struct drm_device *dev = obj->dev; | ||
| 560 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 561 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
| 562 | pgoff_t page_offset; | ||
| 563 | unsigned long pfn; | ||
| 564 | int ret = 0; | ||
| 565 | |||
| 566 | /* We don't use vmf->pgoff since that has the fake offset */ | ||
| 567 | page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> | ||
| 568 | PAGE_SHIFT; | ||
| 569 | |||
| 570 | /* Now bind it into the GTT if needed */ | ||
| 571 | mutex_lock(&dev->struct_mutex); | ||
| 572 | if (!obj_priv->gtt_space) { | ||
| 573 | ret = i915_gem_object_bind_to_gtt(obj, obj_priv->gtt_alignment); | ||
| 574 | if (ret) { | ||
| 575 | mutex_unlock(&dev->struct_mutex); | ||
| 576 | return VM_FAULT_SIGBUS; | ||
| 577 | } | ||
| 578 | list_add(&obj_priv->list, &dev_priv->mm.inactive_list); | ||
| 579 | } | ||
| 580 | |||
| 581 | /* Need a new fence register? */ | ||
| 582 | if (obj_priv->fence_reg == I915_FENCE_REG_NONE && | ||
| 583 | obj_priv->tiling_mode != I915_TILING_NONE) | ||
| 584 | i915_gem_object_get_fence_reg(obj); | ||
| 585 | |||
| 586 | pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) + | ||
| 587 | page_offset; | ||
| 588 | |||
| 589 | /* Finally, remap it using the new GTT offset */ | ||
| 590 | ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); | ||
| 591 | |||
| 592 | mutex_unlock(&dev->struct_mutex); | ||
| 593 | |||
| 594 | switch (ret) { | ||
| 595 | case -ENOMEM: | ||
| 596 | case -EAGAIN: | ||
| 597 | return VM_FAULT_OOM; | ||
| 598 | case -EFAULT: | ||
| 599 | case -EBUSY: | ||
| 600 | DRM_ERROR("can't insert pfn?? fault or busy...\n"); | ||
| 601 | return VM_FAULT_SIGBUS; | ||
| 602 | default: | ||
| 603 | return VM_FAULT_NOPAGE; | ||
| 604 | } | ||
| 605 | } | ||
| 606 | |||
| 607 | /** | ||
| 608 | * i915_gem_create_mmap_offset - create a fake mmap offset for an object | ||
| 609 | * @obj: obj in question | ||
| 610 | * | ||
| 611 | * GEM memory mapping works by handing back to userspace a fake mmap offset | ||
| 612 | * it can use in a subsequent mmap(2) call. The DRM core code then looks | ||
| 613 | * up the object based on the offset and sets up the various memory mapping | ||
| 614 | * structures. | ||
| 615 | * | ||
| 616 | * This routine allocates and attaches a fake offset for @obj. | ||
| 617 | */ | ||
| 618 | static int | ||
| 619 | i915_gem_create_mmap_offset(struct drm_gem_object *obj) | ||
| 620 | { | ||
| 621 | struct drm_device *dev = obj->dev; | ||
| 622 | struct drm_gem_mm *mm = dev->mm_private; | ||
| 623 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
| 624 | struct drm_map_list *list; | ||
| 625 | struct drm_map *map; | ||
| 626 | int ret = 0; | ||
| 627 | |||
| 628 | /* Set the object up for mmap'ing */ | ||
| 629 | list = &obj->map_list; | ||
| 630 | list->map = drm_calloc(1, sizeof(struct drm_map_list), | ||
| 631 | DRM_MEM_DRIVER); | ||
| 632 | if (!list->map) | ||
| 633 | return -ENOMEM; | ||
| 634 | |||
| 635 | map = list->map; | ||
| 636 | map->type = _DRM_GEM; | ||
| 637 | map->size = obj->size; | ||
| 638 | map->handle = obj; | ||
| 639 | |||
| 640 | /* Get a DRM GEM mmap offset allocated... */ | ||
| 641 | list->file_offset_node = drm_mm_search_free(&mm->offset_manager, | ||
| 642 | obj->size / PAGE_SIZE, 0, 0); | ||
| 643 | if (!list->file_offset_node) { | ||
| 644 | DRM_ERROR("failed to allocate offset for bo %d\n", obj->name); | ||
| 645 | ret = -ENOMEM; | ||
| 646 | goto out_free_list; | ||
| 647 | } | ||
| 648 | |||
| 649 | list->file_offset_node = drm_mm_get_block(list->file_offset_node, | ||
| 650 | obj->size / PAGE_SIZE, 0); | ||
| 651 | if (!list->file_offset_node) { | ||
| 652 | ret = -ENOMEM; | ||
| 653 | goto out_free_list; | ||
| 654 | } | ||
| 655 | |||
| 656 | list->hash.key = list->file_offset_node->start; | ||
| 657 | if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) { | ||
| 658 | DRM_ERROR("failed to add to map hash\n"); | ||
| 659 | goto out_free_mm; | ||
| 660 | } | ||
| 661 | |||
| 662 | /* By now we should be all set, any drm_mmap request on the offset | ||
| 663 | * below will get to our mmap & fault handler */ | ||
| 664 | obj_priv->mmap_offset = ((uint64_t) list->hash.key) << PAGE_SHIFT; | ||
| 665 | |||
| 666 | return 0; | ||
| 667 | |||
| 668 | out_free_mm: | ||
| 669 | drm_mm_put_block(list->file_offset_node); | ||
| 670 | out_free_list: | ||
| 671 | drm_free(list->map, sizeof(struct drm_map_list), DRM_MEM_DRIVER); | ||
| 672 | |||
| 673 | return ret; | ||
| 674 | } | ||
| 675 | |||
| 676 | /** | ||
| 677 | * i915_gem_get_gtt_alignment - return required GTT alignment for an object | ||
| 678 | * @obj: object to check | ||
| 679 | * | ||
| 680 | * Return the required GTT alignment for an object, taking into account | ||
| 681 | * potential fence register mapping if needed. | ||
| 682 | */ | ||
| 683 | static uint32_t | ||
| 684 | i915_gem_get_gtt_alignment(struct drm_gem_object *obj) | ||
| 685 | { | ||
| 686 | struct drm_device *dev = obj->dev; | ||
| 687 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
| 688 | int start, i; | ||
| 689 | |||
| 690 | /* | ||
| 691 | * Minimum alignment is 4k (GTT page size), but might be greater | ||
| 692 | * if a fence register is needed for the object. | ||
| 693 | */ | ||
| 694 | if (IS_I965G(dev) || obj_priv->tiling_mode == I915_TILING_NONE) | ||
| 695 | return 4096; | ||
| 696 | |||
| 697 | /* | ||
| 698 | * Previous chips need to be aligned to the size of the smallest | ||
| 699 | * fence register that can contain the object. | ||
| 700 | */ | ||
| 701 | if (IS_I9XX(dev)) | ||
| 702 | start = 1024*1024; | ||
| 703 | else | ||
| 704 | start = 512*1024; | ||
| 705 | |||
| 706 | for (i = start; i < obj->size; i <<= 1) | ||
| 707 | ; | ||
| 708 | |||
| 709 | return i; | ||
| 710 | } | ||
| 711 | |||
| 712 | /** | ||
| 713 | * i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing | ||
| 714 | * @dev: DRM device | ||
| 715 | * @data: GTT mapping ioctl data | ||
| 716 | * @file_priv: GEM object info | ||
| 717 | * | ||
| 718 | * Simply returns the fake offset to userspace so it can mmap it. | ||
| 719 | * The mmap call will end up in drm_gem_mmap(), which will set things | ||
| 720 | * up so we can get faults in the handler above. | ||
| 721 | * | ||
| 722 | * The fault handler will take care of binding the object into the GTT | ||
| 723 | * (since it may have been evicted to make room for something), allocating | ||
| 724 | * a fence register, and mapping the appropriate aperture address into | ||
| 725 | * userspace. | ||
| 726 | */ | ||
| 727 | int | ||
| 728 | i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, | ||
| 729 | struct drm_file *file_priv) | ||
| 730 | { | ||
| 731 | struct drm_i915_gem_mmap_gtt *args = data; | ||
| 732 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 733 | struct drm_gem_object *obj; | ||
| 734 | struct drm_i915_gem_object *obj_priv; | ||
| 735 | int ret; | ||
| 736 | |||
| 737 | if (!(dev->driver->driver_features & DRIVER_GEM)) | ||
| 738 | return -ENODEV; | ||
| 739 | |||
| 740 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | ||
| 741 | if (obj == NULL) | ||
| 742 | return -EBADF; | ||
| 743 | |||
| 744 | mutex_lock(&dev->struct_mutex); | ||
| 745 | |||
| 746 | obj_priv = obj->driver_private; | ||
| 747 | |||
| 748 | if (!obj_priv->mmap_offset) { | ||
| 749 | ret = i915_gem_create_mmap_offset(obj); | ||
| 750 | if (ret) | ||
| 751 | return ret; | ||
| 752 | } | ||
| 753 | |||
| 754 | args->offset = obj_priv->mmap_offset; | ||
| 755 | |||
| 756 | obj_priv->gtt_alignment = i915_gem_get_gtt_alignment(obj); | ||
| 757 | |||
| 758 | /* Make sure the alignment is correct for fence regs etc */ | ||
| 759 | if (obj_priv->agp_mem && | ||
| 760 | (obj_priv->gtt_offset & (obj_priv->gtt_alignment - 1))) { | ||
| 761 | drm_gem_object_unreference(obj); | ||
| 762 | mutex_unlock(&dev->struct_mutex); | ||
| 763 | return -EINVAL; | ||
| 764 | } | ||
| 765 | |||
| 766 | /* | ||
| 767 | * Pull it into the GTT so that we have a page list (makes the | ||
| 768 | * initial fault faster and any subsequent flushing possible). | ||
| 769 | */ | ||
| 770 | if (!obj_priv->agp_mem) { | ||
| 771 | ret = i915_gem_object_bind_to_gtt(obj, obj_priv->gtt_alignment); | ||
| 772 | if (ret) { | ||
| 773 | drm_gem_object_unreference(obj); | ||
| 774 | mutex_unlock(&dev->struct_mutex); | ||
| 775 | return ret; | ||
| 776 | } | ||
| 777 | list_add(&obj_priv->list, &dev_priv->mm.inactive_list); | ||
| 778 | } | ||
| 779 | |||
| 780 | drm_gem_object_unreference(obj); | ||
| 781 | mutex_unlock(&dev->struct_mutex); | ||
| 782 | |||
| 783 | return 0; | ||
| 784 | } | ||
| 785 | |||
| 532 | static void | 786 | static void |
| 533 | i915_gem_object_free_page_list(struct drm_gem_object *obj) | 787 | i915_gem_object_free_page_list(struct drm_gem_object *obj) |
| 534 | { | 788 | { |
| @@ -726,6 +980,7 @@ i915_gem_retire_request(struct drm_device *dev, | |||
| 726 | */ | 980 | */ |
| 727 | if (obj_priv->last_rendering_seqno != request->seqno) | 981 | if (obj_priv->last_rendering_seqno != request->seqno) |
| 728 | return; | 982 | return; |
| 983 | |||
| 729 | #if WATCH_LRU | 984 | #if WATCH_LRU |
| 730 | DRM_INFO("%s: retire %d moves to inactive list %p\n", | 985 | DRM_INFO("%s: retire %d moves to inactive list %p\n", |
| 731 | __func__, request->seqno, obj); | 986 | __func__, request->seqno, obj); |
| @@ -956,6 +1211,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) | |||
| 956 | { | 1211 | { |
| 957 | struct drm_device *dev = obj->dev; | 1212 | struct drm_device *dev = obj->dev; |
| 958 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 1213 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
| 1214 | loff_t offset; | ||
| 959 | int ret = 0; | 1215 | int ret = 0; |
| 960 | 1216 | ||
| 961 | #if WATCH_BUF | 1217 | #if WATCH_BUF |
| @@ -991,6 +1247,14 @@ i915_gem_object_unbind(struct drm_gem_object *obj) | |||
| 991 | 1247 | ||
| 992 | BUG_ON(obj_priv->active); | 1248 | BUG_ON(obj_priv->active); |
| 993 | 1249 | ||
| 1250 | /* blow away mappings if mapped through GTT */ | ||
| 1251 | offset = ((loff_t) obj->map_list.hash.key) << PAGE_SHIFT; | ||
| 1252 | if (dev->dev_mapping) | ||
| 1253 | unmap_mapping_range(dev->dev_mapping, offset, obj->size, 1); | ||
| 1254 | |||
| 1255 | if (obj_priv->fence_reg != I915_FENCE_REG_NONE) | ||
| 1256 | i915_gem_clear_fence_reg(obj); | ||
| 1257 | |||
| 994 | i915_gem_object_free_page_list(obj); | 1258 | i915_gem_object_free_page_list(obj); |
| 995 | 1259 | ||
| 996 | if (obj_priv->gtt_space) { | 1260 | if (obj_priv->gtt_space) { |
| @@ -1149,6 +1413,204 @@ i915_gem_object_get_page_list(struct drm_gem_object *obj) | |||
| 1149 | return 0; | 1413 | return 0; |
| 1150 | } | 1414 | } |
| 1151 | 1415 | ||
| 1416 | static void i965_write_fence_reg(struct drm_i915_fence_reg *reg) | ||
| 1417 | { | ||
| 1418 | struct drm_gem_object *obj = reg->obj; | ||
| 1419 | struct drm_device *dev = obj->dev; | ||
| 1420 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 1421 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
| 1422 | int regnum = obj_priv->fence_reg; | ||
| 1423 | uint64_t val; | ||
| 1424 | |||
| 1425 | val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) & | ||
| 1426 | 0xfffff000) << 32; | ||
| 1427 | val |= obj_priv->gtt_offset & 0xfffff000; | ||
| 1428 | val |= ((obj_priv->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT; | ||
| 1429 | if (obj_priv->tiling_mode == I915_TILING_Y) | ||
| 1430 | val |= 1 << I965_FENCE_TILING_Y_SHIFT; | ||
| 1431 | val |= I965_FENCE_REG_VALID; | ||
| 1432 | |||
| 1433 | I915_WRITE64(FENCE_REG_965_0 + (regnum * 8), val); | ||
| 1434 | } | ||
| 1435 | |||
| 1436 | static void i915_write_fence_reg(struct drm_i915_fence_reg *reg) | ||
| 1437 | { | ||
| 1438 | struct drm_gem_object *obj = reg->obj; | ||
| 1439 | struct drm_device *dev = obj->dev; | ||
| 1440 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 1441 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
| 1442 | int regnum = obj_priv->fence_reg; | ||
| 1443 | uint32_t val; | ||
| 1444 | uint32_t pitch_val; | ||
| 1445 | |||
| 1446 | if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) || | ||
| 1447 | (obj_priv->gtt_offset & (obj->size - 1))) { | ||
| 1448 | WARN(1, "%s: object not 1M or size aligned\n", __FUNCTION__); | ||
| 1449 | return; | ||
| 1450 | } | ||
| 1451 | |||
| 1452 | if (obj_priv->tiling_mode == I915_TILING_Y && (IS_I945G(dev) || | ||
| 1453 | IS_I945GM(dev) || | ||
| 1454 | IS_G33(dev))) | ||
| 1455 | pitch_val = (obj_priv->stride / 128) - 1; | ||
| 1456 | else | ||
| 1457 | pitch_val = (obj_priv->stride / 512) - 1; | ||
| 1458 | |||
| 1459 | val = obj_priv->gtt_offset; | ||
| 1460 | if (obj_priv->tiling_mode == I915_TILING_Y) | ||
| 1461 | val |= 1 << I830_FENCE_TILING_Y_SHIFT; | ||
| 1462 | val |= I915_FENCE_SIZE_BITS(obj->size); | ||
| 1463 | val |= pitch_val << I830_FENCE_PITCH_SHIFT; | ||
| 1464 | val |= I830_FENCE_REG_VALID; | ||
| 1465 | |||
| 1466 | I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); | ||
| 1467 | } | ||
| 1468 | |||
| 1469 | static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) | ||
| 1470 | { | ||
| 1471 | struct drm_gem_object *obj = reg->obj; | ||
| 1472 | struct drm_device *dev = obj->dev; | ||
| 1473 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 1474 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
| 1475 | int regnum = obj_priv->fence_reg; | ||
| 1476 | uint32_t val; | ||
| 1477 | uint32_t pitch_val; | ||
| 1478 | |||
| 1479 | if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) || | ||
| 1480 | (obj_priv->gtt_offset & (obj->size - 1))) { | ||
| 1481 | WARN(1, "%s: object not 1M or size aligned\n", __FUNCTION__); | ||
| 1482 | return; | ||
| 1483 | } | ||
| 1484 | |||
| 1485 | pitch_val = (obj_priv->stride / 128) - 1; | ||
| 1486 | |||
| 1487 | val = obj_priv->gtt_offset; | ||
| 1488 | if (obj_priv->tiling_mode == I915_TILING_Y) | ||
| 1489 | val |= 1 << I830_FENCE_TILING_Y_SHIFT; | ||
| 1490 | val |= I830_FENCE_SIZE_BITS(obj->size); | ||
| 1491 | val |= pitch_val << I830_FENCE_PITCH_SHIFT; | ||
| 1492 | val |= I830_FENCE_REG_VALID; | ||
| 1493 | |||
| 1494 | I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); | ||
| 1495 | |||
| 1496 | } | ||
| 1497 | |||
| 1498 | /** | ||
| 1499 | * i915_gem_object_get_fence_reg - set up a fence reg for an object | ||
| 1500 | * @obj: object to map through a fence reg | ||
| 1501 | * | ||
| 1502 | * When mapping objects through the GTT, userspace wants to be able to write | ||
| 1503 | * to them without having to worry about swizzling if the object is tiled. | ||
| 1504 | * | ||
| 1505 | * This function walks the fence regs looking for a free one for @obj, | ||
| 1506 | * stealing one if it can't find any. | ||
| 1507 | * | ||
| 1508 | * It then sets up the reg based on the object's properties: address, pitch | ||
| 1509 | * and tiling format. | ||
| 1510 | */ | ||
| 1511 | static void | ||
| 1512 | i915_gem_object_get_fence_reg(struct drm_gem_object *obj) | ||
| 1513 | { | ||
| 1514 | struct drm_device *dev = obj->dev; | ||
| 1515 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 1516 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
| 1517 | struct drm_i915_fence_reg *reg = NULL; | ||
| 1518 | int i, ret; | ||
| 1519 | |||
| 1520 | switch (obj_priv->tiling_mode) { | ||
| 1521 | case I915_TILING_NONE: | ||
| 1522 | WARN(1, "allocating a fence for non-tiled object?\n"); | ||
| 1523 | break; | ||
| 1524 | case I915_TILING_X: | ||
| 1525 | WARN(obj_priv->stride & (512 - 1), | ||
| 1526 | "object is X tiled but has non-512B pitch\n"); | ||
| 1527 | break; | ||
| 1528 | case I915_TILING_Y: | ||
| 1529 | WARN(obj_priv->stride & (128 - 1), | ||
| 1530 | "object is Y tiled but has non-128B pitch\n"); | ||
| 1531 | break; | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | /* First try to find a free reg */ | ||
| 1535 | for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { | ||
| 1536 | reg = &dev_priv->fence_regs[i]; | ||
| 1537 | if (!reg->obj) | ||
| 1538 | break; | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | /* None available, try to steal one or wait for a user to finish */ | ||
| 1542 | if (i == dev_priv->num_fence_regs) { | ||
| 1543 | struct drm_i915_gem_object *old_obj_priv = NULL; | ||
| 1544 | loff_t offset; | ||
| 1545 | |||
| 1546 | try_again: | ||
| 1547 | /* Could try to use LRU here instead... */ | ||
| 1548 | for (i = dev_priv->fence_reg_start; | ||
| 1549 | i < dev_priv->num_fence_regs; i++) { | ||
| 1550 | reg = &dev_priv->fence_regs[i]; | ||
| 1551 | old_obj_priv = reg->obj->driver_private; | ||
| 1552 | if (!old_obj_priv->pin_count) | ||
| 1553 | break; | ||
| 1554 | } | ||
| 1555 | |||
| 1556 | /* | ||
| 1557 | * Now things get ugly... we have to wait for one of the | ||
| 1558 | * objects to finish before trying again. | ||
| 1559 | */ | ||
| 1560 | if (i == dev_priv->num_fence_regs) { | ||
| 1561 | ret = i915_gem_object_wait_rendering(reg->obj); | ||
| 1562 | if (ret) { | ||
| 1563 | WARN(ret, "wait_rendering failed: %d\n", ret); | ||
| 1564 | return; | ||
| 1565 | } | ||
| 1566 | goto try_again; | ||
| 1567 | } | ||
| 1568 | |||
| 1569 | /* | ||
| 1570 | * Zap this virtual mapping so we can set up a fence again | ||
| 1571 | * for this object next time we need it. | ||
| 1572 | */ | ||
| 1573 | offset = ((loff_t) reg->obj->map_list.hash.key) << PAGE_SHIFT; | ||
| 1574 | if (dev->dev_mapping) | ||
| 1575 | unmap_mapping_range(dev->dev_mapping, offset, | ||
| 1576 | reg->obj->size, 1); | ||
| 1577 | old_obj_priv->fence_reg = I915_FENCE_REG_NONE; | ||
| 1578 | } | ||
| 1579 | |||
| 1580 | obj_priv->fence_reg = i; | ||
| 1581 | reg->obj = obj; | ||
| 1582 | |||
| 1583 | if (IS_I965G(dev)) | ||
| 1584 | i965_write_fence_reg(reg); | ||
| 1585 | else if (IS_I9XX(dev)) | ||
| 1586 | i915_write_fence_reg(reg); | ||
| 1587 | else | ||
| 1588 | i830_write_fence_reg(reg); | ||
| 1589 | } | ||
| 1590 | |||
| 1591 | /** | ||
| 1592 | * i915_gem_clear_fence_reg - clear out fence register info | ||
| 1593 | * @obj: object to clear | ||
| 1594 | * | ||
| 1595 | * Zeroes out the fence register itself and clears out the associated | ||
| 1596 | * data structures in dev_priv and obj_priv. | ||
| 1597 | */ | ||
| 1598 | static void | ||
| 1599 | i915_gem_clear_fence_reg(struct drm_gem_object *obj) | ||
| 1600 | { | ||
| 1601 | struct drm_device *dev = obj->dev; | ||
| 1602 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 1603 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
| 1604 | |||
| 1605 | if (IS_I965G(dev)) | ||
| 1606 | I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0); | ||
| 1607 | else | ||
| 1608 | I915_WRITE(FENCE_REG_830_0 + (obj_priv->fence_reg * 4), 0); | ||
| 1609 | |||
| 1610 | dev_priv->fence_regs[obj_priv->fence_reg].obj = NULL; | ||
| 1611 | obj_priv->fence_reg = I915_FENCE_REG_NONE; | ||
| 1612 | } | ||
| 1613 | |||
| 1152 | /** | 1614 | /** |
| 1153 | * Finds free space in the GTT aperture and binds the object there. | 1615 | * Finds free space in the GTT aperture and binds the object there. |
| 1154 | */ | 1616 | */ |
| @@ -1307,7 +1769,7 @@ i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj) | |||
| 1307 | * This function returns when the move is complete, including waiting on | 1769 | * This function returns when the move is complete, including waiting on |
| 1308 | * flushes to occur. | 1770 | * flushes to occur. |
| 1309 | */ | 1771 | */ |
| 1310 | static int | 1772 | int |
| 1311 | i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) | 1773 | i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) |
| 1312 | { | 1774 | { |
| 1313 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 1775 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
| @@ -2029,13 +2491,15 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | |||
| 2029 | 2491 | ||
| 2030 | /* error other than GTT full, or we've already tried again */ | 2492 | /* error other than GTT full, or we've already tried again */ |
| 2031 | if (ret != -ENOMEM || pin_tries >= 1) { | 2493 | if (ret != -ENOMEM || pin_tries >= 1) { |
| 2032 | DRM_ERROR("Failed to pin buffers %d\n", ret); | 2494 | if (ret != -ERESTARTSYS) |
| 2495 | DRM_ERROR("Failed to pin buffers %d\n", ret); | ||
| 2033 | goto err; | 2496 | goto err; |
| 2034 | } | 2497 | } |
| 2035 | 2498 | ||
| 2036 | /* unpin all of our buffers */ | 2499 | /* unpin all of our buffers */ |
| 2037 | for (i = 0; i < pinned; i++) | 2500 | for (i = 0; i < pinned; i++) |
| 2038 | i915_gem_object_unpin(object_list[i]); | 2501 | i915_gem_object_unpin(object_list[i]); |
| 2502 | pinned = 0; | ||
| 2039 | 2503 | ||
| 2040 | /* evict everyone we can from the aperture */ | 2504 | /* evict everyone we can from the aperture */ |
| 2041 | ret = i915_gem_evict_everything(dev); | 2505 | ret = i915_gem_evict_everything(dev); |
| @@ -2149,13 +2613,12 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | |||
| 2149 | "back to user (%d)\n", | 2613 | "back to user (%d)\n", |
| 2150 | args->buffer_count, ret); | 2614 | args->buffer_count, ret); |
| 2151 | err: | 2615 | err: |
| 2152 | if (object_list != NULL) { | 2616 | for (i = 0; i < pinned; i++) |
| 2153 | for (i = 0; i < pinned; i++) | 2617 | i915_gem_object_unpin(object_list[i]); |
| 2154 | i915_gem_object_unpin(object_list[i]); | 2618 | |
| 2619 | for (i = 0; i < args->buffer_count; i++) | ||
| 2620 | drm_gem_object_unreference(object_list[i]); | ||
| 2155 | 2621 | ||
| 2156 | for (i = 0; i < args->buffer_count; i++) | ||
| 2157 | drm_gem_object_unreference(object_list[i]); | ||
| 2158 | } | ||
| 2159 | mutex_unlock(&dev->struct_mutex); | 2622 | mutex_unlock(&dev->struct_mutex); |
| 2160 | 2623 | ||
| 2161 | pre_mutex_err: | 2624 | pre_mutex_err: |
| @@ -2178,7 +2641,8 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) | |||
| 2178 | if (obj_priv->gtt_space == NULL) { | 2641 | if (obj_priv->gtt_space == NULL) { |
| 2179 | ret = i915_gem_object_bind_to_gtt(obj, alignment); | 2642 | ret = i915_gem_object_bind_to_gtt(obj, alignment); |
| 2180 | if (ret != 0) { | 2643 | if (ret != 0) { |
| 2181 | DRM_ERROR("Failure to bind: %d", ret); | 2644 | if (ret != -ERESTARTSYS) |
| 2645 | DRM_ERROR("Failure to bind: %d", ret); | ||
| 2182 | return ret; | 2646 | return ret; |
| 2183 | } | 2647 | } |
| 2184 | } | 2648 | } |
| @@ -2249,11 +2713,22 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, | |||
| 2249 | } | 2713 | } |
| 2250 | obj_priv = obj->driver_private; | 2714 | obj_priv = obj->driver_private; |
| 2251 | 2715 | ||
| 2252 | ret = i915_gem_object_pin(obj, args->alignment); | 2716 | if (obj_priv->pin_filp != NULL && obj_priv->pin_filp != file_priv) { |
| 2253 | if (ret != 0) { | 2717 | DRM_ERROR("Already pinned in i915_gem_pin_ioctl(): %d\n", |
| 2254 | drm_gem_object_unreference(obj); | 2718 | args->handle); |
| 2255 | mutex_unlock(&dev->struct_mutex); | 2719 | mutex_unlock(&dev->struct_mutex); |
| 2256 | return ret; | 2720 | return -EINVAL; |
| 2721 | } | ||
| 2722 | |||
| 2723 | obj_priv->user_pin_count++; | ||
| 2724 | obj_priv->pin_filp = file_priv; | ||
| 2725 | if (obj_priv->user_pin_count == 1) { | ||
| 2726 | ret = i915_gem_object_pin(obj, args->alignment); | ||
| 2727 | if (ret != 0) { | ||
| 2728 | drm_gem_object_unreference(obj); | ||
| 2729 | mutex_unlock(&dev->struct_mutex); | ||
| 2730 | return ret; | ||
| 2731 | } | ||
| 2257 | } | 2732 | } |
| 2258 | 2733 | ||
| 2259 | /* XXX - flush the CPU caches for pinned objects | 2734 | /* XXX - flush the CPU caches for pinned objects |
| @@ -2273,6 +2748,7 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data, | |||
| 2273 | { | 2748 | { |
| 2274 | struct drm_i915_gem_pin *args = data; | 2749 | struct drm_i915_gem_pin *args = data; |
| 2275 | struct drm_gem_object *obj; | 2750 | struct drm_gem_object *obj; |
| 2751 | struct drm_i915_gem_object *obj_priv; | ||
| 2276 | 2752 | ||
| 2277 | mutex_lock(&dev->struct_mutex); | 2753 | mutex_lock(&dev->struct_mutex); |
| 2278 | 2754 | ||
| @@ -2284,7 +2760,19 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data, | |||
| 2284 | return -EBADF; | 2760 | return -EBADF; |
| 2285 | } | 2761 | } |
| 2286 | 2762 | ||
| 2287 | i915_gem_object_unpin(obj); | 2763 | obj_priv = obj->driver_private; |
| 2764 | if (obj_priv->pin_filp != file_priv) { | ||
| 2765 | DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n", | ||
| 2766 | args->handle); | ||
| 2767 | drm_gem_object_unreference(obj); | ||
| 2768 | mutex_unlock(&dev->struct_mutex); | ||
| 2769 | return -EINVAL; | ||
| 2770 | } | ||
| 2771 | obj_priv->user_pin_count--; | ||
| 2772 | if (obj_priv->user_pin_count == 0) { | ||
| 2773 | obj_priv->pin_filp = NULL; | ||
| 2774 | i915_gem_object_unpin(obj); | ||
| 2775 | } | ||
| 2288 | 2776 | ||
| 2289 | drm_gem_object_unreference(obj); | 2777 | drm_gem_object_unreference(obj); |
| 2290 | mutex_unlock(&dev->struct_mutex); | 2778 | mutex_unlock(&dev->struct_mutex); |
| @@ -2351,12 +2839,18 @@ int i915_gem_init_object(struct drm_gem_object *obj) | |||
| 2351 | 2839 | ||
| 2352 | obj->driver_private = obj_priv; | 2840 | obj->driver_private = obj_priv; |
| 2353 | obj_priv->obj = obj; | 2841 | obj_priv->obj = obj; |
| 2842 | obj_priv->fence_reg = I915_FENCE_REG_NONE; | ||
| 2354 | INIT_LIST_HEAD(&obj_priv->list); | 2843 | INIT_LIST_HEAD(&obj_priv->list); |
| 2844 | |||
| 2355 | return 0; | 2845 | return 0; |
| 2356 | } | 2846 | } |
| 2357 | 2847 | ||
| 2358 | void i915_gem_free_object(struct drm_gem_object *obj) | 2848 | void i915_gem_free_object(struct drm_gem_object *obj) |
| 2359 | { | 2849 | { |
| 2850 | struct drm_device *dev = obj->dev; | ||
| 2851 | struct drm_gem_mm *mm = dev->mm_private; | ||
| 2852 | struct drm_map_list *list; | ||
| 2853 | struct drm_map *map; | ||
| 2360 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 2854 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
| 2361 | 2855 | ||
| 2362 | while (obj_priv->pin_count > 0) | 2856 | while (obj_priv->pin_count > 0) |
| @@ -2364,6 +2858,20 @@ void i915_gem_free_object(struct drm_gem_object *obj) | |||
| 2364 | 2858 | ||
| 2365 | i915_gem_object_unbind(obj); | 2859 | i915_gem_object_unbind(obj); |
| 2366 | 2860 | ||
| 2861 | list = &obj->map_list; | ||
| 2862 | drm_ht_remove_item(&mm->offset_hash, &list->hash); | ||
| 2863 | |||
| 2864 | if (list->file_offset_node) { | ||
| 2865 | drm_mm_put_block(list->file_offset_node); | ||
| 2866 | list->file_offset_node = NULL; | ||
| 2867 | } | ||
| 2868 | |||
| 2869 | map = list->map; | ||
| 2870 | if (map) { | ||
| 2871 | drm_free(map, sizeof(*map), DRM_MEM_DRIVER); | ||
| 2872 | list->map = NULL; | ||
| 2873 | } | ||
| 2874 | |||
| 2367 | drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER); | 2875 | drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER); |
| 2368 | drm_free(obj->driver_private, 1, DRM_MEM_DRIVER); | 2876 | drm_free(obj->driver_private, 1, DRM_MEM_DRIVER); |
| 2369 | } | 2877 | } |
| @@ -2432,8 +2940,7 @@ i915_gem_idle(struct drm_device *dev) | |||
| 2432 | */ | 2940 | */ |
| 2433 | i915_gem_flush(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT), | 2941 | i915_gem_flush(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT), |
| 2434 | ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); | 2942 | ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); |
| 2435 | seqno = i915_add_request(dev, ~(I915_GEM_DOMAIN_CPU | | 2943 | seqno = i915_add_request(dev, ~I915_GEM_DOMAIN_CPU); |
| 2436 | I915_GEM_DOMAIN_GTT)); | ||
| 2437 | 2944 | ||
| 2438 | if (seqno == 0) { | 2945 | if (seqno == 0) { |
| 2439 | mutex_unlock(&dev->struct_mutex); | 2946 | mutex_unlock(&dev->struct_mutex); |
| @@ -2560,12 +3067,13 @@ i915_gem_init_hws(struct drm_device *dev) | |||
| 2560 | return 0; | 3067 | return 0; |
| 2561 | } | 3068 | } |
| 2562 | 3069 | ||
| 2563 | static int | 3070 | int |
| 2564 | i915_gem_init_ringbuffer(struct drm_device *dev) | 3071 | i915_gem_init_ringbuffer(struct drm_device *dev) |
| 2565 | { | 3072 | { |
| 2566 | drm_i915_private_t *dev_priv = dev->dev_private; | 3073 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 2567 | struct drm_gem_object *obj; | 3074 | struct drm_gem_object *obj; |
| 2568 | struct drm_i915_gem_object *obj_priv; | 3075 | struct drm_i915_gem_object *obj_priv; |
| 3076 | drm_i915_ring_buffer_t *ring = &dev_priv->ring; | ||
| 2569 | int ret; | 3077 | int ret; |
| 2570 | u32 head; | 3078 | u32 head; |
| 2571 | 3079 | ||
| @@ -2587,24 +3095,24 @@ i915_gem_init_ringbuffer(struct drm_device *dev) | |||
| 2587 | } | 3095 | } |
| 2588 | 3096 | ||
| 2589 | /* Set up the kernel mapping for the ring. */ | 3097 | /* Set up the kernel mapping for the ring. */ |
| 2590 | dev_priv->ring.Size = obj->size; | 3098 | ring->Size = obj->size; |
| 2591 | dev_priv->ring.tail_mask = obj->size - 1; | 3099 | ring->tail_mask = obj->size - 1; |
| 2592 | 3100 | ||
| 2593 | dev_priv->ring.map.offset = dev->agp->base + obj_priv->gtt_offset; | 3101 | ring->map.offset = dev->agp->base + obj_priv->gtt_offset; |
| 2594 | dev_priv->ring.map.size = obj->size; | 3102 | ring->map.size = obj->size; |
| 2595 | dev_priv->ring.map.type = 0; | 3103 | ring->map.type = 0; |
| 2596 | dev_priv->ring.map.flags = 0; | 3104 | ring->map.flags = 0; |
| 2597 | dev_priv->ring.map.mtrr = 0; | 3105 | ring->map.mtrr = 0; |
| 2598 | 3106 | ||
| 2599 | drm_core_ioremap_wc(&dev_priv->ring.map, dev); | 3107 | drm_core_ioremap_wc(&ring->map, dev); |
| 2600 | if (dev_priv->ring.map.handle == NULL) { | 3108 | if (ring->map.handle == NULL) { |
| 2601 | DRM_ERROR("Failed to map ringbuffer.\n"); | 3109 | DRM_ERROR("Failed to map ringbuffer.\n"); |
| 2602 | memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); | 3110 | memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); |
| 2603 | drm_gem_object_unreference(obj); | 3111 | drm_gem_object_unreference(obj); |
| 2604 | return -EINVAL; | 3112 | return -EINVAL; |
| 2605 | } | 3113 | } |
| 2606 | dev_priv->ring.ring_obj = obj; | 3114 | ring->ring_obj = obj; |
| 2607 | dev_priv->ring.virtual_start = dev_priv->ring.map.handle; | 3115 | ring->virtual_start = ring->map.handle; |
| 2608 | 3116 | ||
| 2609 | /* Stop the ring if it's running. */ | 3117 | /* Stop the ring if it's running. */ |
| 2610 | I915_WRITE(PRB0_CTL, 0); | 3118 | I915_WRITE(PRB0_CTL, 0); |
| @@ -2652,12 +3160,20 @@ i915_gem_init_ringbuffer(struct drm_device *dev) | |||
| 2652 | } | 3160 | } |
| 2653 | 3161 | ||
| 2654 | /* Update our cache of the ring state */ | 3162 | /* Update our cache of the ring state */ |
| 2655 | i915_kernel_lost_context(dev); | 3163 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
| 3164 | i915_kernel_lost_context(dev); | ||
| 3165 | else { | ||
| 3166 | ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; | ||
| 3167 | ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; | ||
| 3168 | ring->space = ring->head - (ring->tail + 8); | ||
| 3169 | if (ring->space < 0) | ||
| 3170 | ring->space += ring->Size; | ||
| 3171 | } | ||
| 2656 | 3172 | ||
| 2657 | return 0; | 3173 | return 0; |
| 2658 | } | 3174 | } |
| 2659 | 3175 | ||
| 2660 | static void | 3176 | void |
| 2661 | i915_gem_cleanup_ringbuffer(struct drm_device *dev) | 3177 | i915_gem_cleanup_ringbuffer(struct drm_device *dev) |
| 2662 | { | 3178 | { |
| 2663 | drm_i915_private_t *dev_priv = dev->dev_private; | 3179 | drm_i915_private_t *dev_priv = dev->dev_private; |
| @@ -2695,6 +3211,9 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, | |||
| 2695 | drm_i915_private_t *dev_priv = dev->dev_private; | 3211 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 2696 | int ret; | 3212 | int ret; |
| 2697 | 3213 | ||
| 3214 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
| 3215 | return 0; | ||
| 3216 | |||
| 2698 | if (dev_priv->mm.wedged) { | 3217 | if (dev_priv->mm.wedged) { |
| 2699 | DRM_ERROR("Reenabling wedged hardware, good luck\n"); | 3218 | DRM_ERROR("Reenabling wedged hardware, good luck\n"); |
| 2700 | dev_priv->mm.wedged = 0; | 3219 | dev_priv->mm.wedged = 0; |
| @@ -2728,6 +3247,9 @@ i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, | |||
| 2728 | drm_i915_private_t *dev_priv = dev->dev_private; | 3247 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 2729 | int ret; | 3248 | int ret; |
| 2730 | 3249 | ||
| 3250 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
| 3251 | return 0; | ||
| 3252 | |||
| 2731 | ret = i915_gem_idle(dev); | 3253 | ret = i915_gem_idle(dev); |
| 2732 | drm_irq_uninstall(dev); | 3254 | drm_irq_uninstall(dev); |
| 2733 | 3255 | ||
| @@ -2758,5 +3280,13 @@ i915_gem_load(struct drm_device *dev) | |||
| 2758 | i915_gem_retire_work_handler); | 3280 | i915_gem_retire_work_handler); |
| 2759 | dev_priv->mm.next_gem_seqno = 1; | 3281 | dev_priv->mm.next_gem_seqno = 1; |
| 2760 | 3282 | ||
| 3283 | /* Old X drivers will take 0-2 for front, back, depth buffers */ | ||
| 3284 | dev_priv->fence_reg_start = 3; | ||
| 3285 | |||
| 3286 | if (IS_I965G(dev)) | ||
| 3287 | dev_priv->num_fence_regs = 16; | ||
| 3288 | else | ||
| 3289 | dev_priv->num_fence_regs = 8; | ||
| 3290 | |||
| 2761 | i915_gem_detect_bit_6_swizzle(dev); | 3291 | i915_gem_detect_bit_6_swizzle(dev); |
| 2762 | } | 3292 | } |
diff --git a/drivers/gpu/drm/i915/i915_gem_proc.c b/drivers/gpu/drm/i915/i915_gem_proc.c index e8d5abe1250e..4d1b9de0cd8b 100644 --- a/drivers/gpu/drm/i915/i915_gem_proc.c +++ b/drivers/gpu/drm/i915/i915_gem_proc.c | |||
| @@ -250,6 +250,39 @@ static int i915_interrupt_info(char *buf, char **start, off_t offset, | |||
| 250 | return len - offset; | 250 | return len - offset; |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | static int i915_hws_info(char *buf, char **start, off_t offset, | ||
| 254 | int request, int *eof, void *data) | ||
| 255 | { | ||
| 256 | struct drm_minor *minor = (struct drm_minor *) data; | ||
| 257 | struct drm_device *dev = minor->dev; | ||
| 258 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
| 259 | int len = 0, i; | ||
| 260 | volatile u32 *hws; | ||
| 261 | |||
| 262 | if (offset > DRM_PROC_LIMIT) { | ||
| 263 | *eof = 1; | ||
| 264 | return 0; | ||
| 265 | } | ||
| 266 | |||
| 267 | hws = (volatile u32 *)dev_priv->hw_status_page; | ||
| 268 | if (hws == NULL) { | ||
| 269 | *eof = 1; | ||
| 270 | return 0; | ||
| 271 | } | ||
| 272 | |||
| 273 | *start = &buf[offset]; | ||
| 274 | *eof = 0; | ||
| 275 | for (i = 0; i < 4096 / sizeof(u32) / 4; i += 4) { | ||
| 276 | DRM_PROC_PRINT("0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n", | ||
| 277 | i * 4, | ||
| 278 | hws[i], hws[i + 1], hws[i + 2], hws[i + 3]); | ||
| 279 | } | ||
| 280 | if (len > request + offset) | ||
| 281 | return request; | ||
| 282 | *eof = 1; | ||
| 283 | return len - offset; | ||
| 284 | } | ||
| 285 | |||
| 253 | static struct drm_proc_list { | 286 | static struct drm_proc_list { |
| 254 | /** file name */ | 287 | /** file name */ |
| 255 | const char *name; | 288 | const char *name; |
| @@ -262,6 +295,7 @@ static struct drm_proc_list { | |||
| 262 | {"i915_gem_request", i915_gem_request_info}, | 295 | {"i915_gem_request", i915_gem_request_info}, |
| 263 | {"i915_gem_seqno", i915_gem_seqno_info}, | 296 | {"i915_gem_seqno", i915_gem_seqno_info}, |
| 264 | {"i915_gem_interrupt", i915_interrupt_info}, | 297 | {"i915_gem_interrupt", i915_interrupt_info}, |
| 298 | {"i915_gem_hws", i915_hws_info}, | ||
| 265 | }; | 299 | }; |
| 266 | 300 | ||
| 267 | #define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list) | 301 | #define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list) |
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index a8cb69469c64..241f39b7f460 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c | |||
| @@ -208,6 +208,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, | |||
| 208 | } | 208 | } |
| 209 | } | 209 | } |
| 210 | obj_priv->tiling_mode = args->tiling_mode; | 210 | obj_priv->tiling_mode = args->tiling_mode; |
| 211 | obj_priv->stride = args->stride; | ||
| 211 | 212 | ||
| 212 | mutex_unlock(&dev->struct_mutex); | 213 | mutex_unlock(&dev->struct_mutex); |
| 213 | 214 | ||
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 69b9a42da95e..0cadafbef411 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include "drm.h" | 30 | #include "drm.h" |
| 31 | #include "i915_drm.h" | 31 | #include "i915_drm.h" |
| 32 | #include "i915_drv.h" | 32 | #include "i915_drv.h" |
| 33 | #include "intel_drv.h" | ||
| 33 | 34 | ||
| 34 | #define MAX_NOPID ((u32)~0) | 35 | #define MAX_NOPID ((u32)~0) |
| 35 | 36 | ||
| @@ -51,6 +52,15 @@ | |||
| 51 | #define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \ | 52 | #define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \ |
| 52 | I915_INTERRUPT_ENABLE_VAR) | 53 | I915_INTERRUPT_ENABLE_VAR) |
| 53 | 54 | ||
| 55 | #define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\ | ||
| 56 | PIPE_VBLANK_INTERRUPT_STATUS) | ||
| 57 | |||
| 58 | #define I915_PIPE_VBLANK_ENABLE (PIPE_START_VBLANK_INTERRUPT_ENABLE |\ | ||
| 59 | PIPE_VBLANK_INTERRUPT_ENABLE) | ||
| 60 | |||
| 61 | #define DRM_I915_VBLANK_PIPE_ALL (DRM_I915_VBLANK_PIPE_A | \ | ||
| 62 | DRM_I915_VBLANK_PIPE_B) | ||
| 63 | |||
| 54 | void | 64 | void |
| 55 | i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) | 65 | i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) |
| 56 | { | 66 | { |
| @@ -168,6 +178,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 168 | { | 178 | { |
| 169 | struct drm_device *dev = (struct drm_device *) arg; | 179 | struct drm_device *dev = (struct drm_device *) arg; |
| 170 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 180 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 181 | struct drm_i915_master_private *master_priv; | ||
| 171 | u32 iir, new_iir; | 182 | u32 iir, new_iir; |
| 172 | u32 pipea_stats, pipeb_stats; | 183 | u32 pipea_stats, pipeb_stats; |
| 173 | u32 vblank_status; | 184 | u32 vblank_status; |
| @@ -200,6 +211,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 200 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); | 211 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); |
| 201 | pipea_stats = I915_READ(PIPEASTAT); | 212 | pipea_stats = I915_READ(PIPEASTAT); |
| 202 | pipeb_stats = I915_READ(PIPEBSTAT); | 213 | pipeb_stats = I915_READ(PIPEBSTAT); |
| 214 | |||
| 203 | /* | 215 | /* |
| 204 | * Clear the PIPE(A|B)STAT regs before the IIR | 216 | * Clear the PIPE(A|B)STAT regs before the IIR |
| 205 | */ | 217 | */ |
| @@ -222,9 +234,12 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 222 | I915_WRITE(IIR, iir); | 234 | I915_WRITE(IIR, iir); |
| 223 | new_iir = I915_READ(IIR); /* Flush posted writes */ | 235 | new_iir = I915_READ(IIR); /* Flush posted writes */ |
| 224 | 236 | ||
| 225 | if (dev_priv->sarea_priv) | 237 | if (dev->primary->master) { |
| 226 | dev_priv->sarea_priv->last_dispatch = | 238 | master_priv = dev->primary->master->driver_priv; |
| 227 | READ_BREADCRUMB(dev_priv); | 239 | if (master_priv->sarea_priv) |
| 240 | master_priv->sarea_priv->last_dispatch = | ||
| 241 | READ_BREADCRUMB(dev_priv); | ||
| 242 | } | ||
| 228 | 243 | ||
| 229 | if (iir & I915_USER_INTERRUPT) { | 244 | if (iir & I915_USER_INTERRUPT) { |
| 230 | dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); | 245 | dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); |
| @@ -269,6 +284,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
| 269 | static int i915_emit_irq(struct drm_device * dev) | 284 | static int i915_emit_irq(struct drm_device * dev) |
| 270 | { | 285 | { |
| 271 | drm_i915_private_t *dev_priv = dev->dev_private; | 286 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 287 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; | ||
| 272 | RING_LOCALS; | 288 | RING_LOCALS; |
| 273 | 289 | ||
| 274 | i915_kernel_lost_context(dev); | 290 | i915_kernel_lost_context(dev); |
| @@ -278,8 +294,8 @@ static int i915_emit_irq(struct drm_device * dev) | |||
| 278 | dev_priv->counter++; | 294 | dev_priv->counter++; |
| 279 | if (dev_priv->counter > 0x7FFFFFFFUL) | 295 | if (dev_priv->counter > 0x7FFFFFFFUL) |
| 280 | dev_priv->counter = 1; | 296 | dev_priv->counter = 1; |
| 281 | if (dev_priv->sarea_priv) | 297 | if (master_priv->sarea_priv) |
| 282 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter; | 298 | master_priv->sarea_priv->last_enqueue = dev_priv->counter; |
| 283 | 299 | ||
| 284 | BEGIN_LP_RING(4); | 300 | BEGIN_LP_RING(4); |
| 285 | OUT_RING(MI_STORE_DWORD_INDEX); | 301 | OUT_RING(MI_STORE_DWORD_INDEX); |
| @@ -317,21 +333,20 @@ void i915_user_irq_put(struct drm_device *dev) | |||
| 317 | static int i915_wait_irq(struct drm_device * dev, int irq_nr) | 333 | static int i915_wait_irq(struct drm_device * dev, int irq_nr) |
| 318 | { | 334 | { |
| 319 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 335 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 336 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; | ||
| 320 | int ret = 0; | 337 | int ret = 0; |
| 321 | 338 | ||
| 322 | DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, | 339 | DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, |
| 323 | READ_BREADCRUMB(dev_priv)); | 340 | READ_BREADCRUMB(dev_priv)); |
| 324 | 341 | ||
| 325 | if (READ_BREADCRUMB(dev_priv) >= irq_nr) { | 342 | if (READ_BREADCRUMB(dev_priv) >= irq_nr) { |
| 326 | if (dev_priv->sarea_priv) { | 343 | if (master_priv->sarea_priv) |
| 327 | dev_priv->sarea_priv->last_dispatch = | 344 | master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); |
| 328 | READ_BREADCRUMB(dev_priv); | ||
| 329 | } | ||
| 330 | return 0; | 345 | return 0; |
| 331 | } | 346 | } |
| 332 | 347 | ||
| 333 | if (dev_priv->sarea_priv) | 348 | if (master_priv->sarea_priv) |
| 334 | dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; | 349 | master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; |
| 335 | 350 | ||
| 336 | i915_user_irq_get(dev); | 351 | i915_user_irq_get(dev); |
| 337 | DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, | 352 | DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, |
| @@ -343,10 +358,6 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) | |||
| 343 | READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); | 358 | READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); |
| 344 | } | 359 | } |
| 345 | 360 | ||
| 346 | if (dev_priv->sarea_priv) | ||
| 347 | dev_priv->sarea_priv->last_dispatch = | ||
| 348 | READ_BREADCRUMB(dev_priv); | ||
| 349 | |||
| 350 | return ret; | 361 | return ret; |
| 351 | } | 362 | } |
| 352 | 363 | ||
| @@ -427,6 +438,14 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) | |||
| 427 | spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); | 438 | spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); |
| 428 | } | 439 | } |
| 429 | 440 | ||
| 441 | void i915_enable_interrupt (struct drm_device *dev) | ||
| 442 | { | ||
| 443 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 444 | opregion_enable_asle(dev); | ||
| 445 | dev_priv->irq_enabled = 1; | ||
| 446 | } | ||
| 447 | |||
| 448 | |||
| 430 | /* Set the vblank monitor pipe | 449 | /* Set the vblank monitor pipe |
| 431 | */ | 450 | */ |
| 432 | int i915_vblank_pipe_set(struct drm_device *dev, void *data, | 451 | int i915_vblank_pipe_set(struct drm_device *dev, void *data, |
| @@ -487,6 +506,8 @@ void i915_driver_irq_preinstall(struct drm_device * dev) | |||
| 487 | { | 506 | { |
| 488 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 507 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
| 489 | 508 | ||
| 509 | atomic_set(&dev_priv->irq_received, 0); | ||
| 510 | |||
| 490 | I915_WRITE(HWSTAM, 0xeffe); | 511 | I915_WRITE(HWSTAM, 0xeffe); |
| 491 | I915_WRITE(PIPEASTAT, 0); | 512 | I915_WRITE(PIPEASTAT, 0); |
| 492 | I915_WRITE(PIPEBSTAT, 0); | 513 | I915_WRITE(PIPEBSTAT, 0); |
diff --git a/drivers/gpu/drm/i915/i915_mem.c b/drivers/gpu/drm/i915/i915_mem.c index 6126a60dc9cb..96e271986d2a 100644 --- a/drivers/gpu/drm/i915/i915_mem.c +++ b/drivers/gpu/drm/i915/i915_mem.c | |||
| @@ -46,7 +46,8 @@ | |||
| 46 | static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use) | 46 | static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use) |
| 47 | { | 47 | { |
| 48 | drm_i915_private_t *dev_priv = dev->dev_private; | 48 | drm_i915_private_t *dev_priv = dev->dev_private; |
| 49 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; | 49 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; |
| 50 | drm_i915_sarea_t *sarea_priv = master_priv->sarea_priv; | ||
| 50 | struct drm_tex_region *list; | 51 | struct drm_tex_region *list; |
| 51 | unsigned shift, nr; | 52 | unsigned shift, nr; |
| 52 | unsigned start; | 53 | unsigned start; |
diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c index 13ae731a33db..ff012835a386 100644 --- a/drivers/gpu/drm/i915/i915_opregion.c +++ b/drivers/gpu/drm/i915/i915_opregion.c | |||
| @@ -257,8 +257,8 @@ void opregion_enable_asle(struct drm_device *dev) | |||
| 257 | 257 | ||
| 258 | static struct intel_opregion *system_opregion; | 258 | static struct intel_opregion *system_opregion; |
| 259 | 259 | ||
| 260 | int intel_opregion_video_event(struct notifier_block *nb, unsigned long val, | 260 | static int intel_opregion_video_event(struct notifier_block *nb, |
| 261 | void *data) | 261 | unsigned long val, void *data) |
| 262 | { | 262 | { |
| 263 | /* The only video events relevant to opregion are 0x80. These indicate | 263 | /* The only video events relevant to opregion are 0x80. These indicate |
| 264 | either a docking event, lid switch or display switch request. In | 264 | either a docking event, lid switch or display switch request. In |
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9d24aaeb8a45..47e6bafeb743 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
| @@ -175,9 +175,26 @@ | |||
| 175 | #define DISPLAY_PLANE_B (1<<20) | 175 | #define DISPLAY_PLANE_B (1<<20) |
| 176 | 176 | ||
| 177 | /* | 177 | /* |
| 178 | * Instruction and interrupt control regs | 178 | * Fence registers |
| 179 | */ | 179 | */ |
| 180 | #define FENCE_REG_830_0 0x2000 | ||
| 181 | #define I830_FENCE_START_MASK 0x07f80000 | ||
| 182 | #define I830_FENCE_TILING_Y_SHIFT 12 | ||
| 183 | #define I830_FENCE_SIZE_BITS(size) ((get_order(size >> 19) - 1) << 8) | ||
| 184 | #define I830_FENCE_PITCH_SHIFT 4 | ||
| 185 | #define I830_FENCE_REG_VALID (1<<0) | ||
| 186 | |||
| 187 | #define I915_FENCE_START_MASK 0x0ff00000 | ||
| 188 | #define I915_FENCE_SIZE_BITS(size) ((get_order(size >> 20) - 1) << 8) | ||
| 180 | 189 | ||
| 190 | #define FENCE_REG_965_0 0x03000 | ||
| 191 | #define I965_FENCE_PITCH_SHIFT 2 | ||
| 192 | #define I965_FENCE_TILING_Y_SHIFT 1 | ||
| 193 | #define I965_FENCE_REG_VALID (1<<0) | ||
| 194 | |||
| 195 | /* | ||
| 196 | * Instruction and interrupt control regs | ||
| 197 | */ | ||
| 181 | #define PRB0_TAIL 0x02030 | 198 | #define PRB0_TAIL 0x02030 |
| 182 | #define PRB0_HEAD 0x02034 | 199 | #define PRB0_HEAD 0x02034 |
| 183 | #define PRB0_START 0x02038 | 200 | #define PRB0_START 0x02038 |
| @@ -245,6 +262,7 @@ | |||
| 245 | #define CM0_RC_OP_FLUSH_DISABLE (1<<0) | 262 | #define CM0_RC_OP_FLUSH_DISABLE (1<<0) |
| 246 | #define GFX_FLSH_CNTL 0x02170 /* 915+ only */ | 263 | #define GFX_FLSH_CNTL 0x02170 /* 915+ only */ |
| 247 | 264 | ||
| 265 | |||
| 248 | /* | 266 | /* |
| 249 | * Framebuffer compression (915+ only) | 267 | * Framebuffer compression (915+ only) |
| 250 | */ | 268 | */ |
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c new file mode 100644 index 000000000000..4ca82a025525 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_bios.c | |||
| @@ -0,0 +1,193 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2006 Intel Corporation | ||
| 3 | * | ||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 5 | * copy of this software and associated documentation files (the "Software"), | ||
| 6 | * to deal in the Software without restriction, including without limitation | ||
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 9 | * Software is furnished to do so, subject to the following conditions: | ||
| 10 | * | ||
| 11 | * The above copyright notice and this permission notice (including the next | ||
| 12 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 13 | * Software. | ||
| 14 | * | ||
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 21 | * SOFTWARE. | ||
| 22 | * | ||
| 23 | * Authors: | ||
| 24 | * Eric Anholt <eric@anholt.net> | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | #include "drmP.h" | ||
| 28 | #include "drm.h" | ||
| 29 | #include "i915_drm.h" | ||
| 30 | #include "i915_drv.h" | ||
| 31 | #include "intel_bios.h" | ||
| 32 | |||
| 33 | |||
| 34 | static void * | ||
| 35 | find_section(struct bdb_header *bdb, int section_id) | ||
| 36 | { | ||
| 37 | u8 *base = (u8 *)bdb; | ||
| 38 | int index = 0; | ||
| 39 | u16 total, current_size; | ||
| 40 | u8 current_id; | ||
| 41 | |||
| 42 | /* skip to first section */ | ||
| 43 | index += bdb->header_size; | ||
| 44 | total = bdb->bdb_size; | ||
| 45 | |||
| 46 | /* walk the sections looking for section_id */ | ||
| 47 | while (index < total) { | ||
| 48 | current_id = *(base + index); | ||
| 49 | index++; | ||
| 50 | current_size = *((u16 *)(base + index)); | ||
| 51 | index += 2; | ||
| 52 | if (current_id == section_id) | ||
| 53 | return base + index; | ||
| 54 | index += current_size; | ||
| 55 | } | ||
| 56 | |||
| 57 | return NULL; | ||
| 58 | } | ||
| 59 | |||
| 60 | /* Try to find panel data */ | ||
| 61 | static void | ||
| 62 | parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb) | ||
| 63 | { | ||
| 64 | struct bdb_lvds_options *lvds_options; | ||
| 65 | struct bdb_lvds_lfp_data *lvds_lfp_data; | ||
| 66 | struct bdb_lvds_lfp_data_entry *entry; | ||
| 67 | struct lvds_dvo_timing *dvo_timing; | ||
| 68 | struct drm_display_mode *panel_fixed_mode; | ||
| 69 | |||
| 70 | /* Defaults if we can't find VBT info */ | ||
| 71 | dev_priv->lvds_dither = 0; | ||
| 72 | dev_priv->lvds_vbt = 0; | ||
| 73 | |||
| 74 | lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); | ||
| 75 | if (!lvds_options) | ||
| 76 | return; | ||
| 77 | |||
| 78 | dev_priv->lvds_dither = lvds_options->pixel_dither; | ||
| 79 | if (lvds_options->panel_type == 0xff) | ||
| 80 | return; | ||
| 81 | |||
| 82 | lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); | ||
| 83 | if (!lvds_lfp_data) | ||
| 84 | return; | ||
| 85 | |||
| 86 | dev_priv->lvds_vbt = 1; | ||
| 87 | |||
| 88 | entry = &lvds_lfp_data->data[lvds_options->panel_type]; | ||
| 89 | dvo_timing = &entry->dvo_timing; | ||
| 90 | |||
| 91 | panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), | ||
| 92 | DRM_MEM_DRIVER); | ||
| 93 | |||
| 94 | panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | | ||
| 95 | dvo_timing->hactive_lo; | ||
| 96 | panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + | ||
| 97 | ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); | ||
| 98 | panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + | ||
| 99 | dvo_timing->hsync_pulse_width; | ||
| 100 | panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + | ||
| 101 | ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); | ||
| 102 | |||
| 103 | panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | | ||
| 104 | dvo_timing->vactive_lo; | ||
| 105 | panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + | ||
| 106 | dvo_timing->vsync_off; | ||
| 107 | panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + | ||
| 108 | dvo_timing->vsync_pulse_width; | ||
| 109 | panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + | ||
| 110 | ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); | ||
| 111 | panel_fixed_mode->clock = dvo_timing->clock * 10; | ||
| 112 | panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; | ||
| 113 | |||
| 114 | drm_mode_set_name(panel_fixed_mode); | ||
| 115 | |||
| 116 | dev_priv->vbt_mode = panel_fixed_mode; | ||
| 117 | |||
| 118 | DRM_DEBUG("Found panel mode in BIOS VBT tables:\n"); | ||
| 119 | drm_mode_debug_printmodeline(panel_fixed_mode); | ||
| 120 | |||
| 121 | return; | ||
| 122 | } | ||
| 123 | |||
| 124 | static void | ||
| 125 | parse_general_features(struct drm_i915_private *dev_priv, | ||
| 126 | struct bdb_header *bdb) | ||
| 127 | { | ||
| 128 | struct bdb_general_features *general; | ||
| 129 | |||
| 130 | /* Set sensible defaults in case we can't find the general block */ | ||
| 131 | dev_priv->int_tv_support = 1; | ||
| 132 | dev_priv->int_crt_support = 1; | ||
| 133 | |||
| 134 | general = find_section(bdb, BDB_GENERAL_FEATURES); | ||
| 135 | if (general) { | ||
| 136 | dev_priv->int_tv_support = general->int_tv_support; | ||
| 137 | dev_priv->int_crt_support = general->int_crt_support; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | /** | ||
| 142 | * intel_init_bios - initialize VBIOS settings & find VBT | ||
| 143 | * @dev: DRM device | ||
| 144 | * | ||
| 145 | * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers | ||
| 146 | * to appropriate values. | ||
| 147 | * | ||
| 148 | * VBT existence is a sanity check that is relied on by other i830_bios.c code. | ||
| 149 | * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may | ||
| 150 | * feed an updated VBT back through that, compared to what we'll fetch using | ||
| 151 | * this method of groping around in the BIOS data. | ||
| 152 | * | ||
| 153 | * Returns 0 on success, nonzero on failure. | ||
| 154 | */ | ||
| 155 | bool | ||
| 156 | intel_init_bios(struct drm_device *dev) | ||
| 157 | { | ||
| 158 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 159 | struct pci_dev *pdev = dev->pdev; | ||
| 160 | struct vbt_header *vbt = NULL; | ||
| 161 | struct bdb_header *bdb; | ||
| 162 | u8 __iomem *bios; | ||
| 163 | size_t size; | ||
| 164 | int i; | ||
| 165 | |||
| 166 | bios = pci_map_rom(pdev, &size); | ||
| 167 | if (!bios) | ||
| 168 | return -1; | ||
| 169 | |||
| 170 | /* Scour memory looking for the VBT signature */ | ||
| 171 | for (i = 0; i + 4 < size; i++) { | ||
| 172 | if (!memcmp(bios + i, "$VBT", 4)) { | ||
| 173 | vbt = (struct vbt_header *)(bios + i); | ||
| 174 | break; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | if (!vbt) { | ||
| 179 | DRM_ERROR("VBT signature missing\n"); | ||
| 180 | pci_unmap_rom(pdev, bios); | ||
| 181 | return -1; | ||
| 182 | } | ||
| 183 | |||
| 184 | bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); | ||
| 185 | |||
| 186 | /* Grab useful general definitions */ | ||
| 187 | parse_general_features(dev_priv, bdb); | ||
| 188 | parse_panel_data(dev_priv, bdb); | ||
| 189 | |||
| 190 | pci_unmap_rom(pdev, bios); | ||
| 191 | |||
| 192 | return 0; | ||
| 193 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h new file mode 100644 index 000000000000..5ea715ace3a0 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_bios.h | |||
| @@ -0,0 +1,405 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2006 Intel Corporation | ||
| 3 | * | ||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 5 | * copy of this software and associated documentation files (the "Software"), | ||
| 6 | * to deal in the Software without restriction, including without limitation | ||
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 9 | * Software is furnished to do so, subject to the following conditions: | ||
| 10 | * | ||
| 11 | * The above copyright notice and this permission notice (including the next | ||
| 12 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 13 | * Software. | ||
| 14 | * | ||
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 21 | * SOFTWARE. | ||
| 22 | * | ||
| 23 | * Authors: | ||
| 24 | * Eric Anholt <eric@anholt.net> | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | |||
| 28 | #ifndef _I830_BIOS_H_ | ||
| 29 | #define _I830_BIOS_H_ | ||
| 30 | |||
| 31 | #include "drmP.h" | ||
| 32 | |||
| 33 | struct vbt_header { | ||
| 34 | u8 signature[20]; /**< Always starts with 'VBT$' */ | ||
| 35 | u16 version; /**< decimal */ | ||
| 36 | u16 header_size; /**< in bytes */ | ||
| 37 | u16 vbt_size; /**< in bytes */ | ||
| 38 | u8 vbt_checksum; | ||
| 39 | u8 reserved0; | ||
| 40 | u32 bdb_offset; /**< from beginning of VBT */ | ||
| 41 | u32 aim_offset[4]; /**< from beginning of VBT */ | ||
| 42 | } __attribute__((packed)); | ||
| 43 | |||
| 44 | struct bdb_header { | ||
| 45 | u8 signature[16]; /**< Always 'BIOS_DATA_BLOCK' */ | ||
| 46 | u16 version; /**< decimal */ | ||
| 47 | u16 header_size; /**< in bytes */ | ||
| 48 | u16 bdb_size; /**< in bytes */ | ||
| 49 | }; | ||
| 50 | |||
| 51 | /* strictly speaking, this is a "skip" block, but it has interesting info */ | ||
| 52 | struct vbios_data { | ||
| 53 | u8 type; /* 0 == desktop, 1 == mobile */ | ||
| 54 | u8 relstage; | ||
| 55 | u8 chipset; | ||
| 56 | u8 lvds_present:1; | ||
| 57 | u8 tv_present:1; | ||
| 58 | u8 rsvd2:6; /* finish byte */ | ||
| 59 | u8 rsvd3[4]; | ||
| 60 | u8 signon[155]; | ||
| 61 | u8 copyright[61]; | ||
| 62 | u16 code_segment; | ||
| 63 | u8 dos_boot_mode; | ||
| 64 | u8 bandwidth_percent; | ||
| 65 | u8 rsvd4; /* popup memory size */ | ||
| 66 | u8 resize_pci_bios; | ||
| 67 | u8 rsvd5; /* is crt already on ddc2 */ | ||
| 68 | } __attribute__((packed)); | ||
| 69 | |||
| 70 | /* | ||
| 71 | * There are several types of BIOS data blocks (BDBs), each block has | ||
| 72 | * an ID and size in the first 3 bytes (ID in first, size in next 2). | ||
| 73 | * Known types are listed below. | ||
| 74 | */ | ||
| 75 | #define BDB_GENERAL_FEATURES 1 | ||
| 76 | #define BDB_GENERAL_DEFINITIONS 2 | ||
| 77 | #define BDB_OLD_TOGGLE_LIST 3 | ||
| 78 | #define BDB_MODE_SUPPORT_LIST 4 | ||
| 79 | #define BDB_GENERIC_MODE_TABLE 5 | ||
| 80 | #define BDB_EXT_MMIO_REGS 6 | ||
| 81 | #define BDB_SWF_IO 7 | ||
| 82 | #define BDB_SWF_MMIO 8 | ||
| 83 | #define BDB_DOT_CLOCK_TABLE 9 | ||
| 84 | #define BDB_MODE_REMOVAL_TABLE 10 | ||
| 85 | #define BDB_CHILD_DEVICE_TABLE 11 | ||
| 86 | #define BDB_DRIVER_FEATURES 12 | ||
| 87 | #define BDB_DRIVER_PERSISTENCE 13 | ||
| 88 | #define BDB_EXT_TABLE_PTRS 14 | ||
| 89 | #define BDB_DOT_CLOCK_OVERRIDE 15 | ||
| 90 | #define BDB_DISPLAY_SELECT 16 | ||
| 91 | /* 17 rsvd */ | ||
| 92 | #define BDB_DRIVER_ROTATION 18 | ||
| 93 | #define BDB_DISPLAY_REMOVE 19 | ||
| 94 | #define BDB_OEM_CUSTOM 20 | ||
| 95 | #define BDB_EFP_LIST 21 /* workarounds for VGA hsync/vsync */ | ||
| 96 | #define BDB_SDVO_LVDS_OPTIONS 22 | ||
| 97 | #define BDB_SDVO_PANEL_DTDS 23 | ||
| 98 | #define BDB_SDVO_LVDS_PNP_IDS 24 | ||
| 99 | #define BDB_SDVO_LVDS_POWER_SEQ 25 | ||
| 100 | #define BDB_TV_OPTIONS 26 | ||
| 101 | #define BDB_LVDS_OPTIONS 40 | ||
| 102 | #define BDB_LVDS_LFP_DATA_PTRS 41 | ||
| 103 | #define BDB_LVDS_LFP_DATA 42 | ||
| 104 | #define BDB_LVDS_BACKLIGHT 43 | ||
| 105 | #define BDB_LVDS_POWER 44 | ||
| 106 | #define BDB_SKIP 254 /* VBIOS private block, ignore */ | ||
| 107 | |||
| 108 | struct bdb_general_features { | ||
| 109 | /* bits 1 */ | ||
| 110 | u8 panel_fitting:2; | ||
| 111 | u8 flexaim:1; | ||
| 112 | u8 msg_enable:1; | ||
| 113 | u8 clear_screen:3; | ||
| 114 | u8 color_flip:1; | ||
| 115 | |||
| 116 | /* bits 2 */ | ||
| 117 | u8 download_ext_vbt:1; | ||
| 118 | u8 enable_ssc:1; | ||
| 119 | u8 ssc_freq:1; | ||
| 120 | u8 enable_lfp_on_override:1; | ||
| 121 | u8 disable_ssc_ddt:1; | ||
| 122 | u8 rsvd8:3; /* finish byte */ | ||
| 123 | |||
| 124 | /* bits 3 */ | ||
| 125 | u8 disable_smooth_vision:1; | ||
| 126 | u8 single_dvi:1; | ||
| 127 | u8 rsvd9:6; /* finish byte */ | ||
| 128 | |||
| 129 | /* bits 4 */ | ||
| 130 | u8 legacy_monitor_detect; | ||
| 131 | |||
| 132 | /* bits 5 */ | ||
| 133 | u8 int_crt_support:1; | ||
| 134 | u8 int_tv_support:1; | ||
| 135 | u8 rsvd11:6; /* finish byte */ | ||
| 136 | } __attribute__((packed)); | ||
| 137 | |||
| 138 | struct bdb_general_definitions { | ||
| 139 | /* DDC GPIO */ | ||
| 140 | u8 crt_ddc_gmbus_pin; | ||
| 141 | |||
| 142 | /* DPMS bits */ | ||
| 143 | u8 dpms_acpi:1; | ||
| 144 | u8 skip_boot_crt_detect:1; | ||
| 145 | u8 dpms_aim:1; | ||
| 146 | u8 rsvd1:5; /* finish byte */ | ||
| 147 | |||
| 148 | /* boot device bits */ | ||
| 149 | u8 boot_display[2]; | ||
| 150 | u8 child_dev_size; | ||
| 151 | |||
| 152 | /* device info */ | ||
| 153 | u8 tv_or_lvds_info[33]; | ||
| 154 | u8 dev1[33]; | ||
| 155 | u8 dev2[33]; | ||
| 156 | u8 dev3[33]; | ||
| 157 | u8 dev4[33]; | ||
| 158 | /* may be another device block here on some platforms */ | ||
| 159 | }; | ||
| 160 | |||
| 161 | struct bdb_lvds_options { | ||
| 162 | u8 panel_type; | ||
| 163 | u8 rsvd1; | ||
| 164 | /* LVDS capabilities, stored in a dword */ | ||
| 165 | u8 rsvd2:1; | ||
| 166 | u8 lvds_edid:1; | ||
| 167 | u8 pixel_dither:1; | ||
| 168 | u8 pfit_ratio_auto:1; | ||
| 169 | u8 pfit_gfx_mode_enhanced:1; | ||
| 170 | u8 pfit_text_mode_enhanced:1; | ||
| 171 | u8 pfit_mode:2; | ||
| 172 | u8 rsvd4; | ||
| 173 | } __attribute__((packed)); | ||
| 174 | |||
| 175 | /* LFP pointer table contains entries to the struct below */ | ||
| 176 | struct bdb_lvds_lfp_data_ptr { | ||
| 177 | u16 fp_timing_offset; /* offsets are from start of bdb */ | ||
| 178 | u8 fp_table_size; | ||
| 179 | u16 dvo_timing_offset; | ||
| 180 | u8 dvo_table_size; | ||
| 181 | u16 panel_pnp_id_offset; | ||
| 182 | u8 pnp_table_size; | ||
| 183 | } __attribute__((packed)); | ||
| 184 | |||
| 185 | struct bdb_lvds_lfp_data_ptrs { | ||
| 186 | u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ | ||
| 187 | struct bdb_lvds_lfp_data_ptr ptr[16]; | ||
| 188 | } __attribute__((packed)); | ||
| 189 | |||
| 190 | /* LFP data has 3 blocks per entry */ | ||
| 191 | struct lvds_fp_timing { | ||
| 192 | u16 x_res; | ||
| 193 | u16 y_res; | ||
| 194 | u32 lvds_reg; | ||
| 195 | u32 lvds_reg_val; | ||
| 196 | u32 pp_on_reg; | ||
| 197 | u32 pp_on_reg_val; | ||
| 198 | u32 pp_off_reg; | ||
| 199 | u32 pp_off_reg_val; | ||
| 200 | u32 pp_cycle_reg; | ||
| 201 | u32 pp_cycle_reg_val; | ||
| 202 | u32 pfit_reg; | ||
| 203 | u32 pfit_reg_val; | ||
| 204 | u16 terminator; | ||
| 205 | } __attribute__((packed)); | ||
| 206 | |||
| 207 | struct lvds_dvo_timing { | ||
| 208 | u16 clock; /**< In 10khz */ | ||
| 209 | u8 hactive_lo; | ||
| 210 | u8 hblank_lo; | ||
| 211 | u8 hblank_hi:4; | ||
| 212 | u8 hactive_hi:4; | ||
| 213 | u8 vactive_lo; | ||
| 214 | u8 vblank_lo; | ||
| 215 | u8 vblank_hi:4; | ||
| 216 | u8 vactive_hi:4; | ||
| 217 | u8 hsync_off_lo; | ||
| 218 | u8 hsync_pulse_width; | ||
| 219 | u8 vsync_pulse_width:4; | ||
| 220 | u8 vsync_off:4; | ||
| 221 | u8 rsvd0:6; | ||
| 222 | u8 hsync_off_hi:2; | ||
| 223 | u8 h_image; | ||
| 224 | u8 v_image; | ||
| 225 | u8 max_hv; | ||
| 226 | u8 h_border; | ||
| 227 | u8 v_border; | ||
| 228 | u8 rsvd1:3; | ||
| 229 | u8 digital:2; | ||
| 230 | u8 vsync_positive:1; | ||
| 231 | u8 hsync_positive:1; | ||
| 232 | u8 rsvd2:1; | ||
| 233 | } __attribute__((packed)); | ||
| 234 | |||
| 235 | struct lvds_pnp_id { | ||
| 236 | u16 mfg_name; | ||
| 237 | u16 product_code; | ||
| 238 | u32 serial; | ||
| 239 | u8 mfg_week; | ||
| 240 | u8 mfg_year; | ||
| 241 | } __attribute__((packed)); | ||
| 242 | |||
| 243 | struct bdb_lvds_lfp_data_entry { | ||
| 244 | struct lvds_fp_timing fp_timing; | ||
| 245 | struct lvds_dvo_timing dvo_timing; | ||
| 246 | struct lvds_pnp_id pnp_id; | ||
| 247 | } __attribute__((packed)); | ||
| 248 | |||
| 249 | struct bdb_lvds_lfp_data { | ||
| 250 | struct bdb_lvds_lfp_data_entry data[16]; | ||
| 251 | } __attribute__((packed)); | ||
| 252 | |||
| 253 | struct aimdb_header { | ||
| 254 | char signature[16]; | ||
| 255 | char oem_device[20]; | ||
| 256 | u16 aimdb_version; | ||
| 257 | u16 aimdb_header_size; | ||
| 258 | u16 aimdb_size; | ||
| 259 | } __attribute__((packed)); | ||
| 260 | |||
| 261 | struct aimdb_block { | ||
| 262 | u8 aimdb_id; | ||
| 263 | u16 aimdb_size; | ||
| 264 | } __attribute__((packed)); | ||
| 265 | |||
| 266 | struct vch_panel_data { | ||
| 267 | u16 fp_timing_offset; | ||
| 268 | u8 fp_timing_size; | ||
| 269 | u16 dvo_timing_offset; | ||
| 270 | u8 dvo_timing_size; | ||
| 271 | u16 text_fitting_offset; | ||
| 272 | u8 text_fitting_size; | ||
| 273 | u16 graphics_fitting_offset; | ||
| 274 | u8 graphics_fitting_size; | ||
| 275 | } __attribute__((packed)); | ||
| 276 | |||
| 277 | struct vch_bdb_22 { | ||
| 278 | struct aimdb_block aimdb_block; | ||
| 279 | struct vch_panel_data panels[16]; | ||
| 280 | } __attribute__((packed)); | ||
| 281 | |||
| 282 | bool intel_init_bios(struct drm_device *dev); | ||
| 283 | |||
| 284 | /* | ||
| 285 | * Driver<->VBIOS interaction occurs through scratch bits in | ||
| 286 | * GR18 & SWF*. | ||
| 287 | */ | ||
| 288 | |||
| 289 | /* GR18 bits are set on display switch and hotkey events */ | ||
| 290 | #define GR18_DRIVER_SWITCH_EN (1<<7) /* 0: VBIOS control, 1: driver control */ | ||
| 291 | #define GR18_HOTKEY_MASK 0x78 /* See also SWF4 15:0 */ | ||
| 292 | #define GR18_HK_NONE (0x0<<3) | ||
| 293 | #define GR18_HK_LFP_STRETCH (0x1<<3) | ||
| 294 | #define GR18_HK_TOGGLE_DISP (0x2<<3) | ||
| 295 | #define GR18_HK_DISP_SWITCH (0x4<<3) /* see SWF14 15:0 for what to enable */ | ||
| 296 | #define GR18_HK_POPUP_DISABLED (0x6<<3) | ||
| 297 | #define GR18_HK_POPUP_ENABLED (0x7<<3) | ||
| 298 | #define GR18_HK_PFIT (0x8<<3) | ||
| 299 | #define GR18_HK_APM_CHANGE (0xa<<3) | ||
| 300 | #define GR18_HK_MULTIPLE (0xc<<3) | ||
| 301 | #define GR18_USER_INT_EN (1<<2) | ||
| 302 | #define GR18_A0000_FLUSH_EN (1<<1) | ||
| 303 | #define GR18_SMM_EN (1<<0) | ||
| 304 | |||
| 305 | /* Set by driver, cleared by VBIOS */ | ||
| 306 | #define SWF00_YRES_SHIFT 16 | ||
| 307 | #define SWF00_XRES_SHIFT 0 | ||
| 308 | #define SWF00_RES_MASK 0xffff | ||
| 309 | |||
| 310 | /* Set by VBIOS at boot time and driver at runtime */ | ||
| 311 | #define SWF01_TV2_FORMAT_SHIFT 8 | ||
| 312 | #define SWF01_TV1_FORMAT_SHIFT 0 | ||
| 313 | #define SWF01_TV_FORMAT_MASK 0xffff | ||
| 314 | |||
| 315 | #define SWF10_VBIOS_BLC_I2C_EN (1<<29) | ||
| 316 | #define SWF10_GTT_OVERRIDE_EN (1<<28) | ||
| 317 | #define SWF10_LFP_DPMS_OVR (1<<27) /* override DPMS on display switch */ | ||
| 318 | #define SWF10_ACTIVE_TOGGLE_LIST_MASK (7<<24) | ||
| 319 | #define SWF10_OLD_TOGGLE 0x0 | ||
| 320 | #define SWF10_TOGGLE_LIST_1 0x1 | ||
| 321 | #define SWF10_TOGGLE_LIST_2 0x2 | ||
| 322 | #define SWF10_TOGGLE_LIST_3 0x3 | ||
| 323 | #define SWF10_TOGGLE_LIST_4 0x4 | ||
| 324 | #define SWF10_PANNING_EN (1<<23) | ||
| 325 | #define SWF10_DRIVER_LOADED (1<<22) | ||
| 326 | #define SWF10_EXTENDED_DESKTOP (1<<21) | ||
| 327 | #define SWF10_EXCLUSIVE_MODE (1<<20) | ||
| 328 | #define SWF10_OVERLAY_EN (1<<19) | ||
| 329 | #define SWF10_PLANEB_HOLDOFF (1<<18) | ||
| 330 | #define SWF10_PLANEA_HOLDOFF (1<<17) | ||
| 331 | #define SWF10_VGA_HOLDOFF (1<<16) | ||
| 332 | #define SWF10_ACTIVE_DISP_MASK 0xffff | ||
| 333 | #define SWF10_PIPEB_LFP2 (1<<15) | ||
| 334 | #define SWF10_PIPEB_EFP2 (1<<14) | ||
| 335 | #define SWF10_PIPEB_TV2 (1<<13) | ||
| 336 | #define SWF10_PIPEB_CRT2 (1<<12) | ||
| 337 | #define SWF10_PIPEB_LFP (1<<11) | ||
| 338 | #define SWF10_PIPEB_EFP (1<<10) | ||
| 339 | #define SWF10_PIPEB_TV (1<<9) | ||
| 340 | #define SWF10_PIPEB_CRT (1<<8) | ||
| 341 | #define SWF10_PIPEA_LFP2 (1<<7) | ||
| 342 | #define SWF10_PIPEA_EFP2 (1<<6) | ||
| 343 | #define SWF10_PIPEA_TV2 (1<<5) | ||
| 344 | #define SWF10_PIPEA_CRT2 (1<<4) | ||
| 345 | #define SWF10_PIPEA_LFP (1<<3) | ||
| 346 | #define SWF10_PIPEA_EFP (1<<2) | ||
| 347 | #define SWF10_PIPEA_TV (1<<1) | ||
| 348 | #define SWF10_PIPEA_CRT (1<<0) | ||
| 349 | |||
| 350 | #define SWF11_MEMORY_SIZE_SHIFT 16 | ||
| 351 | #define SWF11_SV_TEST_EN (1<<15) | ||
| 352 | #define SWF11_IS_AGP (1<<14) | ||
| 353 | #define SWF11_DISPLAY_HOLDOFF (1<<13) | ||
| 354 | #define SWF11_DPMS_REDUCED (1<<12) | ||
| 355 | #define SWF11_IS_VBE_MODE (1<<11) | ||
| 356 | #define SWF11_PIPEB_ACCESS (1<<10) /* 0 here means pipe a */ | ||
| 357 | #define SWF11_DPMS_MASK 0x07 | ||
| 358 | #define SWF11_DPMS_OFF (1<<2) | ||
| 359 | #define SWF11_DPMS_SUSPEND (1<<1) | ||
| 360 | #define SWF11_DPMS_STANDBY (1<<0) | ||
| 361 | #define SWF11_DPMS_ON 0 | ||
| 362 | |||
| 363 | #define SWF14_GFX_PFIT_EN (1<<31) | ||
| 364 | #define SWF14_TEXT_PFIT_EN (1<<30) | ||
| 365 | #define SWF14_LID_STATUS_CLOSED (1<<29) /* 0 here means open */ | ||
| 366 | #define SWF14_POPUP_EN (1<<28) | ||
| 367 | #define SWF14_DISPLAY_HOLDOFF (1<<27) | ||
| 368 | #define SWF14_DISP_DETECT_EN (1<<26) | ||
| 369 | #define SWF14_DOCKING_STATUS_DOCKED (1<<25) /* 0 here means undocked */ | ||
| 370 | #define SWF14_DRIVER_STATUS (1<<24) | ||
| 371 | #define SWF14_OS_TYPE_WIN9X (1<<23) | ||
| 372 | #define SWF14_OS_TYPE_WINNT (1<<22) | ||
| 373 | /* 21:19 rsvd */ | ||
| 374 | #define SWF14_PM_TYPE_MASK 0x00070000 | ||
| 375 | #define SWF14_PM_ACPI_VIDEO (0x4 << 16) | ||
| 376 | #define SWF14_PM_ACPI (0x3 << 16) | ||
| 377 | #define SWF14_PM_APM_12 (0x2 << 16) | ||
| 378 | #define SWF14_PM_APM_11 (0x1 << 16) | ||
| 379 | #define SWF14_HK_REQUEST_MASK 0x0000ffff /* see GR18 6:3 for event type */ | ||
| 380 | /* if GR18 indicates a display switch */ | ||
| 381 | #define SWF14_DS_PIPEB_LFP2_EN (1<<15) | ||
| 382 | #define SWF14_DS_PIPEB_EFP2_EN (1<<14) | ||
| 383 | #define SWF14_DS_PIPEB_TV2_EN (1<<13) | ||
| 384 | #define SWF14_DS_PIPEB_CRT2_EN (1<<12) | ||
| 385 | #define SWF14_DS_PIPEB_LFP_EN (1<<11) | ||
| 386 | #define SWF14_DS_PIPEB_EFP_EN (1<<10) | ||
| 387 | #define SWF14_DS_PIPEB_TV_EN (1<<9) | ||
| 388 | #define SWF14_DS_PIPEB_CRT_EN (1<<8) | ||
| 389 | #define SWF14_DS_PIPEA_LFP2_EN (1<<7) | ||
| 390 | #define SWF14_DS_PIPEA_EFP2_EN (1<<6) | ||
| 391 | #define SWF14_DS_PIPEA_TV2_EN (1<<5) | ||
| 392 | #define SWF14_DS_PIPEA_CRT2_EN (1<<4) | ||
| 393 | #define SWF14_DS_PIPEA_LFP_EN (1<<3) | ||
| 394 | #define SWF14_DS_PIPEA_EFP_EN (1<<2) | ||
| 395 | #define SWF14_DS_PIPEA_TV_EN (1<<1) | ||
| 396 | #define SWF14_DS_PIPEA_CRT_EN (1<<0) | ||
| 397 | /* if GR18 indicates a panel fitting request */ | ||
| 398 | #define SWF14_PFIT_EN (1<<0) /* 0 means disable */ | ||
| 399 | /* if GR18 indicates an APM change request */ | ||
| 400 | #define SWF14_APM_HIBERNATE 0x4 | ||
| 401 | #define SWF14_APM_SUSPEND 0x3 | ||
| 402 | #define SWF14_APM_STANDBY 0x1 | ||
| 403 | #define SWF14_APM_RESTORE 0x0 | ||
| 404 | |||
| 405 | #endif /* _I830_BIOS_H_ */ | ||
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c new file mode 100644 index 000000000000..dcaed3466e83 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_crt.c | |||
| @@ -0,0 +1,284 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2006-2007 Intel Corporation | ||
| 3 | * | ||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 5 | * copy of this software and associated documentation files (the "Software"), | ||
| 6 | * to deal in the Software without restriction, including without limitation | ||
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 9 | * Software is furnished to do so, subject to the following conditions: | ||
| 10 | * | ||
| 11 | * The above copyright notice and this permission notice (including the next | ||
| 12 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 13 | * Software. | ||
| 14 | * | ||
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 21 | * DEALINGS IN THE SOFTWARE. | ||
| 22 | * | ||
| 23 | * Authors: | ||
| 24 | * Eric Anholt <eric@anholt.net> | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <linux/i2c.h> | ||
| 28 | #include "drmP.h" | ||
| 29 | #include "drm.h" | ||
| 30 | #include "drm_crtc.h" | ||
| 31 | #include "drm_crtc_helper.h" | ||
| 32 | #include "intel_drv.h" | ||
| 33 | #include "i915_drm.h" | ||
| 34 | #include "i915_drv.h" | ||
| 35 | |||
| 36 | static void intel_crt_dpms(struct drm_encoder *encoder, int mode) | ||
| 37 | { | ||
| 38 | struct drm_device *dev = encoder->dev; | ||
| 39 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 40 | u32 temp; | ||
| 41 | |||
| 42 | temp = I915_READ(ADPA); | ||
| 43 | temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); | ||
| 44 | temp &= ~ADPA_DAC_ENABLE; | ||
| 45 | |||
| 46 | switch(mode) { | ||
| 47 | case DRM_MODE_DPMS_ON: | ||
| 48 | temp |= ADPA_DAC_ENABLE; | ||
| 49 | break; | ||
| 50 | case DRM_MODE_DPMS_STANDBY: | ||
| 51 | temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; | ||
| 52 | break; | ||
| 53 | case DRM_MODE_DPMS_SUSPEND: | ||
| 54 | temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; | ||
| 55 | break; | ||
| 56 | case DRM_MODE_DPMS_OFF: | ||
| 57 | temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; | ||
| 58 | break; | ||
| 59 | } | ||
| 60 | |||
| 61 | I915_WRITE(ADPA, temp); | ||
| 62 | } | ||
| 63 | |||
| 64 | static int intel_crt_mode_valid(struct drm_connector *connector, | ||
| 65 | struct drm_display_mode *mode) | ||
| 66 | { | ||
| 67 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
| 68 | return MODE_NO_DBLESCAN; | ||
| 69 | |||
| 70 | if (mode->clock > 400000 || mode->clock < 25000) | ||
| 71 | return MODE_CLOCK_RANGE; | ||
| 72 | |||
| 73 | return MODE_OK; | ||
| 74 | } | ||
| 75 | |||
| 76 | static bool intel_crt_mode_fixup(struct drm_encoder *encoder, | ||
| 77 | struct drm_display_mode *mode, | ||
| 78 | struct drm_display_mode *adjusted_mode) | ||
| 79 | { | ||
| 80 | return true; | ||
| 81 | } | ||
| 82 | |||
| 83 | static void intel_crt_mode_set(struct drm_encoder *encoder, | ||
| 84 | struct drm_display_mode *mode, | ||
| 85 | struct drm_display_mode *adjusted_mode) | ||
| 86 | { | ||
| 87 | |||
| 88 | struct drm_device *dev = encoder->dev; | ||
| 89 | struct drm_crtc *crtc = encoder->crtc; | ||
| 90 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 91 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 92 | int dpll_md_reg; | ||
| 93 | u32 adpa, dpll_md; | ||
| 94 | |||
| 95 | if (intel_crtc->pipe == 0) | ||
| 96 | dpll_md_reg = DPLL_A_MD; | ||
| 97 | else | ||
| 98 | dpll_md_reg = DPLL_B_MD; | ||
| 99 | |||
| 100 | /* | ||
| 101 | * Disable separate mode multiplier used when cloning SDVO to CRT | ||
| 102 | * XXX this needs to be adjusted when we really are cloning | ||
| 103 | */ | ||
| 104 | if (IS_I965G(dev)) { | ||
| 105 | dpll_md = I915_READ(dpll_md_reg); | ||
| 106 | I915_WRITE(dpll_md_reg, | ||
| 107 | dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); | ||
| 108 | } | ||
| 109 | |||
| 110 | adpa = 0; | ||
| 111 | if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
| 112 | adpa |= ADPA_HSYNC_ACTIVE_HIGH; | ||
| 113 | if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
| 114 | adpa |= ADPA_VSYNC_ACTIVE_HIGH; | ||
| 115 | |||
| 116 | if (intel_crtc->pipe == 0) | ||
| 117 | adpa |= ADPA_PIPE_A_SELECT; | ||
| 118 | else | ||
| 119 | adpa |= ADPA_PIPE_B_SELECT; | ||
| 120 | |||
| 121 | I915_WRITE(ADPA, adpa); | ||
| 122 | } | ||
| 123 | |||
| 124 | /** | ||
| 125 | * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence. | ||
| 126 | * | ||
| 127 | * Not for i915G/i915GM | ||
| 128 | * | ||
| 129 | * \return true if CRT is connected. | ||
| 130 | * \return false if CRT is disconnected. | ||
| 131 | */ | ||
| 132 | static bool intel_crt_detect_hotplug(struct drm_connector *connector) | ||
| 133 | { | ||
| 134 | struct drm_device *dev = connector->dev; | ||
| 135 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 136 | u32 temp; | ||
| 137 | |||
| 138 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); | ||
| 139 | |||
| 140 | temp = I915_READ(PORT_HOTPLUG_EN); | ||
| 141 | |||
| 142 | I915_WRITE(PORT_HOTPLUG_EN, | ||
| 143 | temp | CRT_HOTPLUG_FORCE_DETECT | (1 << 5)); | ||
| 144 | |||
| 145 | do { | ||
| 146 | if (!(I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT)) | ||
| 147 | break; | ||
| 148 | msleep(1); | ||
| 149 | } while (time_after(timeout, jiffies)); | ||
| 150 | |||
| 151 | if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) == | ||
| 152 | CRT_HOTPLUG_MONITOR_COLOR) | ||
| 153 | return true; | ||
| 154 | |||
| 155 | return false; | ||
| 156 | } | ||
| 157 | |||
| 158 | static bool intel_crt_detect_ddc(struct drm_connector *connector) | ||
| 159 | { | ||
| 160 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 161 | |||
| 162 | /* CRT should always be at 0, but check anyway */ | ||
| 163 | if (intel_output->type != INTEL_OUTPUT_ANALOG) | ||
| 164 | return false; | ||
| 165 | |||
| 166 | return intel_ddc_probe(intel_output); | ||
| 167 | } | ||
| 168 | |||
| 169 | static enum drm_connector_status intel_crt_detect(struct drm_connector *connector) | ||
| 170 | { | ||
| 171 | struct drm_device *dev = connector->dev; | ||
| 172 | |||
| 173 | if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { | ||
| 174 | if (intel_crt_detect_hotplug(connector)) | ||
| 175 | return connector_status_connected; | ||
| 176 | else | ||
| 177 | return connector_status_disconnected; | ||
| 178 | } | ||
| 179 | |||
| 180 | if (intel_crt_detect_ddc(connector)) | ||
| 181 | return connector_status_connected; | ||
| 182 | |||
| 183 | /* TODO use load detect */ | ||
| 184 | return connector_status_unknown; | ||
| 185 | } | ||
| 186 | |||
| 187 | static void intel_crt_destroy(struct drm_connector *connector) | ||
| 188 | { | ||
| 189 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 190 | |||
| 191 | intel_i2c_destroy(intel_output->ddc_bus); | ||
| 192 | drm_sysfs_connector_remove(connector); | ||
| 193 | drm_connector_cleanup(connector); | ||
| 194 | kfree(connector); | ||
| 195 | } | ||
| 196 | |||
| 197 | static int intel_crt_get_modes(struct drm_connector *connector) | ||
| 198 | { | ||
| 199 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 200 | return intel_ddc_get_modes(intel_output); | ||
| 201 | } | ||
| 202 | |||
| 203 | static int intel_crt_set_property(struct drm_connector *connector, | ||
| 204 | struct drm_property *property, | ||
| 205 | uint64_t value) | ||
| 206 | { | ||
| 207 | struct drm_device *dev = connector->dev; | ||
| 208 | |||
| 209 | if (property == dev->mode_config.dpms_property && connector->encoder) | ||
| 210 | intel_crt_dpms(connector->encoder, (uint32_t)(value & 0xf)); | ||
| 211 | |||
| 212 | return 0; | ||
| 213 | } | ||
| 214 | |||
| 215 | /* | ||
| 216 | * Routines for controlling stuff on the analog port | ||
| 217 | */ | ||
| 218 | |||
| 219 | static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = { | ||
| 220 | .dpms = intel_crt_dpms, | ||
| 221 | .mode_fixup = intel_crt_mode_fixup, | ||
| 222 | .prepare = intel_encoder_prepare, | ||
| 223 | .commit = intel_encoder_commit, | ||
| 224 | .mode_set = intel_crt_mode_set, | ||
| 225 | }; | ||
| 226 | |||
| 227 | static const struct drm_connector_funcs intel_crt_connector_funcs = { | ||
| 228 | .detect = intel_crt_detect, | ||
| 229 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
| 230 | .destroy = intel_crt_destroy, | ||
| 231 | .set_property = intel_crt_set_property, | ||
| 232 | }; | ||
| 233 | |||
| 234 | static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { | ||
| 235 | .mode_valid = intel_crt_mode_valid, | ||
| 236 | .get_modes = intel_crt_get_modes, | ||
| 237 | .best_encoder = intel_best_encoder, | ||
| 238 | }; | ||
| 239 | |||
| 240 | static void intel_crt_enc_destroy(struct drm_encoder *encoder) | ||
| 241 | { | ||
| 242 | drm_encoder_cleanup(encoder); | ||
| 243 | } | ||
| 244 | |||
| 245 | static const struct drm_encoder_funcs intel_crt_enc_funcs = { | ||
| 246 | .destroy = intel_crt_enc_destroy, | ||
| 247 | }; | ||
| 248 | |||
| 249 | void intel_crt_init(struct drm_device *dev) | ||
| 250 | { | ||
| 251 | struct drm_connector *connector; | ||
| 252 | struct intel_output *intel_output; | ||
| 253 | |||
| 254 | intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); | ||
| 255 | if (!intel_output) | ||
| 256 | return; | ||
| 257 | |||
| 258 | connector = &intel_output->base; | ||
| 259 | drm_connector_init(dev, &intel_output->base, | ||
| 260 | &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); | ||
| 261 | |||
| 262 | drm_encoder_init(dev, &intel_output->enc, &intel_crt_enc_funcs, | ||
| 263 | DRM_MODE_ENCODER_DAC); | ||
| 264 | |||
| 265 | drm_mode_connector_attach_encoder(&intel_output->base, | ||
| 266 | &intel_output->enc); | ||
| 267 | |||
| 268 | /* Set up the DDC bus. */ | ||
| 269 | intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); | ||
| 270 | if (!intel_output->ddc_bus) { | ||
| 271 | dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " | ||
| 272 | "failed.\n"); | ||
| 273 | return; | ||
| 274 | } | ||
| 275 | |||
| 276 | intel_output->type = INTEL_OUTPUT_ANALOG; | ||
| 277 | connector->interlace_allowed = 0; | ||
| 278 | connector->doublescan_allowed = 0; | ||
| 279 | |||
| 280 | drm_encoder_helper_add(&intel_output->enc, &intel_crt_helper_funcs); | ||
| 281 | drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); | ||
| 282 | |||
| 283 | drm_sysfs_connector_add(connector); | ||
| 284 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c new file mode 100644 index 000000000000..e5c1c80d1f90 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_display.c | |||
| @@ -0,0 +1,1618 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2006-2007 Intel Corporation | ||
| 3 | * | ||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 5 | * copy of this software and associated documentation files (the "Software"), | ||
| 6 | * to deal in the Software without restriction, including without limitation | ||
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 9 | * Software is furnished to do so, subject to the following conditions: | ||
| 10 | * | ||
| 11 | * The above copyright notice and this permission notice (including the next | ||
| 12 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 13 | * Software. | ||
| 14 | * | ||
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 21 | * DEALINGS IN THE SOFTWARE. | ||
| 22 | * | ||
| 23 | * Authors: | ||
| 24 | * Eric Anholt <eric@anholt.net> | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <linux/i2c.h> | ||
| 28 | #include "drmP.h" | ||
| 29 | #include "intel_drv.h" | ||
| 30 | #include "i915_drm.h" | ||
| 31 | #include "i915_drv.h" | ||
| 32 | |||
| 33 | #include "drm_crtc_helper.h" | ||
| 34 | |||
| 35 | bool intel_pipe_has_type (struct drm_crtc *crtc, int type); | ||
| 36 | |||
| 37 | typedef struct { | ||
| 38 | /* given values */ | ||
| 39 | int n; | ||
| 40 | int m1, m2; | ||
| 41 | int p1, p2; | ||
| 42 | /* derived values */ | ||
| 43 | int dot; | ||
| 44 | int vco; | ||
| 45 | int m; | ||
| 46 | int p; | ||
| 47 | } intel_clock_t; | ||
| 48 | |||
| 49 | typedef struct { | ||
| 50 | int min, max; | ||
| 51 | } intel_range_t; | ||
| 52 | |||
| 53 | typedef struct { | ||
| 54 | int dot_limit; | ||
| 55 | int p2_slow, p2_fast; | ||
| 56 | } intel_p2_t; | ||
| 57 | |||
| 58 | #define INTEL_P2_NUM 2 | ||
| 59 | |||
| 60 | typedef struct { | ||
| 61 | intel_range_t dot, vco, n, m, m1, m2, p, p1; | ||
| 62 | intel_p2_t p2; | ||
| 63 | } intel_limit_t; | ||
| 64 | |||
| 65 | #define I8XX_DOT_MIN 25000 | ||
| 66 | #define I8XX_DOT_MAX 350000 | ||
| 67 | #define I8XX_VCO_MIN 930000 | ||
| 68 | #define I8XX_VCO_MAX 1400000 | ||
| 69 | #define I8XX_N_MIN 3 | ||
| 70 | #define I8XX_N_MAX 16 | ||
| 71 | #define I8XX_M_MIN 96 | ||
| 72 | #define I8XX_M_MAX 140 | ||
| 73 | #define I8XX_M1_MIN 18 | ||
| 74 | #define I8XX_M1_MAX 26 | ||
| 75 | #define I8XX_M2_MIN 6 | ||
| 76 | #define I8XX_M2_MAX 16 | ||
| 77 | #define I8XX_P_MIN 4 | ||
| 78 | #define I8XX_P_MAX 128 | ||
| 79 | #define I8XX_P1_MIN 2 | ||
| 80 | #define I8XX_P1_MAX 33 | ||
| 81 | #define I8XX_P1_LVDS_MIN 1 | ||
| 82 | #define I8XX_P1_LVDS_MAX 6 | ||
| 83 | #define I8XX_P2_SLOW 4 | ||
| 84 | #define I8XX_P2_FAST 2 | ||
| 85 | #define I8XX_P2_LVDS_SLOW 14 | ||
| 86 | #define I8XX_P2_LVDS_FAST 14 /* No fast option */ | ||
| 87 | #define I8XX_P2_SLOW_LIMIT 165000 | ||
| 88 | |||
| 89 | #define I9XX_DOT_MIN 20000 | ||
| 90 | #define I9XX_DOT_MAX 400000 | ||
| 91 | #define I9XX_VCO_MIN 1400000 | ||
| 92 | #define I9XX_VCO_MAX 2800000 | ||
| 93 | #define I9XX_N_MIN 3 | ||
| 94 | #define I9XX_N_MAX 8 | ||
| 95 | #define I9XX_M_MIN 70 | ||
| 96 | #define I9XX_M_MAX 120 | ||
| 97 | #define I9XX_M1_MIN 10 | ||
| 98 | #define I9XX_M1_MAX 20 | ||
| 99 | #define I9XX_M2_MIN 5 | ||
| 100 | #define I9XX_M2_MAX 9 | ||
| 101 | #define I9XX_P_SDVO_DAC_MIN 5 | ||
| 102 | #define I9XX_P_SDVO_DAC_MAX 80 | ||
| 103 | #define I9XX_P_LVDS_MIN 7 | ||
| 104 | #define I9XX_P_LVDS_MAX 98 | ||
| 105 | #define I9XX_P1_MIN 1 | ||
| 106 | #define I9XX_P1_MAX 8 | ||
| 107 | #define I9XX_P2_SDVO_DAC_SLOW 10 | ||
| 108 | #define I9XX_P2_SDVO_DAC_FAST 5 | ||
| 109 | #define I9XX_P2_SDVO_DAC_SLOW_LIMIT 200000 | ||
| 110 | #define I9XX_P2_LVDS_SLOW 14 | ||
| 111 | #define I9XX_P2_LVDS_FAST 7 | ||
| 112 | #define I9XX_P2_LVDS_SLOW_LIMIT 112000 | ||
| 113 | |||
| 114 | #define INTEL_LIMIT_I8XX_DVO_DAC 0 | ||
| 115 | #define INTEL_LIMIT_I8XX_LVDS 1 | ||
| 116 | #define INTEL_LIMIT_I9XX_SDVO_DAC 2 | ||
| 117 | #define INTEL_LIMIT_I9XX_LVDS 3 | ||
| 118 | |||
| 119 | static const intel_limit_t intel_limits[] = { | ||
| 120 | { /* INTEL_LIMIT_I8XX_DVO_DAC */ | ||
| 121 | .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, | ||
| 122 | .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, | ||
| 123 | .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, | ||
| 124 | .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX }, | ||
| 125 | .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX }, | ||
| 126 | .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX }, | ||
| 127 | .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX }, | ||
| 128 | .p1 = { .min = I8XX_P1_MIN, .max = I8XX_P1_MAX }, | ||
| 129 | .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, | ||
| 130 | .p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST }, | ||
| 131 | }, | ||
| 132 | { /* INTEL_LIMIT_I8XX_LVDS */ | ||
| 133 | .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, | ||
| 134 | .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, | ||
| 135 | .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, | ||
| 136 | .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX }, | ||
| 137 | .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX }, | ||
| 138 | .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX }, | ||
| 139 | .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX }, | ||
| 140 | .p1 = { .min = I8XX_P1_LVDS_MIN, .max = I8XX_P1_LVDS_MAX }, | ||
| 141 | .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, | ||
| 142 | .p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST }, | ||
| 143 | }, | ||
| 144 | { /* INTEL_LIMIT_I9XX_SDVO_DAC */ | ||
| 145 | .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, | ||
| 146 | .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, | ||
| 147 | .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, | ||
| 148 | .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX }, | ||
| 149 | .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX }, | ||
| 150 | .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX }, | ||
| 151 | .p = { .min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX }, | ||
| 152 | .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, | ||
| 153 | .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, | ||
| 154 | .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST }, | ||
| 155 | }, | ||
| 156 | { /* INTEL_LIMIT_I9XX_LVDS */ | ||
| 157 | .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, | ||
| 158 | .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, | ||
| 159 | .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, | ||
| 160 | .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX }, | ||
| 161 | .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX }, | ||
| 162 | .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX }, | ||
| 163 | .p = { .min = I9XX_P_LVDS_MIN, .max = I9XX_P_LVDS_MAX }, | ||
| 164 | .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, | ||
| 165 | /* The single-channel range is 25-112Mhz, and dual-channel | ||
| 166 | * is 80-224Mhz. Prefer single channel as much as possible. | ||
| 167 | */ | ||
| 168 | .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, | ||
| 169 | .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST }, | ||
| 170 | }, | ||
| 171 | }; | ||
| 172 | |||
| 173 | static const intel_limit_t *intel_limit(struct drm_crtc *crtc) | ||
| 174 | { | ||
| 175 | struct drm_device *dev = crtc->dev; | ||
| 176 | const intel_limit_t *limit; | ||
| 177 | |||
| 178 | if (IS_I9XX(dev)) { | ||
| 179 | if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) | ||
| 180 | limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS]; | ||
| 181 | else | ||
| 182 | limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; | ||
| 183 | } else { | ||
| 184 | if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) | ||
| 185 | limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS]; | ||
| 186 | else | ||
| 187 | limit = &intel_limits[INTEL_LIMIT_I8XX_DVO_DAC]; | ||
| 188 | } | ||
| 189 | return limit; | ||
| 190 | } | ||
| 191 | |||
| 192 | /** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ | ||
| 193 | |||
| 194 | static void i8xx_clock(int refclk, intel_clock_t *clock) | ||
| 195 | { | ||
| 196 | clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); | ||
| 197 | clock->p = clock->p1 * clock->p2; | ||
| 198 | clock->vco = refclk * clock->m / (clock->n + 2); | ||
| 199 | clock->dot = clock->vco / clock->p; | ||
| 200 | } | ||
| 201 | |||
| 202 | /** Derive the pixel clock for the given refclk and divisors for 9xx chips. */ | ||
| 203 | |||
| 204 | static void i9xx_clock(int refclk, intel_clock_t *clock) | ||
| 205 | { | ||
| 206 | clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); | ||
| 207 | clock->p = clock->p1 * clock->p2; | ||
| 208 | clock->vco = refclk * clock->m / (clock->n + 2); | ||
| 209 | clock->dot = clock->vco / clock->p; | ||
| 210 | } | ||
| 211 | |||
| 212 | static void intel_clock(struct drm_device *dev, int refclk, | ||
| 213 | intel_clock_t *clock) | ||
| 214 | { | ||
| 215 | if (IS_I9XX(dev)) | ||
| 216 | i9xx_clock (refclk, clock); | ||
| 217 | else | ||
| 218 | i8xx_clock (refclk, clock); | ||
| 219 | } | ||
| 220 | |||
| 221 | /** | ||
| 222 | * Returns whether any output on the specified pipe is of the specified type | ||
| 223 | */ | ||
| 224 | bool intel_pipe_has_type (struct drm_crtc *crtc, int type) | ||
| 225 | { | ||
| 226 | struct drm_device *dev = crtc->dev; | ||
| 227 | struct drm_mode_config *mode_config = &dev->mode_config; | ||
| 228 | struct drm_connector *l_entry; | ||
| 229 | |||
| 230 | list_for_each_entry(l_entry, &mode_config->connector_list, head) { | ||
| 231 | if (l_entry->encoder && | ||
| 232 | l_entry->encoder->crtc == crtc) { | ||
| 233 | struct intel_output *intel_output = to_intel_output(l_entry); | ||
| 234 | if (intel_output->type == type) | ||
| 235 | return true; | ||
| 236 | } | ||
| 237 | } | ||
| 238 | return false; | ||
| 239 | } | ||
| 240 | |||
| 241 | #define INTELPllInvalid(s) { /* ErrorF (s) */; return false; } | ||
| 242 | /** | ||
| 243 | * Returns whether the given set of divisors are valid for a given refclk with | ||
| 244 | * the given connectors. | ||
| 245 | */ | ||
| 246 | |||
| 247 | static bool intel_PLL_is_valid(struct drm_crtc *crtc, intel_clock_t *clock) | ||
| 248 | { | ||
| 249 | const intel_limit_t *limit = intel_limit (crtc); | ||
| 250 | |||
| 251 | if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) | ||
| 252 | INTELPllInvalid ("p1 out of range\n"); | ||
| 253 | if (clock->p < limit->p.min || limit->p.max < clock->p) | ||
| 254 | INTELPllInvalid ("p out of range\n"); | ||
| 255 | if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2) | ||
| 256 | INTELPllInvalid ("m2 out of range\n"); | ||
| 257 | if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1) | ||
| 258 | INTELPllInvalid ("m1 out of range\n"); | ||
| 259 | if (clock->m1 <= clock->m2) | ||
| 260 | INTELPllInvalid ("m1 <= m2\n"); | ||
| 261 | if (clock->m < limit->m.min || limit->m.max < clock->m) | ||
| 262 | INTELPllInvalid ("m out of range\n"); | ||
| 263 | if (clock->n < limit->n.min || limit->n.max < clock->n) | ||
| 264 | INTELPllInvalid ("n out of range\n"); | ||
| 265 | if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) | ||
| 266 | INTELPllInvalid ("vco out of range\n"); | ||
| 267 | /* XXX: We may need to be checking "Dot clock" depending on the multiplier, | ||
| 268 | * connector, etc., rather than just a single range. | ||
| 269 | */ | ||
| 270 | if (clock->dot < limit->dot.min || limit->dot.max < clock->dot) | ||
| 271 | INTELPllInvalid ("dot out of range\n"); | ||
| 272 | |||
| 273 | return true; | ||
| 274 | } | ||
| 275 | |||
| 276 | /** | ||
| 277 | * Returns a set of divisors for the desired target clock with the given | ||
| 278 | * refclk, or FALSE. The returned values represent the clock equation: | ||
| 279 | * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. | ||
| 280 | */ | ||
| 281 | static bool intel_find_best_PLL(struct drm_crtc *crtc, int target, | ||
| 282 | int refclk, intel_clock_t *best_clock) | ||
| 283 | { | ||
| 284 | struct drm_device *dev = crtc->dev; | ||
| 285 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 286 | intel_clock_t clock; | ||
| 287 | const intel_limit_t *limit = intel_limit(crtc); | ||
| 288 | int err = target; | ||
| 289 | |||
| 290 | if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && | ||
| 291 | (I915_READ(LVDS) & LVDS_PORT_EN) != 0) { | ||
| 292 | /* | ||
| 293 | * For LVDS, if the panel is on, just rely on its current | ||
| 294 | * settings for dual-channel. We haven't figured out how to | ||
| 295 | * reliably set up different single/dual channel state, if we | ||
| 296 | * even can. | ||
| 297 | */ | ||
| 298 | if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == | ||
| 299 | LVDS_CLKB_POWER_UP) | ||
| 300 | clock.p2 = limit->p2.p2_fast; | ||
| 301 | else | ||
| 302 | clock.p2 = limit->p2.p2_slow; | ||
| 303 | } else { | ||
| 304 | if (target < limit->p2.dot_limit) | ||
| 305 | clock.p2 = limit->p2.p2_slow; | ||
| 306 | else | ||
| 307 | clock.p2 = limit->p2.p2_fast; | ||
| 308 | } | ||
| 309 | |||
| 310 | memset (best_clock, 0, sizeof (*best_clock)); | ||
| 311 | |||
| 312 | for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { | ||
| 313 | for (clock.m2 = limit->m2.min; clock.m2 < clock.m1 && | ||
| 314 | clock.m2 <= limit->m2.max; clock.m2++) { | ||
| 315 | for (clock.n = limit->n.min; clock.n <= limit->n.max; | ||
| 316 | clock.n++) { | ||
| 317 | for (clock.p1 = limit->p1.min; | ||
| 318 | clock.p1 <= limit->p1.max; clock.p1++) { | ||
| 319 | int this_err; | ||
| 320 | |||
| 321 | intel_clock(dev, refclk, &clock); | ||
| 322 | |||
| 323 | if (!intel_PLL_is_valid(crtc, &clock)) | ||
| 324 | continue; | ||
| 325 | |||
| 326 | this_err = abs(clock.dot - target); | ||
| 327 | if (this_err < err) { | ||
| 328 | *best_clock = clock; | ||
| 329 | err = this_err; | ||
| 330 | } | ||
| 331 | } | ||
| 332 | } | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | return (err != target); | ||
| 337 | } | ||
| 338 | |||
| 339 | void | ||
| 340 | intel_wait_for_vblank(struct drm_device *dev) | ||
| 341 | { | ||
| 342 | /* Wait for 20ms, i.e. one cycle at 50hz. */ | ||
| 343 | udelay(20000); | ||
| 344 | } | ||
| 345 | |||
| 346 | static void | ||
| 347 | intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, | ||
| 348 | struct drm_framebuffer *old_fb) | ||
| 349 | { | ||
| 350 | struct drm_device *dev = crtc->dev; | ||
| 351 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 352 | struct drm_i915_master_private *master_priv; | ||
| 353 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 354 | struct intel_framebuffer *intel_fb; | ||
| 355 | struct drm_i915_gem_object *obj_priv; | ||
| 356 | struct drm_gem_object *obj; | ||
| 357 | int pipe = intel_crtc->pipe; | ||
| 358 | unsigned long Start, Offset; | ||
| 359 | int dspbase = (pipe == 0 ? DSPAADDR : DSPBADDR); | ||
| 360 | int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); | ||
| 361 | int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE; | ||
| 362 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
| 363 | u32 dspcntr, alignment; | ||
| 364 | |||
| 365 | /* no fb bound */ | ||
| 366 | if (!crtc->fb) { | ||
| 367 | DRM_DEBUG("No FB bound\n"); | ||
| 368 | return; | ||
| 369 | } | ||
| 370 | |||
| 371 | intel_fb = to_intel_framebuffer(crtc->fb); | ||
| 372 | obj = intel_fb->obj; | ||
| 373 | obj_priv = obj->driver_private; | ||
| 374 | |||
| 375 | switch (obj_priv->tiling_mode) { | ||
| 376 | case I915_TILING_NONE: | ||
| 377 | alignment = 64 * 1024; | ||
| 378 | break; | ||
| 379 | case I915_TILING_X: | ||
| 380 | if (IS_I9XX(dev)) | ||
| 381 | alignment = 1024 * 1024; | ||
| 382 | else | ||
| 383 | alignment = 512 * 1024; | ||
| 384 | break; | ||
| 385 | case I915_TILING_Y: | ||
| 386 | /* FIXME: Is this true? */ | ||
| 387 | DRM_ERROR("Y tiled not allowed for scan out buffers\n"); | ||
| 388 | return; | ||
| 389 | default: | ||
| 390 | BUG(); | ||
| 391 | } | ||
| 392 | |||
| 393 | if (i915_gem_object_pin(intel_fb->obj, alignment)) | ||
| 394 | return; | ||
| 395 | |||
| 396 | i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1); | ||
| 397 | |||
| 398 | Start = obj_priv->gtt_offset; | ||
| 399 | Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); | ||
| 400 | |||
| 401 | I915_WRITE(dspstride, crtc->fb->pitch); | ||
| 402 | |||
| 403 | dspcntr = I915_READ(dspcntr_reg); | ||
| 404 | switch (crtc->fb->bits_per_pixel) { | ||
| 405 | case 8: | ||
| 406 | dspcntr |= DISPPLANE_8BPP; | ||
| 407 | break; | ||
| 408 | case 16: | ||
| 409 | if (crtc->fb->depth == 15) | ||
| 410 | dspcntr |= DISPPLANE_15_16BPP; | ||
| 411 | else | ||
| 412 | dspcntr |= DISPPLANE_16BPP; | ||
| 413 | break; | ||
| 414 | case 24: | ||
| 415 | case 32: | ||
| 416 | dspcntr |= DISPPLANE_32BPP_NO_ALPHA; | ||
| 417 | break; | ||
| 418 | default: | ||
| 419 | DRM_ERROR("Unknown color depth\n"); | ||
| 420 | return; | ||
| 421 | } | ||
| 422 | I915_WRITE(dspcntr_reg, dspcntr); | ||
| 423 | |||
| 424 | DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); | ||
| 425 | if (IS_I965G(dev)) { | ||
| 426 | I915_WRITE(dspbase, Offset); | ||
| 427 | I915_READ(dspbase); | ||
| 428 | I915_WRITE(dspsurf, Start); | ||
| 429 | I915_READ(dspsurf); | ||
| 430 | } else { | ||
| 431 | I915_WRITE(dspbase, Start + Offset); | ||
| 432 | I915_READ(dspbase); | ||
| 433 | } | ||
| 434 | |||
| 435 | intel_wait_for_vblank(dev); | ||
| 436 | |||
| 437 | if (old_fb) { | ||
| 438 | intel_fb = to_intel_framebuffer(old_fb); | ||
| 439 | i915_gem_object_unpin(intel_fb->obj); | ||
| 440 | } | ||
| 441 | |||
| 442 | if (!dev->primary->master) | ||
| 443 | return; | ||
| 444 | |||
| 445 | master_priv = dev->primary->master->driver_priv; | ||
| 446 | if (!master_priv->sarea_priv) | ||
| 447 | return; | ||
| 448 | |||
| 449 | switch (pipe) { | ||
| 450 | case 0: | ||
| 451 | master_priv->sarea_priv->pipeA_x = x; | ||
| 452 | master_priv->sarea_priv->pipeA_y = y; | ||
| 453 | break; | ||
| 454 | case 1: | ||
| 455 | master_priv->sarea_priv->pipeB_x = x; | ||
| 456 | master_priv->sarea_priv->pipeB_y = y; | ||
| 457 | break; | ||
| 458 | default: | ||
| 459 | DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); | ||
| 460 | break; | ||
| 461 | } | ||
| 462 | } | ||
| 463 | |||
| 464 | |||
| 465 | |||
| 466 | /** | ||
| 467 | * Sets the power management mode of the pipe and plane. | ||
| 468 | * | ||
| 469 | * This code should probably grow support for turning the cursor off and back | ||
| 470 | * on appropriately at the same time as we're turning the pipe off/on. | ||
| 471 | */ | ||
| 472 | static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) | ||
| 473 | { | ||
| 474 | struct drm_device *dev = crtc->dev; | ||
| 475 | struct drm_i915_master_private *master_priv; | ||
| 476 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 477 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 478 | int pipe = intel_crtc->pipe; | ||
| 479 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | ||
| 480 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
| 481 | int dspbase_reg = (pipe == 0) ? DSPAADDR : DSPBADDR; | ||
| 482 | int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
| 483 | u32 temp; | ||
| 484 | bool enabled; | ||
| 485 | |||
| 486 | /* XXX: When our outputs are all unaware of DPMS modes other than off | ||
| 487 | * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. | ||
| 488 | */ | ||
| 489 | switch (mode) { | ||
| 490 | case DRM_MODE_DPMS_ON: | ||
| 491 | case DRM_MODE_DPMS_STANDBY: | ||
| 492 | case DRM_MODE_DPMS_SUSPEND: | ||
| 493 | /* Enable the DPLL */ | ||
| 494 | temp = I915_READ(dpll_reg); | ||
| 495 | if ((temp & DPLL_VCO_ENABLE) == 0) { | ||
| 496 | I915_WRITE(dpll_reg, temp); | ||
| 497 | I915_READ(dpll_reg); | ||
| 498 | /* Wait for the clocks to stabilize. */ | ||
| 499 | udelay(150); | ||
| 500 | I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); | ||
| 501 | I915_READ(dpll_reg); | ||
| 502 | /* Wait for the clocks to stabilize. */ | ||
| 503 | udelay(150); | ||
| 504 | I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); | ||
| 505 | I915_READ(dpll_reg); | ||
| 506 | /* Wait for the clocks to stabilize. */ | ||
| 507 | udelay(150); | ||
| 508 | } | ||
| 509 | |||
| 510 | /* Enable the pipe */ | ||
| 511 | temp = I915_READ(pipeconf_reg); | ||
| 512 | if ((temp & PIPEACONF_ENABLE) == 0) | ||
| 513 | I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); | ||
| 514 | |||
| 515 | /* Enable the plane */ | ||
| 516 | temp = I915_READ(dspcntr_reg); | ||
| 517 | if ((temp & DISPLAY_PLANE_ENABLE) == 0) { | ||
| 518 | I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); | ||
| 519 | /* Flush the plane changes */ | ||
| 520 | I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); | ||
| 521 | } | ||
| 522 | |||
| 523 | intel_crtc_load_lut(crtc); | ||
| 524 | |||
| 525 | /* Give the overlay scaler a chance to enable if it's on this pipe */ | ||
| 526 | //intel_crtc_dpms_video(crtc, true); TODO | ||
| 527 | break; | ||
| 528 | case DRM_MODE_DPMS_OFF: | ||
| 529 | /* Give the overlay scaler a chance to disable if it's on this pipe */ | ||
| 530 | //intel_crtc_dpms_video(crtc, FALSE); TODO | ||
| 531 | |||
| 532 | /* Disable the VGA plane that we never use */ | ||
| 533 | I915_WRITE(VGACNTRL, VGA_DISP_DISABLE); | ||
| 534 | |||
| 535 | /* Disable display plane */ | ||
| 536 | temp = I915_READ(dspcntr_reg); | ||
| 537 | if ((temp & DISPLAY_PLANE_ENABLE) != 0) { | ||
| 538 | I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); | ||
| 539 | /* Flush the plane changes */ | ||
| 540 | I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); | ||
| 541 | I915_READ(dspbase_reg); | ||
| 542 | } | ||
| 543 | |||
| 544 | if (!IS_I9XX(dev)) { | ||
| 545 | /* Wait for vblank for the disable to take effect */ | ||
| 546 | intel_wait_for_vblank(dev); | ||
| 547 | } | ||
| 548 | |||
| 549 | /* Next, disable display pipes */ | ||
| 550 | temp = I915_READ(pipeconf_reg); | ||
| 551 | if ((temp & PIPEACONF_ENABLE) != 0) { | ||
| 552 | I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); | ||
| 553 | I915_READ(pipeconf_reg); | ||
| 554 | } | ||
| 555 | |||
| 556 | /* Wait for vblank for the disable to take effect. */ | ||
| 557 | intel_wait_for_vblank(dev); | ||
| 558 | |||
| 559 | temp = I915_READ(dpll_reg); | ||
| 560 | if ((temp & DPLL_VCO_ENABLE) != 0) { | ||
| 561 | I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE); | ||
| 562 | I915_READ(dpll_reg); | ||
| 563 | } | ||
| 564 | |||
| 565 | /* Wait for the clocks to turn off. */ | ||
| 566 | udelay(150); | ||
| 567 | break; | ||
| 568 | } | ||
| 569 | |||
| 570 | if (!dev->primary->master) | ||
| 571 | return; | ||
| 572 | |||
| 573 | master_priv = dev->primary->master->driver_priv; | ||
| 574 | if (!master_priv->sarea_priv) | ||
| 575 | return; | ||
| 576 | |||
| 577 | enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF; | ||
| 578 | |||
| 579 | switch (pipe) { | ||
| 580 | case 0: | ||
| 581 | master_priv->sarea_priv->pipeA_w = enabled ? crtc->mode.hdisplay : 0; | ||
| 582 | master_priv->sarea_priv->pipeA_h = enabled ? crtc->mode.vdisplay : 0; | ||
| 583 | break; | ||
| 584 | case 1: | ||
| 585 | master_priv->sarea_priv->pipeB_w = enabled ? crtc->mode.hdisplay : 0; | ||
| 586 | master_priv->sarea_priv->pipeB_h = enabled ? crtc->mode.vdisplay : 0; | ||
| 587 | break; | ||
| 588 | default: | ||
| 589 | DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); | ||
| 590 | break; | ||
| 591 | } | ||
| 592 | |||
| 593 | intel_crtc->dpms_mode = mode; | ||
| 594 | } | ||
| 595 | |||
| 596 | static void intel_crtc_prepare (struct drm_crtc *crtc) | ||
| 597 | { | ||
| 598 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
| 599 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); | ||
| 600 | } | ||
| 601 | |||
| 602 | static void intel_crtc_commit (struct drm_crtc *crtc) | ||
| 603 | { | ||
| 604 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
| 605 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
| 606 | } | ||
| 607 | |||
| 608 | void intel_encoder_prepare (struct drm_encoder *encoder) | ||
| 609 | { | ||
| 610 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; | ||
| 611 | /* lvds has its own version of prepare see intel_lvds_prepare */ | ||
| 612 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); | ||
| 613 | } | ||
| 614 | |||
| 615 | void intel_encoder_commit (struct drm_encoder *encoder) | ||
| 616 | { | ||
| 617 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; | ||
| 618 | /* lvds has its own version of commit see intel_lvds_commit */ | ||
| 619 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); | ||
| 620 | } | ||
| 621 | |||
| 622 | static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, | ||
| 623 | struct drm_display_mode *mode, | ||
| 624 | struct drm_display_mode *adjusted_mode) | ||
| 625 | { | ||
| 626 | return true; | ||
| 627 | } | ||
| 628 | |||
| 629 | |||
| 630 | /** Returns the core display clock speed for i830 - i945 */ | ||
| 631 | static int intel_get_core_clock_speed(struct drm_device *dev) | ||
| 632 | { | ||
| 633 | |||
| 634 | /* Core clock values taken from the published datasheets. | ||
| 635 | * The 830 may go up to 166 Mhz, which we should check. | ||
| 636 | */ | ||
| 637 | if (IS_I945G(dev)) | ||
| 638 | return 400000; | ||
| 639 | else if (IS_I915G(dev)) | ||
| 640 | return 333000; | ||
| 641 | else if (IS_I945GM(dev) || IS_845G(dev)) | ||
| 642 | return 200000; | ||
| 643 | else if (IS_I915GM(dev)) { | ||
| 644 | u16 gcfgc = 0; | ||
| 645 | |||
| 646 | pci_read_config_word(dev->pdev, GCFGC, &gcfgc); | ||
| 647 | |||
| 648 | if (gcfgc & GC_LOW_FREQUENCY_ENABLE) | ||
| 649 | return 133000; | ||
| 650 | else { | ||
| 651 | switch (gcfgc & GC_DISPLAY_CLOCK_MASK) { | ||
| 652 | case GC_DISPLAY_CLOCK_333_MHZ: | ||
| 653 | return 333000; | ||
| 654 | default: | ||
| 655 | case GC_DISPLAY_CLOCK_190_200_MHZ: | ||
| 656 | return 190000; | ||
| 657 | } | ||
| 658 | } | ||
| 659 | } else if (IS_I865G(dev)) | ||
| 660 | return 266000; | ||
| 661 | else if (IS_I855(dev)) { | ||
| 662 | u16 hpllcc = 0; | ||
| 663 | /* Assume that the hardware is in the high speed state. This | ||
| 664 | * should be the default. | ||
| 665 | */ | ||
| 666 | switch (hpllcc & GC_CLOCK_CONTROL_MASK) { | ||
| 667 | case GC_CLOCK_133_200: | ||
| 668 | case GC_CLOCK_100_200: | ||
| 669 | return 200000; | ||
| 670 | case GC_CLOCK_166_250: | ||
| 671 | return 250000; | ||
| 672 | case GC_CLOCK_100_133: | ||
| 673 | return 133000; | ||
| 674 | } | ||
| 675 | } else /* 852, 830 */ | ||
| 676 | return 133000; | ||
| 677 | |||
| 678 | return 0; /* Silence gcc warning */ | ||
| 679 | } | ||
| 680 | |||
| 681 | |||
| 682 | /** | ||
| 683 | * Return the pipe currently connected to the panel fitter, | ||
| 684 | * or -1 if the panel fitter is not present or not in use | ||
| 685 | */ | ||
| 686 | static int intel_panel_fitter_pipe (struct drm_device *dev) | ||
| 687 | { | ||
| 688 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 689 | u32 pfit_control; | ||
| 690 | |||
| 691 | /* i830 doesn't have a panel fitter */ | ||
| 692 | if (IS_I830(dev)) | ||
| 693 | return -1; | ||
| 694 | |||
| 695 | pfit_control = I915_READ(PFIT_CONTROL); | ||
| 696 | |||
| 697 | /* See if the panel fitter is in use */ | ||
| 698 | if ((pfit_control & PFIT_ENABLE) == 0) | ||
| 699 | return -1; | ||
| 700 | |||
| 701 | /* 965 can place panel fitter on either pipe */ | ||
| 702 | if (IS_I965G(dev)) | ||
| 703 | return (pfit_control >> 29) & 0x3; | ||
| 704 | |||
| 705 | /* older chips can only use pipe 1 */ | ||
| 706 | return 1; | ||
| 707 | } | ||
| 708 | |||
| 709 | static void intel_crtc_mode_set(struct drm_crtc *crtc, | ||
| 710 | struct drm_display_mode *mode, | ||
| 711 | struct drm_display_mode *adjusted_mode, | ||
| 712 | int x, int y, | ||
| 713 | struct drm_framebuffer *old_fb) | ||
| 714 | { | ||
| 715 | struct drm_device *dev = crtc->dev; | ||
| 716 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 717 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 718 | int pipe = intel_crtc->pipe; | ||
| 719 | int fp_reg = (pipe == 0) ? FPA0 : FPB0; | ||
| 720 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | ||
| 721 | int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD; | ||
| 722 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
| 723 | int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
| 724 | int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; | ||
| 725 | int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; | ||
| 726 | int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; | ||
| 727 | int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; | ||
| 728 | int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; | ||
| 729 | int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; | ||
| 730 | int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE; | ||
| 731 | int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS; | ||
| 732 | int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; | ||
| 733 | int refclk; | ||
| 734 | intel_clock_t clock; | ||
| 735 | u32 dpll = 0, fp = 0, dspcntr, pipeconf; | ||
| 736 | bool ok, is_sdvo = false, is_dvo = false; | ||
| 737 | bool is_crt = false, is_lvds = false, is_tv = false; | ||
| 738 | struct drm_mode_config *mode_config = &dev->mode_config; | ||
| 739 | struct drm_connector *connector; | ||
| 740 | |||
| 741 | drm_vblank_pre_modeset(dev, pipe); | ||
| 742 | |||
| 743 | list_for_each_entry(connector, &mode_config->connector_list, head) { | ||
| 744 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 745 | |||
| 746 | if (!connector->encoder || connector->encoder->crtc != crtc) | ||
| 747 | continue; | ||
| 748 | |||
| 749 | switch (intel_output->type) { | ||
| 750 | case INTEL_OUTPUT_LVDS: | ||
| 751 | is_lvds = true; | ||
| 752 | break; | ||
| 753 | case INTEL_OUTPUT_SDVO: | ||
| 754 | is_sdvo = true; | ||
| 755 | break; | ||
| 756 | case INTEL_OUTPUT_DVO: | ||
| 757 | is_dvo = true; | ||
| 758 | break; | ||
| 759 | case INTEL_OUTPUT_TVOUT: | ||
| 760 | is_tv = true; | ||
| 761 | break; | ||
| 762 | case INTEL_OUTPUT_ANALOG: | ||
| 763 | is_crt = true; | ||
| 764 | break; | ||
| 765 | } | ||
| 766 | } | ||
| 767 | |||
| 768 | if (IS_I9XX(dev)) { | ||
| 769 | refclk = 96000; | ||
| 770 | } else { | ||
| 771 | refclk = 48000; | ||
| 772 | } | ||
| 773 | |||
| 774 | ok = intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, &clock); | ||
| 775 | if (!ok) { | ||
| 776 | DRM_ERROR("Couldn't find PLL settings for mode!\n"); | ||
| 777 | return; | ||
| 778 | } | ||
| 779 | |||
| 780 | fp = clock.n << 16 | clock.m1 << 8 | clock.m2; | ||
| 781 | |||
| 782 | dpll = DPLL_VGA_MODE_DIS; | ||
| 783 | if (IS_I9XX(dev)) { | ||
| 784 | if (is_lvds) | ||
| 785 | dpll |= DPLLB_MODE_LVDS; | ||
| 786 | else | ||
| 787 | dpll |= DPLLB_MODE_DAC_SERIAL; | ||
| 788 | if (is_sdvo) { | ||
| 789 | dpll |= DPLL_DVO_HIGH_SPEED; | ||
| 790 | if (IS_I945G(dev) || IS_I945GM(dev)) { | ||
| 791 | int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; | ||
| 792 | dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; | ||
| 793 | } | ||
| 794 | } | ||
| 795 | |||
| 796 | /* compute bitmask from p1 value */ | ||
| 797 | dpll |= (1 << (clock.p1 - 1)) << 16; | ||
| 798 | switch (clock.p2) { | ||
| 799 | case 5: | ||
| 800 | dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; | ||
| 801 | break; | ||
| 802 | case 7: | ||
| 803 | dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7; | ||
| 804 | break; | ||
| 805 | case 10: | ||
| 806 | dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10; | ||
| 807 | break; | ||
| 808 | case 14: | ||
| 809 | dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; | ||
| 810 | break; | ||
| 811 | } | ||
| 812 | if (IS_I965G(dev)) | ||
| 813 | dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); | ||
| 814 | } else { | ||
| 815 | if (is_lvds) { | ||
| 816 | dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; | ||
| 817 | } else { | ||
| 818 | if (clock.p1 == 2) | ||
| 819 | dpll |= PLL_P1_DIVIDE_BY_TWO; | ||
| 820 | else | ||
| 821 | dpll |= (clock.p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT; | ||
| 822 | if (clock.p2 == 4) | ||
| 823 | dpll |= PLL_P2_DIVIDE_BY_4; | ||
| 824 | } | ||
| 825 | } | ||
| 826 | |||
| 827 | if (is_tv) { | ||
| 828 | /* XXX: just matching BIOS for now */ | ||
| 829 | /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ | ||
| 830 | dpll |= 3; | ||
| 831 | } | ||
| 832 | else | ||
| 833 | dpll |= PLL_REF_INPUT_DREFCLK; | ||
| 834 | |||
| 835 | /* setup pipeconf */ | ||
| 836 | pipeconf = I915_READ(pipeconf_reg); | ||
| 837 | |||
| 838 | /* Set up the display plane register */ | ||
| 839 | dspcntr = DISPPLANE_GAMMA_ENABLE; | ||
| 840 | |||
| 841 | if (pipe == 0) | ||
| 842 | dspcntr |= DISPPLANE_SEL_PIPE_A; | ||
| 843 | else | ||
| 844 | dspcntr |= DISPPLANE_SEL_PIPE_B; | ||
| 845 | |||
| 846 | if (pipe == 0 && !IS_I965G(dev)) { | ||
| 847 | /* Enable pixel doubling when the dot clock is > 90% of the (display) | ||
| 848 | * core speed. | ||
| 849 | * | ||
| 850 | * XXX: No double-wide on 915GM pipe B. Is that the only reason for the | ||
| 851 | * pipe == 0 check? | ||
| 852 | */ | ||
| 853 | if (mode->clock > intel_get_core_clock_speed(dev) * 9 / 10) | ||
| 854 | pipeconf |= PIPEACONF_DOUBLE_WIDE; | ||
| 855 | else | ||
| 856 | pipeconf &= ~PIPEACONF_DOUBLE_WIDE; | ||
| 857 | } | ||
| 858 | |||
| 859 | dspcntr |= DISPLAY_PLANE_ENABLE; | ||
| 860 | pipeconf |= PIPEACONF_ENABLE; | ||
| 861 | dpll |= DPLL_VCO_ENABLE; | ||
| 862 | |||
| 863 | |||
| 864 | /* Disable the panel fitter if it was on our pipe */ | ||
| 865 | if (intel_panel_fitter_pipe(dev) == pipe) | ||
| 866 | I915_WRITE(PFIT_CONTROL, 0); | ||
| 867 | |||
| 868 | DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); | ||
| 869 | drm_mode_debug_printmodeline(mode); | ||
| 870 | |||
| 871 | |||
| 872 | if (dpll & DPLL_VCO_ENABLE) { | ||
| 873 | I915_WRITE(fp_reg, fp); | ||
| 874 | I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); | ||
| 875 | I915_READ(dpll_reg); | ||
| 876 | udelay(150); | ||
| 877 | } | ||
| 878 | |||
| 879 | /* The LVDS pin pair needs to be on before the DPLLs are enabled. | ||
| 880 | * This is an exception to the general rule that mode_set doesn't turn | ||
| 881 | * things on. | ||
| 882 | */ | ||
| 883 | if (is_lvds) { | ||
| 884 | u32 lvds = I915_READ(LVDS); | ||
| 885 | |||
| 886 | lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; | ||
| 887 | /* Set the B0-B3 data pairs corresponding to whether we're going to | ||
| 888 | * set the DPLLs for dual-channel mode or not. | ||
| 889 | */ | ||
| 890 | if (clock.p2 == 7) | ||
| 891 | lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; | ||
| 892 | else | ||
| 893 | lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); | ||
| 894 | |||
| 895 | /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) | ||
| 896 | * appropriately here, but we need to look more thoroughly into how | ||
| 897 | * panels behave in the two modes. | ||
| 898 | */ | ||
| 899 | |||
| 900 | I915_WRITE(LVDS, lvds); | ||
| 901 | I915_READ(LVDS); | ||
| 902 | } | ||
| 903 | |||
| 904 | I915_WRITE(fp_reg, fp); | ||
| 905 | I915_WRITE(dpll_reg, dpll); | ||
| 906 | I915_READ(dpll_reg); | ||
| 907 | /* Wait for the clocks to stabilize. */ | ||
| 908 | udelay(150); | ||
| 909 | |||
| 910 | if (IS_I965G(dev)) { | ||
| 911 | int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; | ||
| 912 | I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | | ||
| 913 | ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); | ||
| 914 | } else { | ||
| 915 | /* write it again -- the BIOS does, after all */ | ||
| 916 | I915_WRITE(dpll_reg, dpll); | ||
| 917 | } | ||
| 918 | I915_READ(dpll_reg); | ||
| 919 | /* Wait for the clocks to stabilize. */ | ||
| 920 | udelay(150); | ||
| 921 | |||
| 922 | I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | | ||
| 923 | ((adjusted_mode->crtc_htotal - 1) << 16)); | ||
| 924 | I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | | ||
| 925 | ((adjusted_mode->crtc_hblank_end - 1) << 16)); | ||
| 926 | I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | | ||
| 927 | ((adjusted_mode->crtc_hsync_end - 1) << 16)); | ||
| 928 | I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | | ||
| 929 | ((adjusted_mode->crtc_vtotal - 1) << 16)); | ||
| 930 | I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | | ||
| 931 | ((adjusted_mode->crtc_vblank_end - 1) << 16)); | ||
| 932 | I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | | ||
| 933 | ((adjusted_mode->crtc_vsync_end - 1) << 16)); | ||
| 934 | /* pipesrc and dspsize control the size that is scaled from, which should | ||
| 935 | * always be the user's requested size. | ||
| 936 | */ | ||
| 937 | I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); | ||
| 938 | I915_WRITE(dsppos_reg, 0); | ||
| 939 | I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); | ||
| 940 | I915_WRITE(pipeconf_reg, pipeconf); | ||
| 941 | I915_READ(pipeconf_reg); | ||
| 942 | |||
| 943 | intel_wait_for_vblank(dev); | ||
| 944 | |||
| 945 | I915_WRITE(dspcntr_reg, dspcntr); | ||
| 946 | |||
| 947 | /* Flush the plane changes */ | ||
| 948 | intel_pipe_set_base(crtc, x, y, old_fb); | ||
| 949 | |||
| 950 | drm_vblank_post_modeset(dev, pipe); | ||
| 951 | } | ||
| 952 | |||
| 953 | /** Loads the palette/gamma unit for the CRTC with the prepared values */ | ||
| 954 | void intel_crtc_load_lut(struct drm_crtc *crtc) | ||
| 955 | { | ||
| 956 | struct drm_device *dev = crtc->dev; | ||
| 957 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 958 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 959 | int palreg = (intel_crtc->pipe == 0) ? PALETTE_A : PALETTE_B; | ||
| 960 | int i; | ||
| 961 | |||
| 962 | /* The clocks have to be on to load the palette. */ | ||
| 963 | if (!crtc->enabled) | ||
| 964 | return; | ||
| 965 | |||
| 966 | for (i = 0; i < 256; i++) { | ||
| 967 | I915_WRITE(palreg + 4 * i, | ||
| 968 | (intel_crtc->lut_r[i] << 16) | | ||
| 969 | (intel_crtc->lut_g[i] << 8) | | ||
| 970 | intel_crtc->lut_b[i]); | ||
| 971 | } | ||
| 972 | } | ||
| 973 | |||
| 974 | static int intel_crtc_cursor_set(struct drm_crtc *crtc, | ||
| 975 | struct drm_file *file_priv, | ||
| 976 | uint32_t handle, | ||
| 977 | uint32_t width, uint32_t height) | ||
| 978 | { | ||
| 979 | struct drm_device *dev = crtc->dev; | ||
| 980 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 981 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 982 | struct drm_gem_object *bo; | ||
| 983 | struct drm_i915_gem_object *obj_priv; | ||
| 984 | int pipe = intel_crtc->pipe; | ||
| 985 | uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; | ||
| 986 | uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; | ||
| 987 | uint32_t temp; | ||
| 988 | size_t addr; | ||
| 989 | |||
| 990 | DRM_DEBUG("\n"); | ||
| 991 | |||
| 992 | /* if we want to turn off the cursor ignore width and height */ | ||
| 993 | if (!handle) { | ||
| 994 | DRM_DEBUG("cursor off\n"); | ||
| 995 | /* turn of the cursor */ | ||
| 996 | temp = 0; | ||
| 997 | temp |= CURSOR_MODE_DISABLE; | ||
| 998 | |||
| 999 | I915_WRITE(control, temp); | ||
| 1000 | I915_WRITE(base, 0); | ||
| 1001 | return 0; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | /* Currently we only support 64x64 cursors */ | ||
| 1005 | if (width != 64 || height != 64) { | ||
| 1006 | DRM_ERROR("we currently only support 64x64 cursors\n"); | ||
| 1007 | return -EINVAL; | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | bo = drm_gem_object_lookup(dev, file_priv, handle); | ||
| 1011 | if (!bo) | ||
| 1012 | return -ENOENT; | ||
| 1013 | |||
| 1014 | obj_priv = bo->driver_private; | ||
| 1015 | |||
| 1016 | if (bo->size < width * height * 4) { | ||
| 1017 | DRM_ERROR("buffer is to small\n"); | ||
| 1018 | drm_gem_object_unreference(bo); | ||
| 1019 | return -ENOMEM; | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | if (dev_priv->cursor_needs_physical) { | ||
| 1023 | addr = dev->agp->base + obj_priv->gtt_offset; | ||
| 1024 | } else { | ||
| 1025 | addr = obj_priv->gtt_offset; | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | intel_crtc->cursor_addr = addr; | ||
| 1029 | temp = 0; | ||
| 1030 | /* set the pipe for the cursor */ | ||
| 1031 | temp |= (pipe << 28); | ||
| 1032 | temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; | ||
| 1033 | |||
| 1034 | I915_WRITE(control, temp); | ||
| 1035 | I915_WRITE(base, addr); | ||
| 1036 | |||
| 1037 | return 0; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) | ||
| 1041 | { | ||
| 1042 | struct drm_device *dev = crtc->dev; | ||
| 1043 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 1044 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 1045 | int pipe = intel_crtc->pipe; | ||
| 1046 | uint32_t temp = 0; | ||
| 1047 | uint32_t adder; | ||
| 1048 | |||
| 1049 | if (x < 0) { | ||
| 1050 | temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT); | ||
| 1051 | x = -x; | ||
| 1052 | } | ||
| 1053 | if (y < 0) { | ||
| 1054 | temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT); | ||
| 1055 | y = -y; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT); | ||
| 1059 | temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); | ||
| 1060 | |||
| 1061 | adder = intel_crtc->cursor_addr; | ||
| 1062 | I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp); | ||
| 1063 | I915_WRITE((pipe == 0) ? CURABASE : CURBBASE, adder); | ||
| 1064 | |||
| 1065 | return 0; | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | /** Sets the color ramps on behalf of RandR */ | ||
| 1069 | void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, | ||
| 1070 | u16 blue, int regno) | ||
| 1071 | { | ||
| 1072 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 1073 | |||
| 1074 | intel_crtc->lut_r[regno] = red >> 8; | ||
| 1075 | intel_crtc->lut_g[regno] = green >> 8; | ||
| 1076 | intel_crtc->lut_b[regno] = blue >> 8; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, | ||
| 1080 | u16 *blue, uint32_t size) | ||
| 1081 | { | ||
| 1082 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 1083 | int i; | ||
| 1084 | |||
| 1085 | if (size != 256) | ||
| 1086 | return; | ||
| 1087 | |||
| 1088 | for (i = 0; i < 256; i++) { | ||
| 1089 | intel_crtc->lut_r[i] = red[i] >> 8; | ||
| 1090 | intel_crtc->lut_g[i] = green[i] >> 8; | ||
| 1091 | intel_crtc->lut_b[i] = blue[i] >> 8; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | intel_crtc_load_lut(crtc); | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | /** | ||
| 1098 | * Get a pipe with a simple mode set on it for doing load-based monitor | ||
| 1099 | * detection. | ||
| 1100 | * | ||
| 1101 | * It will be up to the load-detect code to adjust the pipe as appropriate for | ||
| 1102 | * its requirements. The pipe will be connected to no other outputs. | ||
| 1103 | * | ||
| 1104 | * Currently this code will only succeed if there is a pipe with no outputs | ||
| 1105 | * configured for it. In the future, it could choose to temporarily disable | ||
| 1106 | * some outputs to free up a pipe for its use. | ||
| 1107 | * | ||
| 1108 | * \return crtc, or NULL if no pipes are available. | ||
| 1109 | */ | ||
| 1110 | |||
| 1111 | /* VESA 640x480x72Hz mode to set on the pipe */ | ||
| 1112 | static struct drm_display_mode load_detect_mode = { | ||
| 1113 | DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664, | ||
| 1114 | 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
| 1115 | }; | ||
| 1116 | |||
| 1117 | struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, | ||
| 1118 | struct drm_display_mode *mode, | ||
| 1119 | int *dpms_mode) | ||
| 1120 | { | ||
| 1121 | struct intel_crtc *intel_crtc; | ||
| 1122 | struct drm_crtc *possible_crtc; | ||
| 1123 | struct drm_crtc *supported_crtc =NULL; | ||
| 1124 | struct drm_encoder *encoder = &intel_output->enc; | ||
| 1125 | struct drm_crtc *crtc = NULL; | ||
| 1126 | struct drm_device *dev = encoder->dev; | ||
| 1127 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; | ||
| 1128 | struct drm_crtc_helper_funcs *crtc_funcs; | ||
| 1129 | int i = -1; | ||
| 1130 | |||
| 1131 | /* | ||
| 1132 | * Algorithm gets a little messy: | ||
| 1133 | * - if the connector already has an assigned crtc, use it (but make | ||
| 1134 | * sure it's on first) | ||
| 1135 | * - try to find the first unused crtc that can drive this connector, | ||
| 1136 | * and use that if we find one | ||
| 1137 | * - if there are no unused crtcs available, try to use the first | ||
| 1138 | * one we found that supports the connector | ||
| 1139 | */ | ||
| 1140 | |||
| 1141 | /* See if we already have a CRTC for this connector */ | ||
| 1142 | if (encoder->crtc) { | ||
| 1143 | crtc = encoder->crtc; | ||
| 1144 | /* Make sure the crtc and connector are running */ | ||
| 1145 | intel_crtc = to_intel_crtc(crtc); | ||
| 1146 | *dpms_mode = intel_crtc->dpms_mode; | ||
| 1147 | if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) { | ||
| 1148 | crtc_funcs = crtc->helper_private; | ||
| 1149 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
| 1150 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); | ||
| 1151 | } | ||
| 1152 | return crtc; | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | /* Find an unused one (if possible) */ | ||
| 1156 | list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) { | ||
| 1157 | i++; | ||
| 1158 | if (!(encoder->possible_crtcs & (1 << i))) | ||
| 1159 | continue; | ||
| 1160 | if (!possible_crtc->enabled) { | ||
| 1161 | crtc = possible_crtc; | ||
| 1162 | break; | ||
| 1163 | } | ||
| 1164 | if (!supported_crtc) | ||
| 1165 | supported_crtc = possible_crtc; | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | /* | ||
| 1169 | * If we didn't find an unused CRTC, don't use any. | ||
| 1170 | */ | ||
| 1171 | if (!crtc) { | ||
| 1172 | return NULL; | ||
| 1173 | } | ||
| 1174 | |||
| 1175 | encoder->crtc = crtc; | ||
| 1176 | intel_output->load_detect_temp = true; | ||
| 1177 | |||
| 1178 | intel_crtc = to_intel_crtc(crtc); | ||
| 1179 | *dpms_mode = intel_crtc->dpms_mode; | ||
| 1180 | |||
| 1181 | if (!crtc->enabled) { | ||
| 1182 | if (!mode) | ||
| 1183 | mode = &load_detect_mode; | ||
| 1184 | drm_crtc_helper_set_mode(crtc, mode, 0, 0, crtc->fb); | ||
| 1185 | } else { | ||
| 1186 | if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) { | ||
| 1187 | crtc_funcs = crtc->helper_private; | ||
| 1188 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | /* Add this connector to the crtc */ | ||
| 1192 | encoder_funcs->mode_set(encoder, &crtc->mode, &crtc->mode); | ||
| 1193 | encoder_funcs->commit(encoder); | ||
| 1194 | } | ||
| 1195 | /* let the connector get through one full cycle before testing */ | ||
| 1196 | intel_wait_for_vblank(dev); | ||
| 1197 | |||
| 1198 | return crtc; | ||
| 1199 | } | ||
| 1200 | |||
| 1201 | void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_mode) | ||
| 1202 | { | ||
| 1203 | struct drm_encoder *encoder = &intel_output->enc; | ||
| 1204 | struct drm_device *dev = encoder->dev; | ||
| 1205 | struct drm_crtc *crtc = encoder->crtc; | ||
| 1206 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; | ||
| 1207 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
| 1208 | |||
| 1209 | if (intel_output->load_detect_temp) { | ||
| 1210 | encoder->crtc = NULL; | ||
| 1211 | intel_output->load_detect_temp = false; | ||
| 1212 | crtc->enabled = drm_helper_crtc_in_use(crtc); | ||
| 1213 | drm_helper_disable_unused_functions(dev); | ||
| 1214 | } | ||
| 1215 | |||
| 1216 | /* Switch crtc and output back off if necessary */ | ||
| 1217 | if (crtc->enabled && dpms_mode != DRM_MODE_DPMS_ON) { | ||
| 1218 | if (encoder->crtc == crtc) | ||
| 1219 | encoder_funcs->dpms(encoder, dpms_mode); | ||
| 1220 | crtc_funcs->dpms(crtc, dpms_mode); | ||
| 1221 | } | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | /* Returns the clock of the currently programmed mode of the given pipe. */ | ||
| 1225 | static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) | ||
| 1226 | { | ||
| 1227 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 1228 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 1229 | int pipe = intel_crtc->pipe; | ||
| 1230 | u32 dpll = I915_READ((pipe == 0) ? DPLL_A : DPLL_B); | ||
| 1231 | u32 fp; | ||
| 1232 | intel_clock_t clock; | ||
| 1233 | |||
| 1234 | if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) | ||
| 1235 | fp = I915_READ((pipe == 0) ? FPA0 : FPB0); | ||
| 1236 | else | ||
| 1237 | fp = I915_READ((pipe == 0) ? FPA1 : FPB1); | ||
| 1238 | |||
| 1239 | clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; | ||
| 1240 | clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; | ||
| 1241 | clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; | ||
| 1242 | if (IS_I9XX(dev)) { | ||
| 1243 | clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >> | ||
| 1244 | DPLL_FPA01_P1_POST_DIV_SHIFT); | ||
| 1245 | |||
| 1246 | switch (dpll & DPLL_MODE_MASK) { | ||
| 1247 | case DPLLB_MODE_DAC_SERIAL: | ||
| 1248 | clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? | ||
| 1249 | 5 : 10; | ||
| 1250 | break; | ||
| 1251 | case DPLLB_MODE_LVDS: | ||
| 1252 | clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ? | ||
| 1253 | 7 : 14; | ||
| 1254 | break; | ||
| 1255 | default: | ||
| 1256 | DRM_DEBUG("Unknown DPLL mode %08x in programmed " | ||
| 1257 | "mode\n", (int)(dpll & DPLL_MODE_MASK)); | ||
| 1258 | return 0; | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | /* XXX: Handle the 100Mhz refclk */ | ||
| 1262 | i9xx_clock(96000, &clock); | ||
| 1263 | } else { | ||
| 1264 | bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN); | ||
| 1265 | |||
| 1266 | if (is_lvds) { | ||
| 1267 | clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> | ||
| 1268 | DPLL_FPA01_P1_POST_DIV_SHIFT); | ||
| 1269 | clock.p2 = 14; | ||
| 1270 | |||
| 1271 | if ((dpll & PLL_REF_INPUT_MASK) == | ||
| 1272 | PLLB_REF_INPUT_SPREADSPECTRUMIN) { | ||
| 1273 | /* XXX: might not be 66MHz */ | ||
| 1274 | i8xx_clock(66000, &clock); | ||
| 1275 | } else | ||
| 1276 | i8xx_clock(48000, &clock); | ||
| 1277 | } else { | ||
| 1278 | if (dpll & PLL_P1_DIVIDE_BY_TWO) | ||
| 1279 | clock.p1 = 2; | ||
| 1280 | else { | ||
| 1281 | clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >> | ||
| 1282 | DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; | ||
| 1283 | } | ||
| 1284 | if (dpll & PLL_P2_DIVIDE_BY_4) | ||
| 1285 | clock.p2 = 4; | ||
| 1286 | else | ||
| 1287 | clock.p2 = 2; | ||
| 1288 | |||
| 1289 | i8xx_clock(48000, &clock); | ||
| 1290 | } | ||
| 1291 | } | ||
| 1292 | |||
| 1293 | /* XXX: It would be nice to validate the clocks, but we can't reuse | ||
| 1294 | * i830PllIsValid() because it relies on the xf86_config connector | ||
| 1295 | * configuration being accurate, which it isn't necessarily. | ||
| 1296 | */ | ||
| 1297 | |||
| 1298 | return clock.dot; | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | /** Returns the currently programmed mode of the given pipe. */ | ||
| 1302 | struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, | ||
| 1303 | struct drm_crtc *crtc) | ||
| 1304 | { | ||
| 1305 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 1306 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 1307 | int pipe = intel_crtc->pipe; | ||
| 1308 | struct drm_display_mode *mode; | ||
| 1309 | int htot = I915_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B); | ||
| 1310 | int hsync = I915_READ((pipe == 0) ? HSYNC_A : HSYNC_B); | ||
| 1311 | int vtot = I915_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B); | ||
| 1312 | int vsync = I915_READ((pipe == 0) ? VSYNC_A : VSYNC_B); | ||
| 1313 | |||
| 1314 | mode = kzalloc(sizeof(*mode), GFP_KERNEL); | ||
| 1315 | if (!mode) | ||
| 1316 | return NULL; | ||
| 1317 | |||
| 1318 | mode->clock = intel_crtc_clock_get(dev, crtc); | ||
| 1319 | mode->hdisplay = (htot & 0xffff) + 1; | ||
| 1320 | mode->htotal = ((htot & 0xffff0000) >> 16) + 1; | ||
| 1321 | mode->hsync_start = (hsync & 0xffff) + 1; | ||
| 1322 | mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1; | ||
| 1323 | mode->vdisplay = (vtot & 0xffff) + 1; | ||
| 1324 | mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1; | ||
| 1325 | mode->vsync_start = (vsync & 0xffff) + 1; | ||
| 1326 | mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1; | ||
| 1327 | |||
| 1328 | drm_mode_set_name(mode); | ||
| 1329 | drm_mode_set_crtcinfo(mode, 0); | ||
| 1330 | |||
| 1331 | return mode; | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | static void intel_crtc_destroy(struct drm_crtc *crtc) | ||
| 1335 | { | ||
| 1336 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 1337 | |||
| 1338 | drm_crtc_cleanup(crtc); | ||
| 1339 | kfree(intel_crtc); | ||
| 1340 | } | ||
| 1341 | |||
| 1342 | static const struct drm_crtc_helper_funcs intel_helper_funcs = { | ||
| 1343 | .dpms = intel_crtc_dpms, | ||
| 1344 | .mode_fixup = intel_crtc_mode_fixup, | ||
| 1345 | .mode_set = intel_crtc_mode_set, | ||
| 1346 | .mode_set_base = intel_pipe_set_base, | ||
| 1347 | .prepare = intel_crtc_prepare, | ||
| 1348 | .commit = intel_crtc_commit, | ||
| 1349 | }; | ||
| 1350 | |||
| 1351 | static const struct drm_crtc_funcs intel_crtc_funcs = { | ||
| 1352 | .cursor_set = intel_crtc_cursor_set, | ||
| 1353 | .cursor_move = intel_crtc_cursor_move, | ||
| 1354 | .gamma_set = intel_crtc_gamma_set, | ||
| 1355 | .set_config = drm_crtc_helper_set_config, | ||
| 1356 | .destroy = intel_crtc_destroy, | ||
| 1357 | }; | ||
| 1358 | |||
| 1359 | |||
| 1360 | static void intel_crtc_init(struct drm_device *dev, int pipe) | ||
| 1361 | { | ||
| 1362 | struct intel_crtc *intel_crtc; | ||
| 1363 | int i; | ||
| 1364 | |||
| 1365 | intel_crtc = kzalloc(sizeof(struct intel_crtc) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); | ||
| 1366 | if (intel_crtc == NULL) | ||
| 1367 | return; | ||
| 1368 | |||
| 1369 | drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs); | ||
| 1370 | |||
| 1371 | drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256); | ||
| 1372 | intel_crtc->pipe = pipe; | ||
| 1373 | for (i = 0; i < 256; i++) { | ||
| 1374 | intel_crtc->lut_r[i] = i; | ||
| 1375 | intel_crtc->lut_g[i] = i; | ||
| 1376 | intel_crtc->lut_b[i] = i; | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | intel_crtc->cursor_addr = 0; | ||
| 1380 | intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF; | ||
| 1381 | drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); | ||
| 1382 | |||
| 1383 | intel_crtc->mode_set.crtc = &intel_crtc->base; | ||
| 1384 | intel_crtc->mode_set.connectors = (struct drm_connector **)(intel_crtc + 1); | ||
| 1385 | intel_crtc->mode_set.num_connectors = 0; | ||
| 1386 | |||
| 1387 | if (i915_fbpercrtc) { | ||
| 1388 | |||
| 1389 | |||
| 1390 | |||
| 1391 | } | ||
| 1392 | } | ||
| 1393 | |||
| 1394 | struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) | ||
| 1395 | { | ||
| 1396 | struct drm_crtc *crtc = NULL; | ||
| 1397 | |||
| 1398 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
| 1399 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 1400 | if (intel_crtc->pipe == pipe) | ||
| 1401 | break; | ||
| 1402 | } | ||
| 1403 | return crtc; | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | static int intel_connector_clones(struct drm_device *dev, int type_mask) | ||
| 1407 | { | ||
| 1408 | int index_mask = 0; | ||
| 1409 | struct drm_connector *connector; | ||
| 1410 | int entry = 0; | ||
| 1411 | |||
| 1412 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 1413 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 1414 | if (type_mask & (1 << intel_output->type)) | ||
| 1415 | index_mask |= (1 << entry); | ||
| 1416 | entry++; | ||
| 1417 | } | ||
| 1418 | return index_mask; | ||
| 1419 | } | ||
| 1420 | |||
| 1421 | |||
| 1422 | static void intel_setup_outputs(struct drm_device *dev) | ||
| 1423 | { | ||
| 1424 | struct drm_connector *connector; | ||
| 1425 | |||
| 1426 | intel_crt_init(dev); | ||
| 1427 | |||
| 1428 | /* Set up integrated LVDS */ | ||
| 1429 | if (IS_MOBILE(dev) && !IS_I830(dev)) | ||
| 1430 | intel_lvds_init(dev); | ||
| 1431 | |||
| 1432 | if (IS_I9XX(dev)) { | ||
| 1433 | intel_sdvo_init(dev, SDVOB); | ||
| 1434 | intel_sdvo_init(dev, SDVOC); | ||
| 1435 | } else | ||
| 1436 | intel_dvo_init(dev); | ||
| 1437 | |||
| 1438 | if (IS_I9XX(dev) && !IS_I915G(dev)) | ||
| 1439 | intel_tv_init(dev); | ||
| 1440 | |||
| 1441 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 1442 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 1443 | struct drm_encoder *encoder = &intel_output->enc; | ||
| 1444 | int crtc_mask = 0, clone_mask = 0; | ||
| 1445 | |||
| 1446 | /* valid crtcs */ | ||
| 1447 | switch(intel_output->type) { | ||
| 1448 | case INTEL_OUTPUT_DVO: | ||
| 1449 | case INTEL_OUTPUT_SDVO: | ||
| 1450 | crtc_mask = ((1 << 0)| | ||
| 1451 | (1 << 1)); | ||
| 1452 | clone_mask = ((1 << INTEL_OUTPUT_ANALOG) | | ||
| 1453 | (1 << INTEL_OUTPUT_DVO) | | ||
| 1454 | (1 << INTEL_OUTPUT_SDVO)); | ||
| 1455 | break; | ||
| 1456 | case INTEL_OUTPUT_ANALOG: | ||
| 1457 | crtc_mask = ((1 << 0)| | ||
| 1458 | (1 << 1)); | ||
| 1459 | clone_mask = ((1 << INTEL_OUTPUT_ANALOG) | | ||
| 1460 | (1 << INTEL_OUTPUT_DVO) | | ||
| 1461 | (1 << INTEL_OUTPUT_SDVO)); | ||
| 1462 | break; | ||
| 1463 | case INTEL_OUTPUT_LVDS: | ||
| 1464 | crtc_mask = (1 << 1); | ||
| 1465 | clone_mask = (1 << INTEL_OUTPUT_LVDS); | ||
| 1466 | break; | ||
| 1467 | case INTEL_OUTPUT_TVOUT: | ||
| 1468 | crtc_mask = ((1 << 0) | | ||
| 1469 | (1 << 1)); | ||
| 1470 | clone_mask = (1 << INTEL_OUTPUT_TVOUT); | ||
| 1471 | break; | ||
| 1472 | } | ||
| 1473 | encoder->possible_crtcs = crtc_mask; | ||
| 1474 | encoder->possible_clones = intel_connector_clones(dev, clone_mask); | ||
| 1475 | } | ||
| 1476 | } | ||
| 1477 | |||
| 1478 | static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) | ||
| 1479 | { | ||
| 1480 | struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); | ||
| 1481 | struct drm_device *dev = fb->dev; | ||
| 1482 | |||
| 1483 | if (fb->fbdev) | ||
| 1484 | intelfb_remove(dev, fb); | ||
| 1485 | |||
| 1486 | drm_framebuffer_cleanup(fb); | ||
| 1487 | mutex_lock(&dev->struct_mutex); | ||
| 1488 | drm_gem_object_unreference(intel_fb->obj); | ||
| 1489 | mutex_unlock(&dev->struct_mutex); | ||
| 1490 | |||
| 1491 | kfree(intel_fb); | ||
| 1492 | } | ||
| 1493 | |||
| 1494 | static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, | ||
| 1495 | struct drm_file *file_priv, | ||
| 1496 | unsigned int *handle) | ||
| 1497 | { | ||
| 1498 | struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); | ||
| 1499 | struct drm_gem_object *object = intel_fb->obj; | ||
| 1500 | |||
| 1501 | return drm_gem_handle_create(file_priv, object, handle); | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | static const struct drm_framebuffer_funcs intel_fb_funcs = { | ||
| 1505 | .destroy = intel_user_framebuffer_destroy, | ||
| 1506 | .create_handle = intel_user_framebuffer_create_handle, | ||
| 1507 | }; | ||
| 1508 | |||
| 1509 | int intel_framebuffer_create(struct drm_device *dev, | ||
| 1510 | struct drm_mode_fb_cmd *mode_cmd, | ||
| 1511 | struct drm_framebuffer **fb, | ||
| 1512 | struct drm_gem_object *obj) | ||
| 1513 | { | ||
| 1514 | struct intel_framebuffer *intel_fb; | ||
| 1515 | int ret; | ||
| 1516 | |||
| 1517 | intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); | ||
| 1518 | if (!intel_fb) | ||
| 1519 | return -ENOMEM; | ||
| 1520 | |||
| 1521 | ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); | ||
| 1522 | if (ret) { | ||
| 1523 | DRM_ERROR("framebuffer init failed %d\n", ret); | ||
| 1524 | return ret; | ||
| 1525 | } | ||
| 1526 | |||
| 1527 | drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); | ||
| 1528 | |||
| 1529 | intel_fb->obj = obj; | ||
| 1530 | |||
| 1531 | *fb = &intel_fb->base; | ||
| 1532 | |||
| 1533 | return 0; | ||
| 1534 | } | ||
| 1535 | |||
| 1536 | |||
| 1537 | static struct drm_framebuffer * | ||
| 1538 | intel_user_framebuffer_create(struct drm_device *dev, | ||
| 1539 | struct drm_file *filp, | ||
| 1540 | struct drm_mode_fb_cmd *mode_cmd) | ||
| 1541 | { | ||
| 1542 | struct drm_gem_object *obj; | ||
| 1543 | struct drm_framebuffer *fb; | ||
| 1544 | int ret; | ||
| 1545 | |||
| 1546 | obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle); | ||
| 1547 | if (!obj) | ||
| 1548 | return NULL; | ||
| 1549 | |||
| 1550 | ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj); | ||
| 1551 | if (ret) { | ||
| 1552 | drm_gem_object_unreference(obj); | ||
| 1553 | return NULL; | ||
| 1554 | } | ||
| 1555 | |||
| 1556 | return fb; | ||
| 1557 | } | ||
| 1558 | |||
| 1559 | static const struct drm_mode_config_funcs intel_mode_funcs = { | ||
| 1560 | .fb_create = intel_user_framebuffer_create, | ||
| 1561 | .fb_changed = intelfb_probe, | ||
| 1562 | }; | ||
| 1563 | |||
| 1564 | void intel_modeset_init(struct drm_device *dev) | ||
| 1565 | { | ||
| 1566 | int num_pipe; | ||
| 1567 | int i; | ||
| 1568 | |||
| 1569 | drm_mode_config_init(dev); | ||
| 1570 | |||
| 1571 | dev->mode_config.min_width = 0; | ||
| 1572 | dev->mode_config.min_height = 0; | ||
| 1573 | |||
| 1574 | dev->mode_config.funcs = (void *)&intel_mode_funcs; | ||
| 1575 | |||
| 1576 | if (IS_I965G(dev)) { | ||
| 1577 | dev->mode_config.max_width = 8192; | ||
| 1578 | dev->mode_config.max_height = 8192; | ||
| 1579 | } else { | ||
| 1580 | dev->mode_config.max_width = 2048; | ||
| 1581 | dev->mode_config.max_height = 2048; | ||
| 1582 | } | ||
| 1583 | |||
| 1584 | /* set memory base */ | ||
| 1585 | if (IS_I9XX(dev)) | ||
| 1586 | dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2); | ||
| 1587 | else | ||
| 1588 | dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0); | ||
| 1589 | |||
| 1590 | if (IS_MOBILE(dev) || IS_I9XX(dev)) | ||
| 1591 | num_pipe = 2; | ||
| 1592 | else | ||
| 1593 | num_pipe = 1; | ||
| 1594 | DRM_DEBUG("%d display pipe%s available.\n", | ||
| 1595 | num_pipe, num_pipe > 1 ? "s" : ""); | ||
| 1596 | |||
| 1597 | for (i = 0; i < num_pipe; i++) { | ||
| 1598 | intel_crtc_init(dev, i); | ||
| 1599 | } | ||
| 1600 | |||
| 1601 | intel_setup_outputs(dev); | ||
| 1602 | } | ||
| 1603 | |||
| 1604 | void intel_modeset_cleanup(struct drm_device *dev) | ||
| 1605 | { | ||
| 1606 | drm_mode_config_cleanup(dev); | ||
| 1607 | } | ||
| 1608 | |||
| 1609 | |||
| 1610 | /* current intel driver doesn't take advantage of encoders | ||
| 1611 | always give back the encoder for the connector | ||
| 1612 | */ | ||
| 1613 | struct drm_encoder *intel_best_encoder(struct drm_connector *connector) | ||
| 1614 | { | ||
| 1615 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 1616 | |||
| 1617 | return &intel_output->enc; | ||
| 1618 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h new file mode 100644 index 000000000000..407edd5bf582 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
| @@ -0,0 +1,146 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2006 Dave Airlie <airlied@linux.ie> | ||
| 3 | * Copyright (c) 2007-2008 Intel Corporation | ||
| 4 | * Jesse Barnes <jesse.barnes@intel.com> | ||
| 5 | * | ||
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 7 | * copy of this software and associated documentation files (the "Software"), | ||
| 8 | * to deal in the Software without restriction, including without limitation | ||
| 9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 11 | * Software is furnished to do so, subject to the following conditions: | ||
| 12 | * | ||
| 13 | * The above copyright notice and this permission notice (including the next | ||
| 14 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 15 | * Software. | ||
| 16 | * | ||
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
| 23 | * IN THE SOFTWARE. | ||
| 24 | */ | ||
| 25 | #ifndef __INTEL_DRV_H__ | ||
| 26 | #define __INTEL_DRV_H__ | ||
| 27 | |||
| 28 | #include <linux/i2c.h> | ||
| 29 | #include <linux/i2c-id.h> | ||
| 30 | #include <linux/i2c-algo-bit.h> | ||
| 31 | #include "drm_crtc.h" | ||
| 32 | |||
| 33 | #include "drm_crtc_helper.h" | ||
| 34 | /* | ||
| 35 | * Display related stuff | ||
| 36 | */ | ||
| 37 | |||
| 38 | /* store information about an Ixxx DVO */ | ||
| 39 | /* The i830->i865 use multiple DVOs with multiple i2cs */ | ||
| 40 | /* the i915, i945 have a single sDVO i2c bus - which is different */ | ||
| 41 | #define MAX_OUTPUTS 6 | ||
| 42 | /* maximum connectors per crtcs in the mode set */ | ||
| 43 | #define INTELFB_CONN_LIMIT 4 | ||
| 44 | |||
| 45 | #define INTEL_I2C_BUS_DVO 1 | ||
| 46 | #define INTEL_I2C_BUS_SDVO 2 | ||
| 47 | |||
| 48 | /* these are outputs from the chip - integrated only | ||
| 49 | external chips are via DVO or SDVO output */ | ||
| 50 | #define INTEL_OUTPUT_UNUSED 0 | ||
| 51 | #define INTEL_OUTPUT_ANALOG 1 | ||
| 52 | #define INTEL_OUTPUT_DVO 2 | ||
| 53 | #define INTEL_OUTPUT_SDVO 3 | ||
| 54 | #define INTEL_OUTPUT_LVDS 4 | ||
| 55 | #define INTEL_OUTPUT_TVOUT 5 | ||
| 56 | |||
| 57 | #define INTEL_DVO_CHIP_NONE 0 | ||
| 58 | #define INTEL_DVO_CHIP_LVDS 1 | ||
| 59 | #define INTEL_DVO_CHIP_TMDS 2 | ||
| 60 | #define INTEL_DVO_CHIP_TVOUT 4 | ||
| 61 | |||
| 62 | struct intel_i2c_chan { | ||
| 63 | struct drm_device *drm_dev; /* for getting at dev. private (mmio etc.) */ | ||
| 64 | u32 reg; /* GPIO reg */ | ||
| 65 | struct i2c_adapter adapter; | ||
| 66 | struct i2c_algo_bit_data algo; | ||
| 67 | u8 slave_addr; | ||
| 68 | }; | ||
| 69 | |||
| 70 | struct intel_framebuffer { | ||
| 71 | struct drm_framebuffer base; | ||
| 72 | struct drm_gem_object *obj; | ||
| 73 | }; | ||
| 74 | |||
| 75 | |||
| 76 | struct intel_output { | ||
| 77 | struct drm_connector base; | ||
| 78 | |||
| 79 | struct drm_encoder enc; | ||
| 80 | int type; | ||
| 81 | struct intel_i2c_chan *i2c_bus; /* for control functions */ | ||
| 82 | struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */ | ||
| 83 | bool load_detect_temp; | ||
| 84 | void *dev_priv; | ||
| 85 | }; | ||
| 86 | |||
| 87 | struct intel_crtc { | ||
| 88 | struct drm_crtc base; | ||
| 89 | int pipe; | ||
| 90 | int plane; | ||
| 91 | uint32_t cursor_addr; | ||
| 92 | u8 lut_r[256], lut_g[256], lut_b[256]; | ||
| 93 | int dpms_mode; | ||
| 94 | struct intel_framebuffer *fbdev_fb; | ||
| 95 | /* a mode_set for fbdev users on this crtc */ | ||
| 96 | struct drm_mode_set mode_set; | ||
| 97 | }; | ||
| 98 | |||
| 99 | #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) | ||
| 100 | #define to_intel_output(x) container_of(x, struct intel_output, base) | ||
| 101 | #define enc_to_intel_output(x) container_of(x, struct intel_output, enc) | ||
| 102 | #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) | ||
| 103 | |||
| 104 | struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, | ||
| 105 | const char *name); | ||
| 106 | void intel_i2c_destroy(struct intel_i2c_chan *chan); | ||
| 107 | int intel_ddc_get_modes(struct intel_output *intel_output); | ||
| 108 | extern bool intel_ddc_probe(struct intel_output *intel_output); | ||
| 109 | |||
| 110 | extern void intel_crt_init(struct drm_device *dev); | ||
| 111 | extern void intel_sdvo_init(struct drm_device *dev, int output_device); | ||
| 112 | extern void intel_dvo_init(struct drm_device *dev); | ||
| 113 | extern void intel_tv_init(struct drm_device *dev); | ||
| 114 | extern void intel_lvds_init(struct drm_device *dev); | ||
| 115 | |||
| 116 | extern void intel_crtc_load_lut(struct drm_crtc *crtc); | ||
| 117 | extern void intel_encoder_prepare (struct drm_encoder *encoder); | ||
| 118 | extern void intel_encoder_commit (struct drm_encoder *encoder); | ||
| 119 | |||
| 120 | extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector); | ||
| 121 | |||
| 122 | extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, | ||
| 123 | struct drm_crtc *crtc); | ||
| 124 | extern void intel_wait_for_vblank(struct drm_device *dev); | ||
| 125 | extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); | ||
| 126 | extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, | ||
| 127 | struct drm_display_mode *mode, | ||
| 128 | int *dpms_mode); | ||
| 129 | extern void intel_release_load_detect_pipe(struct intel_output *intel_output, | ||
| 130 | int dpms_mode); | ||
| 131 | |||
| 132 | extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB); | ||
| 133 | extern int intel_sdvo_supports_hotplug(struct drm_connector *connector); | ||
| 134 | extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable); | ||
| 135 | extern int intelfb_probe(struct drm_device *dev); | ||
| 136 | extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); | ||
| 137 | extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); | ||
| 138 | extern void intelfb_restore(void); | ||
| 139 | extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, | ||
| 140 | u16 blue, int regno); | ||
| 141 | |||
| 142 | extern int intel_framebuffer_create(struct drm_device *dev, | ||
| 143 | struct drm_mode_fb_cmd *mode_cmd, | ||
| 144 | struct drm_framebuffer **fb, | ||
| 145 | struct drm_gem_object *obj); | ||
| 146 | #endif /* __INTEL_DRV_H__ */ | ||
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c new file mode 100644 index 000000000000..8b8d6e65cd3f --- /dev/null +++ b/drivers/gpu/drm/i915/intel_dvo.c | |||
| @@ -0,0 +1,495 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2006 Dave Airlie <airlied@linux.ie> | ||
| 3 | * Copyright © 2006-2007 Intel Corporation | ||
| 4 | * | ||
| 5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 6 | * copy of this software and associated documentation files (the "Software"), | ||
| 7 | * to deal in the Software without restriction, including without limitation | ||
| 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 9 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 10 | * Software is furnished to do so, subject to the following conditions: | ||
| 11 | * | ||
| 12 | * The above copyright notice and this permission notice (including the next | ||
| 13 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 14 | * Software. | ||
| 15 | * | ||
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 22 | * DEALINGS IN THE SOFTWARE. | ||
| 23 | * | ||
| 24 | * Authors: | ||
| 25 | * Eric Anholt <eric@anholt.net> | ||
| 26 | */ | ||
| 27 | #include <linux/i2c.h> | ||
| 28 | #include "drmP.h" | ||
| 29 | #include "drm.h" | ||
| 30 | #include "drm_crtc.h" | ||
| 31 | #include "intel_drv.h" | ||
| 32 | #include "i915_drm.h" | ||
| 33 | #include "i915_drv.h" | ||
| 34 | #include "dvo.h" | ||
| 35 | |||
| 36 | #define SIL164_ADDR 0x38 | ||
| 37 | #define CH7xxx_ADDR 0x76 | ||
| 38 | #define TFP410_ADDR 0x38 | ||
| 39 | |||
| 40 | static struct intel_dvo_device intel_dvo_devices[] = { | ||
| 41 | { | ||
| 42 | .type = INTEL_DVO_CHIP_TMDS, | ||
| 43 | .name = "sil164", | ||
| 44 | .dvo_reg = DVOC, | ||
| 45 | .slave_addr = SIL164_ADDR, | ||
| 46 | .dev_ops = &sil164_ops, | ||
| 47 | }, | ||
| 48 | { | ||
| 49 | .type = INTEL_DVO_CHIP_TMDS, | ||
| 50 | .name = "ch7xxx", | ||
| 51 | .dvo_reg = DVOC, | ||
| 52 | .slave_addr = CH7xxx_ADDR, | ||
| 53 | .dev_ops = &ch7xxx_ops, | ||
| 54 | }, | ||
| 55 | { | ||
| 56 | .type = INTEL_DVO_CHIP_LVDS, | ||
| 57 | .name = "ivch", | ||
| 58 | .dvo_reg = DVOA, | ||
| 59 | .slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */ | ||
| 60 | .dev_ops = &ivch_ops, | ||
| 61 | }, | ||
| 62 | { | ||
| 63 | .type = INTEL_DVO_CHIP_TMDS, | ||
| 64 | .name = "tfp410", | ||
| 65 | .dvo_reg = DVOC, | ||
| 66 | .slave_addr = TFP410_ADDR, | ||
| 67 | .dev_ops = &tfp410_ops, | ||
| 68 | }, | ||
| 69 | { | ||
| 70 | .type = INTEL_DVO_CHIP_LVDS, | ||
| 71 | .name = "ch7017", | ||
| 72 | .dvo_reg = DVOC, | ||
| 73 | .slave_addr = 0x75, | ||
| 74 | .gpio = GPIOE, | ||
| 75 | .dev_ops = &ch7017_ops, | ||
| 76 | } | ||
| 77 | }; | ||
| 78 | |||
| 79 | static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) | ||
| 80 | { | ||
| 81 | struct drm_i915_private *dev_priv = encoder->dev->dev_private; | ||
| 82 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
| 83 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
| 84 | u32 dvo_reg = dvo->dvo_reg; | ||
| 85 | u32 temp = I915_READ(dvo_reg); | ||
| 86 | |||
| 87 | if (mode == DRM_MODE_DPMS_ON) { | ||
| 88 | I915_WRITE(dvo_reg, temp | DVO_ENABLE); | ||
| 89 | I915_READ(dvo_reg); | ||
| 90 | dvo->dev_ops->dpms(dvo, mode); | ||
| 91 | } else { | ||
| 92 | dvo->dev_ops->dpms(dvo, mode); | ||
| 93 | I915_WRITE(dvo_reg, temp & ~DVO_ENABLE); | ||
| 94 | I915_READ(dvo_reg); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | static void intel_dvo_save(struct drm_connector *connector) | ||
| 99 | { | ||
| 100 | struct drm_i915_private *dev_priv = connector->dev->dev_private; | ||
| 101 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 102 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
| 103 | |||
| 104 | /* Each output should probably just save the registers it touches, | ||
| 105 | * but for now, use more overkill. | ||
| 106 | */ | ||
| 107 | dev_priv->saveDVOA = I915_READ(DVOA); | ||
| 108 | dev_priv->saveDVOB = I915_READ(DVOB); | ||
| 109 | dev_priv->saveDVOC = I915_READ(DVOC); | ||
| 110 | |||
| 111 | dvo->dev_ops->save(dvo); | ||
| 112 | } | ||
| 113 | |||
| 114 | static void intel_dvo_restore(struct drm_connector *connector) | ||
| 115 | { | ||
| 116 | struct drm_i915_private *dev_priv = connector->dev->dev_private; | ||
| 117 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 118 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
| 119 | |||
| 120 | dvo->dev_ops->restore(dvo); | ||
| 121 | |||
| 122 | I915_WRITE(DVOA, dev_priv->saveDVOA); | ||
| 123 | I915_WRITE(DVOB, dev_priv->saveDVOB); | ||
| 124 | I915_WRITE(DVOC, dev_priv->saveDVOC); | ||
| 125 | } | ||
| 126 | |||
| 127 | static int intel_dvo_mode_valid(struct drm_connector *connector, | ||
| 128 | struct drm_display_mode *mode) | ||
| 129 | { | ||
| 130 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 131 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
| 132 | |||
| 133 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
| 134 | return MODE_NO_DBLESCAN; | ||
| 135 | |||
| 136 | /* XXX: Validate clock range */ | ||
| 137 | |||
| 138 | if (dvo->panel_fixed_mode) { | ||
| 139 | if (mode->hdisplay > dvo->panel_fixed_mode->hdisplay) | ||
| 140 | return MODE_PANEL; | ||
| 141 | if (mode->vdisplay > dvo->panel_fixed_mode->vdisplay) | ||
| 142 | return MODE_PANEL; | ||
| 143 | } | ||
| 144 | |||
| 145 | return dvo->dev_ops->mode_valid(dvo, mode); | ||
| 146 | } | ||
| 147 | |||
| 148 | static bool intel_dvo_mode_fixup(struct drm_encoder *encoder, | ||
| 149 | struct drm_display_mode *mode, | ||
| 150 | struct drm_display_mode *adjusted_mode) | ||
| 151 | { | ||
| 152 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
| 153 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
| 154 | |||
| 155 | /* If we have timings from the BIOS for the panel, put them in | ||
| 156 | * to the adjusted mode. The CRTC will be set up for this mode, | ||
| 157 | * with the panel scaling set up to source from the H/VDisplay | ||
| 158 | * of the original mode. | ||
| 159 | */ | ||
| 160 | if (dvo->panel_fixed_mode != NULL) { | ||
| 161 | #define C(x) adjusted_mode->x = dvo->panel_fixed_mode->x | ||
| 162 | C(hdisplay); | ||
| 163 | C(hsync_start); | ||
| 164 | C(hsync_end); | ||
| 165 | C(htotal); | ||
| 166 | C(vdisplay); | ||
| 167 | C(vsync_start); | ||
| 168 | C(vsync_end); | ||
| 169 | C(vtotal); | ||
| 170 | C(clock); | ||
| 171 | drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); | ||
| 172 | #undef C | ||
| 173 | } | ||
| 174 | |||
| 175 | if (dvo->dev_ops->mode_fixup) | ||
| 176 | return dvo->dev_ops->mode_fixup(dvo, mode, adjusted_mode); | ||
| 177 | |||
| 178 | return true; | ||
| 179 | } | ||
| 180 | |||
| 181 | static void intel_dvo_mode_set(struct drm_encoder *encoder, | ||
| 182 | struct drm_display_mode *mode, | ||
| 183 | struct drm_display_mode *adjusted_mode) | ||
| 184 | { | ||
| 185 | struct drm_device *dev = encoder->dev; | ||
| 186 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 187 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); | ||
| 188 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
| 189 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
| 190 | int pipe = intel_crtc->pipe; | ||
| 191 | u32 dvo_val; | ||
| 192 | u32 dvo_reg = dvo->dvo_reg, dvo_srcdim_reg; | ||
| 193 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | ||
| 194 | |||
| 195 | switch (dvo_reg) { | ||
| 196 | case DVOA: | ||
| 197 | default: | ||
| 198 | dvo_srcdim_reg = DVOA_SRCDIM; | ||
| 199 | break; | ||
| 200 | case DVOB: | ||
| 201 | dvo_srcdim_reg = DVOB_SRCDIM; | ||
| 202 | break; | ||
| 203 | case DVOC: | ||
| 204 | dvo_srcdim_reg = DVOC_SRCDIM; | ||
| 205 | break; | ||
| 206 | } | ||
| 207 | |||
| 208 | dvo->dev_ops->mode_set(dvo, mode, adjusted_mode); | ||
| 209 | |||
| 210 | /* Save the data order, since I don't know what it should be set to. */ | ||
| 211 | dvo_val = I915_READ(dvo_reg) & | ||
| 212 | (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG); | ||
| 213 | dvo_val |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE | | ||
| 214 | DVO_BLANK_ACTIVE_HIGH; | ||
| 215 | |||
| 216 | if (pipe == 1) | ||
| 217 | dvo_val |= DVO_PIPE_B_SELECT; | ||
| 218 | dvo_val |= DVO_PIPE_STALL; | ||
| 219 | if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
| 220 | dvo_val |= DVO_HSYNC_ACTIVE_HIGH; | ||
| 221 | if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
| 222 | dvo_val |= DVO_VSYNC_ACTIVE_HIGH; | ||
| 223 | |||
| 224 | I915_WRITE(dpll_reg, I915_READ(dpll_reg) | DPLL_DVO_HIGH_SPEED); | ||
| 225 | |||
| 226 | /*I915_WRITE(DVOB_SRCDIM, | ||
| 227 | (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | | ||
| 228 | (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/ | ||
| 229 | I915_WRITE(dvo_srcdim_reg, | ||
| 230 | (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | | ||
| 231 | (adjusted_mode->vdisplay << DVO_SRCDIM_VERTICAL_SHIFT)); | ||
| 232 | /*I915_WRITE(DVOB, dvo_val);*/ | ||
| 233 | I915_WRITE(dvo_reg, dvo_val); | ||
| 234 | } | ||
| 235 | |||
| 236 | /** | ||
| 237 | * Detect the output connection on our DVO device. | ||
| 238 | * | ||
| 239 | * Unimplemented. | ||
| 240 | */ | ||
| 241 | static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector) | ||
| 242 | { | ||
| 243 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 244 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
| 245 | |||
| 246 | return dvo->dev_ops->detect(dvo); | ||
| 247 | } | ||
| 248 | |||
| 249 | static int intel_dvo_get_modes(struct drm_connector *connector) | ||
| 250 | { | ||
| 251 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 252 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
| 253 | |||
| 254 | /* We should probably have an i2c driver get_modes function for those | ||
| 255 | * devices which will have a fixed set of modes determined by the chip | ||
| 256 | * (TV-out, for example), but for now with just TMDS and LVDS, | ||
| 257 | * that's not the case. | ||
| 258 | */ | ||
| 259 | intel_ddc_get_modes(intel_output); | ||
| 260 | if (!list_empty(&connector->probed_modes)) | ||
| 261 | return 1; | ||
| 262 | |||
| 263 | |||
| 264 | if (dvo->panel_fixed_mode != NULL) { | ||
| 265 | struct drm_display_mode *mode; | ||
| 266 | mode = drm_mode_duplicate(connector->dev, dvo->panel_fixed_mode); | ||
| 267 | if (mode) { | ||
| 268 | drm_mode_probed_add(connector, mode); | ||
| 269 | return 1; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | |||
| 275 | static void intel_dvo_destroy (struct drm_connector *connector) | ||
| 276 | { | ||
| 277 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 278 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
| 279 | |||
| 280 | if (dvo) { | ||
| 281 | if (dvo->dev_ops->destroy) | ||
| 282 | dvo->dev_ops->destroy(dvo); | ||
| 283 | if (dvo->panel_fixed_mode) | ||
| 284 | kfree(dvo->panel_fixed_mode); | ||
| 285 | /* no need, in i830_dvoices[] now */ | ||
| 286 | //kfree(dvo); | ||
| 287 | } | ||
| 288 | if (intel_output->i2c_bus) | ||
| 289 | intel_i2c_destroy(intel_output->i2c_bus); | ||
| 290 | if (intel_output->ddc_bus) | ||
| 291 | intel_i2c_destroy(intel_output->ddc_bus); | ||
| 292 | drm_sysfs_connector_remove(connector); | ||
| 293 | drm_connector_cleanup(connector); | ||
| 294 | kfree(intel_output); | ||
| 295 | } | ||
| 296 | |||
| 297 | #ifdef RANDR_GET_CRTC_INTERFACE | ||
| 298 | static struct drm_crtc *intel_dvo_get_crtc(struct drm_connector *connector) | ||
| 299 | { | ||
| 300 | struct drm_device *dev = connector->dev; | ||
| 301 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 302 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 303 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
| 304 | int pipe = !!(I915_READ(dvo->dvo_reg) & SDVO_PIPE_B_SELECT); | ||
| 305 | |||
| 306 | return intel_pipe_to_crtc(pScrn, pipe); | ||
| 307 | } | ||
| 308 | #endif | ||
| 309 | |||
| 310 | static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = { | ||
| 311 | .dpms = intel_dvo_dpms, | ||
| 312 | .mode_fixup = intel_dvo_mode_fixup, | ||
| 313 | .prepare = intel_encoder_prepare, | ||
| 314 | .mode_set = intel_dvo_mode_set, | ||
| 315 | .commit = intel_encoder_commit, | ||
| 316 | }; | ||
| 317 | |||
| 318 | static const struct drm_connector_funcs intel_dvo_connector_funcs = { | ||
| 319 | .save = intel_dvo_save, | ||
| 320 | .restore = intel_dvo_restore, | ||
| 321 | .detect = intel_dvo_detect, | ||
| 322 | .destroy = intel_dvo_destroy, | ||
| 323 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
| 324 | }; | ||
| 325 | |||
| 326 | static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = { | ||
| 327 | .mode_valid = intel_dvo_mode_valid, | ||
| 328 | .get_modes = intel_dvo_get_modes, | ||
| 329 | .best_encoder = intel_best_encoder, | ||
| 330 | }; | ||
| 331 | |||
| 332 | static void intel_dvo_enc_destroy(struct drm_encoder *encoder) | ||
| 333 | { | ||
| 334 | drm_encoder_cleanup(encoder); | ||
| 335 | } | ||
| 336 | |||
| 337 | static const struct drm_encoder_funcs intel_dvo_enc_funcs = { | ||
| 338 | .destroy = intel_dvo_enc_destroy, | ||
| 339 | }; | ||
| 340 | |||
| 341 | |||
| 342 | /** | ||
| 343 | * Attempts to get a fixed panel timing for LVDS (currently only the i830). | ||
| 344 | * | ||
| 345 | * Other chips with DVO LVDS will need to extend this to deal with the LVDS | ||
| 346 | * chip being on DVOB/C and having multiple pipes. | ||
| 347 | */ | ||
| 348 | static struct drm_display_mode * | ||
| 349 | intel_dvo_get_current_mode (struct drm_connector *connector) | ||
| 350 | { | ||
| 351 | struct drm_device *dev = connector->dev; | ||
| 352 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 353 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 354 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
| 355 | uint32_t dvo_reg = dvo->dvo_reg; | ||
| 356 | uint32_t dvo_val = I915_READ(dvo_reg); | ||
| 357 | struct drm_display_mode *mode = NULL; | ||
| 358 | |||
| 359 | /* If the DVO port is active, that'll be the LVDS, so we can pull out | ||
| 360 | * its timings to get how the BIOS set up the panel. | ||
| 361 | */ | ||
| 362 | if (dvo_val & DVO_ENABLE) { | ||
| 363 | struct drm_crtc *crtc; | ||
| 364 | int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0; | ||
| 365 | |||
| 366 | crtc = intel_get_crtc_from_pipe(dev, pipe); | ||
| 367 | if (crtc) { | ||
| 368 | mode = intel_crtc_mode_get(dev, crtc); | ||
| 369 | |||
| 370 | if (mode) { | ||
| 371 | mode->type |= DRM_MODE_TYPE_PREFERRED; | ||
| 372 | if (dvo_val & DVO_HSYNC_ACTIVE_HIGH) | ||
| 373 | mode->flags |= DRM_MODE_FLAG_PHSYNC; | ||
| 374 | if (dvo_val & DVO_VSYNC_ACTIVE_HIGH) | ||
| 375 | mode->flags |= DRM_MODE_FLAG_PVSYNC; | ||
| 376 | } | ||
| 377 | } | ||
| 378 | } | ||
| 379 | return mode; | ||
| 380 | } | ||
| 381 | |||
| 382 | void intel_dvo_init(struct drm_device *dev) | ||
| 383 | { | ||
| 384 | struct intel_output *intel_output; | ||
| 385 | struct intel_dvo_device *dvo; | ||
| 386 | struct intel_i2c_chan *i2cbus = NULL; | ||
| 387 | int ret = 0; | ||
| 388 | int i; | ||
| 389 | int gpio_inited = 0; | ||
| 390 | int encoder_type = DRM_MODE_ENCODER_NONE; | ||
| 391 | intel_output = kzalloc (sizeof(struct intel_output), GFP_KERNEL); | ||
| 392 | if (!intel_output) | ||
| 393 | return; | ||
| 394 | |||
| 395 | /* Set up the DDC bus */ | ||
| 396 | intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D"); | ||
| 397 | if (!intel_output->ddc_bus) | ||
| 398 | goto free_intel; | ||
| 399 | |||
| 400 | /* Now, try to find a controller */ | ||
| 401 | for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { | ||
| 402 | struct drm_connector *connector = &intel_output->base; | ||
| 403 | int gpio; | ||
| 404 | |||
| 405 | dvo = &intel_dvo_devices[i]; | ||
| 406 | |||
| 407 | /* Allow the I2C driver info to specify the GPIO to be used in | ||
| 408 | * special cases, but otherwise default to what's defined | ||
| 409 | * in the spec. | ||
| 410 | */ | ||
| 411 | if (dvo->gpio != 0) | ||
| 412 | gpio = dvo->gpio; | ||
| 413 | else if (dvo->type == INTEL_DVO_CHIP_LVDS) | ||
| 414 | gpio = GPIOB; | ||
| 415 | else | ||
| 416 | gpio = GPIOE; | ||
| 417 | |||
| 418 | /* Set up the I2C bus necessary for the chip we're probing. | ||
| 419 | * It appears that everything is on GPIOE except for panels | ||
| 420 | * on i830 laptops, which are on GPIOB (DVOA). | ||
| 421 | */ | ||
| 422 | if (gpio_inited != gpio) { | ||
| 423 | if (i2cbus != NULL) | ||
| 424 | intel_i2c_destroy(i2cbus); | ||
| 425 | if (!(i2cbus = intel_i2c_create(dev, gpio, | ||
| 426 | gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) { | ||
| 427 | continue; | ||
| 428 | } | ||
| 429 | gpio_inited = gpio; | ||
| 430 | } | ||
| 431 | |||
| 432 | if (dvo->dev_ops!= NULL) | ||
| 433 | ret = dvo->dev_ops->init(dvo, i2cbus); | ||
| 434 | else | ||
| 435 | ret = false; | ||
| 436 | |||
| 437 | if (!ret) | ||
| 438 | continue; | ||
| 439 | |||
| 440 | intel_output->type = INTEL_OUTPUT_DVO; | ||
| 441 | switch (dvo->type) { | ||
| 442 | case INTEL_DVO_CHIP_TMDS: | ||
| 443 | drm_connector_init(dev, connector, | ||
| 444 | &intel_dvo_connector_funcs, | ||
| 445 | DRM_MODE_CONNECTOR_DVII); | ||
| 446 | encoder_type = DRM_MODE_ENCODER_TMDS; | ||
| 447 | break; | ||
| 448 | case INTEL_DVO_CHIP_LVDS: | ||
| 449 | drm_connector_init(dev, connector, | ||
| 450 | &intel_dvo_connector_funcs, | ||
| 451 | DRM_MODE_CONNECTOR_LVDS); | ||
| 452 | encoder_type = DRM_MODE_ENCODER_LVDS; | ||
| 453 | break; | ||
| 454 | } | ||
| 455 | |||
| 456 | drm_connector_helper_add(connector, | ||
| 457 | &intel_dvo_connector_helper_funcs); | ||
| 458 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
| 459 | connector->interlace_allowed = false; | ||
| 460 | connector->doublescan_allowed = false; | ||
| 461 | |||
| 462 | intel_output->dev_priv = dvo; | ||
| 463 | intel_output->i2c_bus = i2cbus; | ||
| 464 | |||
| 465 | drm_encoder_init(dev, &intel_output->enc, | ||
| 466 | &intel_dvo_enc_funcs, encoder_type); | ||
| 467 | drm_encoder_helper_add(&intel_output->enc, | ||
| 468 | &intel_dvo_helper_funcs); | ||
| 469 | |||
| 470 | drm_mode_connector_attach_encoder(&intel_output->base, | ||
| 471 | &intel_output->enc); | ||
| 472 | if (dvo->type == INTEL_DVO_CHIP_LVDS) { | ||
| 473 | /* For our LVDS chipsets, we should hopefully be able | ||
| 474 | * to dig the fixed panel mode out of the BIOS data. | ||
| 475 | * However, it's in a different format from the BIOS | ||
| 476 | * data on chipsets with integrated LVDS (stored in AIM | ||
| 477 | * headers, likely), so for now, just get the current | ||
| 478 | * mode being output through DVO. | ||
| 479 | */ | ||
| 480 | dvo->panel_fixed_mode = | ||
| 481 | intel_dvo_get_current_mode(connector); | ||
| 482 | dvo->panel_wants_dither = true; | ||
| 483 | } | ||
| 484 | |||
| 485 | drm_sysfs_connector_add(connector); | ||
| 486 | return; | ||
| 487 | } | ||
| 488 | |||
| 489 | intel_i2c_destroy(intel_output->ddc_bus); | ||
| 490 | /* Didn't find a chip, so tear down. */ | ||
| 491 | if (i2cbus != NULL) | ||
| 492 | intel_i2c_destroy(i2cbus); | ||
| 493 | free_intel: | ||
| 494 | kfree(intel_output); | ||
| 495 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c new file mode 100644 index 000000000000..afd1217b8a02 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_fb.c | |||
| @@ -0,0 +1,925 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2007 David Airlie | ||
| 3 | * | ||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 5 | * copy of this software and associated documentation files (the "Software"), | ||
| 6 | * to deal in the Software without restriction, including without limitation | ||
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 9 | * Software is furnished to do so, subject to the following conditions: | ||
| 10 | * | ||
| 11 | * The above copyright notice and this permission notice (including the next | ||
| 12 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 13 | * Software. | ||
| 14 | * | ||
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 21 | * DEALINGS IN THE SOFTWARE. | ||
| 22 | * | ||
| 23 | * Authors: | ||
| 24 | * David Airlie | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/kernel.h> | ||
| 29 | #include <linux/errno.h> | ||
| 30 | #include <linux/string.h> | ||
| 31 | #include <linux/mm.h> | ||
| 32 | #include <linux/tty.h> | ||
| 33 | #include <linux/slab.h> | ||
| 34 | #include <linux/sysrq.h> | ||
| 35 | #include <linux/delay.h> | ||
| 36 | #include <linux/fb.h> | ||
| 37 | #include <linux/init.h> | ||
| 38 | |||
| 39 | #include "drmP.h" | ||
| 40 | #include "drm.h" | ||
| 41 | #include "drm_crtc.h" | ||
| 42 | #include "intel_drv.h" | ||
| 43 | #include "i915_drm.h" | ||
| 44 | #include "i915_drv.h" | ||
| 45 | |||
| 46 | struct intelfb_par { | ||
| 47 | struct drm_device *dev; | ||
| 48 | struct drm_display_mode *our_mode; | ||
| 49 | struct intel_framebuffer *intel_fb; | ||
| 50 | int crtc_count; | ||
| 51 | /* crtc currently bound to this */ | ||
| 52 | uint32_t crtc_ids[2]; | ||
| 53 | }; | ||
| 54 | |||
| 55 | static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
| 56 | unsigned blue, unsigned transp, | ||
| 57 | struct fb_info *info) | ||
| 58 | { | ||
| 59 | struct intelfb_par *par = info->par; | ||
| 60 | struct drm_device *dev = par->dev; | ||
| 61 | struct drm_crtc *crtc; | ||
| 62 | int i; | ||
| 63 | |||
| 64 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
| 65 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 66 | struct drm_mode_set *modeset = &intel_crtc->mode_set; | ||
| 67 | struct drm_framebuffer *fb = modeset->fb; | ||
| 68 | |||
| 69 | for (i = 0; i < par->crtc_count; i++) | ||
| 70 | if (crtc->base.id == par->crtc_ids[i]) | ||
| 71 | break; | ||
| 72 | |||
| 73 | if (i == par->crtc_count) | ||
| 74 | continue; | ||
| 75 | |||
| 76 | |||
| 77 | if (regno > 255) | ||
| 78 | return 1; | ||
| 79 | |||
| 80 | if (fb->depth == 8) { | ||
| 81 | intel_crtc_fb_gamma_set(crtc, red, green, blue, regno); | ||
| 82 | return 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | if (regno < 16) { | ||
| 86 | switch (fb->depth) { | ||
| 87 | case 15: | ||
| 88 | fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | | ||
| 89 | ((green & 0xf800) >> 6) | | ||
| 90 | ((blue & 0xf800) >> 11); | ||
| 91 | break; | ||
| 92 | case 16: | ||
| 93 | fb->pseudo_palette[regno] = (red & 0xf800) | | ||
| 94 | ((green & 0xfc00) >> 5) | | ||
| 95 | ((blue & 0xf800) >> 11); | ||
| 96 | break; | ||
| 97 | case 24: | ||
| 98 | case 32: | ||
| 99 | fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | | ||
| 100 | (green & 0xff00) | | ||
| 101 | ((blue & 0xff00) >> 8); | ||
| 102 | break; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | } | ||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | static int intelfb_check_var(struct fb_var_screeninfo *var, | ||
| 110 | struct fb_info *info) | ||
| 111 | { | ||
| 112 | struct intelfb_par *par = info->par; | ||
| 113 | struct intel_framebuffer *intel_fb = par->intel_fb; | ||
| 114 | struct drm_framebuffer *fb = &intel_fb->base; | ||
| 115 | int depth; | ||
| 116 | |||
| 117 | if (var->pixclock == -1 || !var->pixclock) | ||
| 118 | return -EINVAL; | ||
| 119 | |||
| 120 | /* Need to resize the fb object !!! */ | ||
| 121 | if (var->xres > fb->width || var->yres > fb->height) { | ||
| 122 | DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height); | ||
| 123 | DRM_ERROR("Need resizing code.\n"); | ||
| 124 | return -EINVAL; | ||
| 125 | } | ||
| 126 | |||
| 127 | switch (var->bits_per_pixel) { | ||
| 128 | case 16: | ||
| 129 | depth = (var->green.length == 6) ? 16 : 15; | ||
| 130 | break; | ||
| 131 | case 32: | ||
| 132 | depth = (var->transp.length > 0) ? 32 : 24; | ||
| 133 | break; | ||
| 134 | default: | ||
| 135 | depth = var->bits_per_pixel; | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | |||
| 139 | switch (depth) { | ||
| 140 | case 8: | ||
| 141 | var->red.offset = 0; | ||
| 142 | var->green.offset = 0; | ||
| 143 | var->blue.offset = 0; | ||
| 144 | var->red.length = 8; | ||
| 145 | var->green.length = 8; | ||
| 146 | var->blue.length = 8; | ||
| 147 | var->transp.length = 0; | ||
| 148 | var->transp.offset = 0; | ||
| 149 | break; | ||
| 150 | case 15: | ||
| 151 | var->red.offset = 10; | ||
| 152 | var->green.offset = 5; | ||
| 153 | var->blue.offset = 0; | ||
| 154 | var->red.length = 5; | ||
| 155 | var->green.length = 5; | ||
| 156 | var->blue.length = 5; | ||
| 157 | var->transp.length = 1; | ||
| 158 | var->transp.offset = 15; | ||
| 159 | break; | ||
| 160 | case 16: | ||
| 161 | var->red.offset = 11; | ||
| 162 | var->green.offset = 5; | ||
| 163 | var->blue.offset = 0; | ||
| 164 | var->red.length = 5; | ||
| 165 | var->green.length = 6; | ||
| 166 | var->blue.length = 5; | ||
| 167 | var->transp.length = 0; | ||
| 168 | var->transp.offset = 0; | ||
| 169 | break; | ||
| 170 | case 24: | ||
| 171 | var->red.offset = 16; | ||
| 172 | var->green.offset = 8; | ||
| 173 | var->blue.offset = 0; | ||
| 174 | var->red.length = 8; | ||
| 175 | var->green.length = 8; | ||
| 176 | var->blue.length = 8; | ||
| 177 | var->transp.length = 0; | ||
| 178 | var->transp.offset = 0; | ||
| 179 | break; | ||
| 180 | case 32: | ||
| 181 | var->red.offset = 16; | ||
| 182 | var->green.offset = 8; | ||
| 183 | var->blue.offset = 0; | ||
| 184 | var->red.length = 8; | ||
| 185 | var->green.length = 8; | ||
| 186 | var->blue.length = 8; | ||
| 187 | var->transp.length = 8; | ||
| 188 | var->transp.offset = 24; | ||
| 189 | break; | ||
| 190 | default: | ||
| 191 | return -EINVAL; | ||
| 192 | } | ||
| 193 | |||
| 194 | return 0; | ||
| 195 | } | ||
| 196 | |||
| 197 | /* this will let fbcon do the mode init */ | ||
| 198 | /* FIXME: take mode config lock? */ | ||
| 199 | static int intelfb_set_par(struct fb_info *info) | ||
| 200 | { | ||
| 201 | struct intelfb_par *par = info->par; | ||
| 202 | struct drm_device *dev = par->dev; | ||
| 203 | struct fb_var_screeninfo *var = &info->var; | ||
| 204 | int i; | ||
| 205 | |||
| 206 | DRM_DEBUG("%d %d\n", var->xres, var->pixclock); | ||
| 207 | |||
| 208 | if (var->pixclock != -1) { | ||
| 209 | |||
| 210 | DRM_ERROR("PIXEL CLCOK SET\n"); | ||
| 211 | return -EINVAL; | ||
| 212 | } else { | ||
| 213 | struct drm_crtc *crtc; | ||
| 214 | int ret; | ||
| 215 | |||
| 216 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
| 217 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 218 | |||
| 219 | for (i = 0; i < par->crtc_count; i++) | ||
| 220 | if (crtc->base.id == par->crtc_ids[i]) | ||
| 221 | break; | ||
| 222 | |||
| 223 | if (i == par->crtc_count) | ||
| 224 | continue; | ||
| 225 | |||
| 226 | if (crtc->fb == intel_crtc->mode_set.fb) { | ||
| 227 | mutex_lock(&dev->mode_config.mutex); | ||
| 228 | ret = crtc->funcs->set_config(&intel_crtc->mode_set); | ||
| 229 | mutex_unlock(&dev->mode_config.mutex); | ||
| 230 | if (ret) | ||
| 231 | return ret; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | return 0; | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | static int intelfb_pan_display(struct fb_var_screeninfo *var, | ||
| 239 | struct fb_info *info) | ||
| 240 | { | ||
| 241 | struct intelfb_par *par = info->par; | ||
| 242 | struct drm_device *dev = par->dev; | ||
| 243 | struct drm_mode_set *modeset; | ||
| 244 | struct drm_crtc *crtc; | ||
| 245 | struct intel_crtc *intel_crtc; | ||
| 246 | int ret = 0; | ||
| 247 | int i; | ||
| 248 | |||
| 249 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
| 250 | for (i = 0; i < par->crtc_count; i++) | ||
| 251 | if (crtc->base.id == par->crtc_ids[i]) | ||
| 252 | break; | ||
| 253 | |||
| 254 | if (i == par->crtc_count) | ||
| 255 | continue; | ||
| 256 | |||
| 257 | intel_crtc = to_intel_crtc(crtc); | ||
| 258 | modeset = &intel_crtc->mode_set; | ||
| 259 | |||
| 260 | modeset->x = var->xoffset; | ||
| 261 | modeset->y = var->yoffset; | ||
| 262 | |||
| 263 | if (modeset->num_connectors) { | ||
| 264 | mutex_lock(&dev->mode_config.mutex); | ||
| 265 | ret = crtc->funcs->set_config(modeset); | ||
| 266 | mutex_unlock(&dev->mode_config.mutex); | ||
| 267 | if (!ret) { | ||
| 268 | info->var.xoffset = var->xoffset; | ||
| 269 | info->var.yoffset = var->yoffset; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 274 | return ret; | ||
| 275 | } | ||
| 276 | |||
| 277 | static void intelfb_on(struct fb_info *info) | ||
| 278 | { | ||
| 279 | struct intelfb_par *par = info->par; | ||
| 280 | struct drm_device *dev = par->dev; | ||
| 281 | struct drm_crtc *crtc; | ||
| 282 | struct drm_encoder *encoder; | ||
| 283 | int i; | ||
| 284 | |||
| 285 | /* | ||
| 286 | * For each CRTC in this fb, find all associated encoders | ||
| 287 | * and turn them off, then turn off the CRTC. | ||
| 288 | */ | ||
| 289 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
| 290 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
| 291 | |||
| 292 | for (i = 0; i < par->crtc_count; i++) | ||
| 293 | if (crtc->base.id == par->crtc_ids[i]) | ||
| 294 | break; | ||
| 295 | |||
| 296 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
| 297 | |||
| 298 | /* Found a CRTC on this fb, now find encoders */ | ||
| 299 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
| 300 | if (encoder->crtc == crtc) { | ||
| 301 | struct drm_encoder_helper_funcs *encoder_funcs; | ||
| 302 | encoder_funcs = encoder->helper_private; | ||
| 303 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); | ||
| 304 | } | ||
| 305 | } | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | static void intelfb_off(struct fb_info *info, int dpms_mode) | ||
| 310 | { | ||
| 311 | struct intelfb_par *par = info->par; | ||
| 312 | struct drm_device *dev = par->dev; | ||
| 313 | struct drm_crtc *crtc; | ||
| 314 | struct drm_encoder *encoder; | ||
| 315 | int i; | ||
| 316 | |||
| 317 | /* | ||
| 318 | * For each CRTC in this fb, find all associated encoders | ||
| 319 | * and turn them off, then turn off the CRTC. | ||
| 320 | */ | ||
| 321 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
| 322 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
| 323 | |||
| 324 | for (i = 0; i < par->crtc_count; i++) | ||
| 325 | if (crtc->base.id == par->crtc_ids[i]) | ||
| 326 | break; | ||
| 327 | |||
| 328 | /* Found a CRTC on this fb, now find encoders */ | ||
| 329 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
| 330 | if (encoder->crtc == crtc) { | ||
| 331 | struct drm_encoder_helper_funcs *encoder_funcs; | ||
| 332 | encoder_funcs = encoder->helper_private; | ||
| 333 | encoder_funcs->dpms(encoder, dpms_mode); | ||
| 334 | } | ||
| 335 | } | ||
| 336 | if (dpms_mode == DRM_MODE_DPMS_OFF) | ||
| 337 | crtc_funcs->dpms(crtc, dpms_mode); | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | static int intelfb_blank(int blank, struct fb_info *info) | ||
| 342 | { | ||
| 343 | switch (blank) { | ||
| 344 | case FB_BLANK_UNBLANK: | ||
| 345 | intelfb_on(info); | ||
| 346 | break; | ||
| 347 | case FB_BLANK_NORMAL: | ||
| 348 | intelfb_off(info, DRM_MODE_DPMS_STANDBY); | ||
| 349 | break; | ||
| 350 | case FB_BLANK_HSYNC_SUSPEND: | ||
| 351 | intelfb_off(info, DRM_MODE_DPMS_STANDBY); | ||
| 352 | break; | ||
| 353 | case FB_BLANK_VSYNC_SUSPEND: | ||
| 354 | intelfb_off(info, DRM_MODE_DPMS_SUSPEND); | ||
| 355 | break; | ||
| 356 | case FB_BLANK_POWERDOWN: | ||
| 357 | intelfb_off(info, DRM_MODE_DPMS_OFF); | ||
| 358 | break; | ||
| 359 | } | ||
| 360 | return 0; | ||
| 361 | } | ||
| 362 | |||
| 363 | static struct fb_ops intelfb_ops = { | ||
| 364 | .owner = THIS_MODULE, | ||
| 365 | .fb_check_var = intelfb_check_var, | ||
| 366 | .fb_set_par = intelfb_set_par, | ||
| 367 | .fb_setcolreg = intelfb_setcolreg, | ||
| 368 | .fb_fillrect = cfb_fillrect, | ||
| 369 | .fb_copyarea = cfb_copyarea, | ||
| 370 | .fb_imageblit = cfb_imageblit, | ||
| 371 | .fb_pan_display = intelfb_pan_display, | ||
| 372 | .fb_blank = intelfb_blank, | ||
| 373 | }; | ||
| 374 | |||
| 375 | /** | ||
| 376 | * Curretly it is assumed that the old framebuffer is reused. | ||
| 377 | * | ||
| 378 | * LOCKING | ||
| 379 | * caller should hold the mode config lock. | ||
| 380 | * | ||
| 381 | */ | ||
| 382 | int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) | ||
| 383 | { | ||
| 384 | struct fb_info *info; | ||
| 385 | struct drm_framebuffer *fb; | ||
| 386 | struct drm_display_mode *mode = crtc->desired_mode; | ||
| 387 | |||
| 388 | fb = crtc->fb; | ||
| 389 | if (!fb) | ||
| 390 | return 1; | ||
| 391 | |||
| 392 | info = fb->fbdev; | ||
| 393 | if (!info) | ||
| 394 | return 1; | ||
| 395 | |||
| 396 | if (!mode) | ||
| 397 | return 1; | ||
| 398 | |||
| 399 | info->var.xres = mode->hdisplay; | ||
| 400 | info->var.right_margin = mode->hsync_start - mode->hdisplay; | ||
| 401 | info->var.hsync_len = mode->hsync_end - mode->hsync_start; | ||
| 402 | info->var.left_margin = mode->htotal - mode->hsync_end; | ||
| 403 | info->var.yres = mode->vdisplay; | ||
| 404 | info->var.lower_margin = mode->vsync_start - mode->vdisplay; | ||
| 405 | info->var.vsync_len = mode->vsync_end - mode->vsync_start; | ||
| 406 | info->var.upper_margin = mode->vtotal - mode->vsync_end; | ||
| 407 | info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100; | ||
| 408 | /* avoid overflow */ | ||
| 409 | info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; | ||
| 410 | |||
| 411 | return 0; | ||
| 412 | } | ||
| 413 | EXPORT_SYMBOL(intelfb_resize); | ||
| 414 | |||
| 415 | static struct drm_mode_set kernelfb_mode; | ||
| 416 | |||
| 417 | static int intelfb_panic(struct notifier_block *n, unsigned long ununsed, | ||
| 418 | void *panic_str) | ||
| 419 | { | ||
| 420 | DRM_ERROR("panic occurred, switching back to text console\n"); | ||
| 421 | |||
| 422 | intelfb_restore(); | ||
| 423 | return 0; | ||
| 424 | } | ||
| 425 | |||
| 426 | static struct notifier_block paniced = { | ||
| 427 | .notifier_call = intelfb_panic, | ||
| 428 | }; | ||
| 429 | |||
| 430 | static int intelfb_create(struct drm_device *dev, uint32_t fb_width, | ||
| 431 | uint32_t fb_height, uint32_t surface_width, | ||
| 432 | uint32_t surface_height, | ||
| 433 | struct intel_framebuffer **intel_fb_p) | ||
| 434 | { | ||
| 435 | struct fb_info *info; | ||
| 436 | struct intelfb_par *par; | ||
| 437 | struct drm_framebuffer *fb; | ||
| 438 | struct intel_framebuffer *intel_fb; | ||
| 439 | struct drm_mode_fb_cmd mode_cmd; | ||
| 440 | struct drm_gem_object *fbo = NULL; | ||
| 441 | struct drm_i915_gem_object *obj_priv; | ||
| 442 | struct device *device = &dev->pdev->dev; | ||
| 443 | int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1; | ||
| 444 | |||
| 445 | mode_cmd.width = surface_width; | ||
| 446 | mode_cmd.height = surface_height; | ||
| 447 | |||
| 448 | mode_cmd.bpp = 32; | ||
| 449 | mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64); | ||
| 450 | mode_cmd.depth = 24; | ||
| 451 | |||
| 452 | size = mode_cmd.pitch * mode_cmd.height; | ||
| 453 | size = ALIGN(size, PAGE_SIZE); | ||
| 454 | fbo = drm_gem_object_alloc(dev, size); | ||
| 455 | if (!fbo) { | ||
| 456 | printk(KERN_ERR "failed to allocate framebuffer\n"); | ||
| 457 | ret = -ENOMEM; | ||
| 458 | goto out; | ||
| 459 | } | ||
| 460 | obj_priv = fbo->driver_private; | ||
| 461 | |||
| 462 | mutex_lock(&dev->struct_mutex); | ||
| 463 | |||
| 464 | ret = i915_gem_object_pin(fbo, PAGE_SIZE); | ||
| 465 | if (ret) { | ||
| 466 | DRM_ERROR("failed to pin fb: %d\n", ret); | ||
| 467 | goto out_unref; | ||
| 468 | } | ||
| 469 | |||
| 470 | /* Flush everything out, we'll be doing GTT only from now on */ | ||
| 471 | i915_gem_object_set_to_gtt_domain(fbo, 1); | ||
| 472 | |||
| 473 | ret = intel_framebuffer_create(dev, &mode_cmd, &fb, fbo); | ||
| 474 | if (ret) { | ||
| 475 | DRM_ERROR("failed to allocate fb.\n"); | ||
| 476 | goto out_unref; | ||
| 477 | } | ||
| 478 | |||
| 479 | list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); | ||
| 480 | |||
| 481 | intel_fb = to_intel_framebuffer(fb); | ||
| 482 | *intel_fb_p = intel_fb; | ||
| 483 | |||
| 484 | info = framebuffer_alloc(sizeof(struct intelfb_par), device); | ||
| 485 | if (!info) { | ||
| 486 | ret = -ENOMEM; | ||
| 487 | goto out_unref; | ||
| 488 | } | ||
| 489 | |||
| 490 | par = info->par; | ||
| 491 | |||
| 492 | strcpy(info->fix.id, "inteldrmfb"); | ||
| 493 | info->fix.type = FB_TYPE_PACKED_PIXELS; | ||
| 494 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
| 495 | info->fix.type_aux = 0; | ||
| 496 | info->fix.xpanstep = 1; /* doing it in hw */ | ||
| 497 | info->fix.ypanstep = 1; /* doing it in hw */ | ||
| 498 | info->fix.ywrapstep = 0; | ||
| 499 | info->fix.accel = FB_ACCEL_I830; | ||
| 500 | info->fix.type_aux = 0; | ||
| 501 | |||
| 502 | info->flags = FBINFO_DEFAULT; | ||
| 503 | |||
| 504 | info->fbops = &intelfb_ops; | ||
| 505 | |||
| 506 | info->fix.line_length = fb->pitch; | ||
| 507 | info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset; | ||
| 508 | info->fix.smem_len = size; | ||
| 509 | |||
| 510 | info->flags = FBINFO_DEFAULT; | ||
| 511 | |||
| 512 | info->screen_base = ioremap_wc(dev->agp->base + obj_priv->gtt_offset, | ||
| 513 | size); | ||
| 514 | if (!info->screen_base) { | ||
| 515 | ret = -ENOSPC; | ||
| 516 | goto out_unref; | ||
| 517 | } | ||
| 518 | info->screen_size = size; | ||
| 519 | |||
| 520 | // memset(info->screen_base, 0, size); | ||
| 521 | |||
| 522 | info->pseudo_palette = fb->pseudo_palette; | ||
| 523 | info->var.xres_virtual = fb->width; | ||
| 524 | info->var.yres_virtual = fb->height; | ||
| 525 | info->var.bits_per_pixel = fb->bits_per_pixel; | ||
| 526 | info->var.xoffset = 0; | ||
| 527 | info->var.yoffset = 0; | ||
| 528 | info->var.activate = FB_ACTIVATE_NOW; | ||
| 529 | info->var.height = -1; | ||
| 530 | info->var.width = -1; | ||
| 531 | |||
| 532 | info->var.xres = fb_width; | ||
| 533 | info->var.yres = fb_height; | ||
| 534 | |||
| 535 | /* FIXME: we really shouldn't expose mmio space at all */ | ||
| 536 | info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar); | ||
| 537 | info->fix.mmio_len = pci_resource_len(dev->pdev, mmio_bar); | ||
| 538 | |||
| 539 | info->pixmap.size = 64*1024; | ||
| 540 | info->pixmap.buf_align = 8; | ||
| 541 | info->pixmap.access_align = 32; | ||
| 542 | info->pixmap.flags = FB_PIXMAP_SYSTEM; | ||
| 543 | info->pixmap.scan_align = 1; | ||
| 544 | |||
| 545 | switch(fb->depth) { | ||
| 546 | case 8: | ||
| 547 | info->var.red.offset = 0; | ||
| 548 | info->var.green.offset = 0; | ||
| 549 | info->var.blue.offset = 0; | ||
| 550 | info->var.red.length = 8; /* 8bit DAC */ | ||
| 551 | info->var.green.length = 8; | ||
| 552 | info->var.blue.length = 8; | ||
| 553 | info->var.transp.offset = 0; | ||
| 554 | info->var.transp.length = 0; | ||
| 555 | break; | ||
| 556 | case 15: | ||
| 557 | info->var.red.offset = 10; | ||
| 558 | info->var.green.offset = 5; | ||
| 559 | info->var.blue.offset = 0; | ||
| 560 | info->var.red.length = 5; | ||
| 561 | info->var.green.length = 5; | ||
| 562 | info->var.blue.length = 5; | ||
| 563 | info->var.transp.offset = 15; | ||
| 564 | info->var.transp.length = 1; | ||
| 565 | break; | ||
| 566 | case 16: | ||
| 567 | info->var.red.offset = 11; | ||
| 568 | info->var.green.offset = 5; | ||
| 569 | info->var.blue.offset = 0; | ||
| 570 | info->var.red.length = 5; | ||
| 571 | info->var.green.length = 6; | ||
| 572 | info->var.blue.length = 5; | ||
| 573 | info->var.transp.offset = 0; | ||
| 574 | break; | ||
| 575 | case 24: | ||
| 576 | info->var.red.offset = 16; | ||
| 577 | info->var.green.offset = 8; | ||
| 578 | info->var.blue.offset = 0; | ||
| 579 | info->var.red.length = 8; | ||
| 580 | info->var.green.length = 8; | ||
| 581 | info->var.blue.length = 8; | ||
| 582 | info->var.transp.offset = 0; | ||
| 583 | info->var.transp.length = 0; | ||
| 584 | break; | ||
| 585 | case 32: | ||
| 586 | info->var.red.offset = 16; | ||
| 587 | info->var.green.offset = 8; | ||
| 588 | info->var.blue.offset = 0; | ||
| 589 | info->var.red.length = 8; | ||
| 590 | info->var.green.length = 8; | ||
| 591 | info->var.blue.length = 8; | ||
| 592 | info->var.transp.offset = 24; | ||
| 593 | info->var.transp.length = 8; | ||
| 594 | break; | ||
| 595 | default: | ||
| 596 | break; | ||
| 597 | } | ||
| 598 | |||
| 599 | fb->fbdev = info; | ||
| 600 | |||
| 601 | par->intel_fb = intel_fb; | ||
| 602 | par->dev = dev; | ||
| 603 | |||
| 604 | /* To allow resizeing without swapping buffers */ | ||
| 605 | printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width, | ||
| 606 | intel_fb->base.height, obj_priv->gtt_offset, fbo); | ||
| 607 | |||
| 608 | mutex_unlock(&dev->struct_mutex); | ||
| 609 | return 0; | ||
| 610 | |||
| 611 | out_unref: | ||
| 612 | drm_gem_object_unreference(fbo); | ||
| 613 | mutex_unlock(&dev->struct_mutex); | ||
| 614 | out: | ||
| 615 | return ret; | ||
| 616 | } | ||
| 617 | |||
| 618 | static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc) | ||
| 619 | { | ||
| 620 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 621 | struct intel_framebuffer *intel_fb; | ||
| 622 | struct drm_framebuffer *fb; | ||
| 623 | struct drm_connector *connector; | ||
| 624 | struct fb_info *info; | ||
| 625 | struct intelfb_par *par; | ||
| 626 | struct drm_mode_set *modeset; | ||
| 627 | unsigned int width, height; | ||
| 628 | int new_fb = 0; | ||
| 629 | int ret, i, conn_count; | ||
| 630 | |||
| 631 | if (!drm_helper_crtc_in_use(crtc)) | ||
| 632 | return 0; | ||
| 633 | |||
| 634 | if (!crtc->desired_mode) | ||
| 635 | return 0; | ||
| 636 | |||
| 637 | width = crtc->desired_mode->hdisplay; | ||
| 638 | height = crtc->desired_mode->vdisplay; | ||
| 639 | |||
| 640 | /* is there an fb bound to this crtc already */ | ||
| 641 | if (!intel_crtc->mode_set.fb) { | ||
| 642 | ret = intelfb_create(dev, width, height, width, height, &intel_fb); | ||
| 643 | if (ret) | ||
| 644 | return -EINVAL; | ||
| 645 | new_fb = 1; | ||
| 646 | } else { | ||
| 647 | fb = intel_crtc->mode_set.fb; | ||
| 648 | intel_fb = to_intel_framebuffer(fb); | ||
| 649 | if ((intel_fb->base.width < width) || (intel_fb->base.height < height)) | ||
| 650 | return -EINVAL; | ||
| 651 | } | ||
| 652 | |||
| 653 | info = intel_fb->base.fbdev; | ||
| 654 | par = info->par; | ||
| 655 | |||
| 656 | modeset = &intel_crtc->mode_set; | ||
| 657 | modeset->fb = &intel_fb->base; | ||
| 658 | conn_count = 0; | ||
| 659 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 660 | if (connector->encoder) | ||
| 661 | if (connector->encoder->crtc == modeset->crtc) { | ||
| 662 | modeset->connectors[conn_count] = connector; | ||
| 663 | conn_count++; | ||
| 664 | if (conn_count > INTELFB_CONN_LIMIT) | ||
| 665 | BUG(); | ||
| 666 | } | ||
| 667 | } | ||
| 668 | |||
| 669 | for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) | ||
| 670 | modeset->connectors[i] = NULL; | ||
| 671 | |||
| 672 | par->crtc_ids[0] = crtc->base.id; | ||
| 673 | |||
| 674 | modeset->num_connectors = conn_count; | ||
| 675 | if (modeset->mode != modeset->crtc->desired_mode) | ||
| 676 | modeset->mode = modeset->crtc->desired_mode; | ||
| 677 | |||
| 678 | par->crtc_count = 1; | ||
| 679 | |||
| 680 | if (new_fb) { | ||
| 681 | info->var.pixclock = -1; | ||
| 682 | if (register_framebuffer(info) < 0) | ||
| 683 | return -EINVAL; | ||
| 684 | } else | ||
| 685 | intelfb_set_par(info); | ||
| 686 | |||
| 687 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, | ||
| 688 | info->fix.id); | ||
| 689 | |||
| 690 | /* Switch back to kernel console on panic */ | ||
| 691 | kernelfb_mode = *modeset; | ||
| 692 | atomic_notifier_chain_register(&panic_notifier_list, &paniced); | ||
| 693 | printk(KERN_INFO "registered panic notifier\n"); | ||
| 694 | |||
| 695 | return 0; | ||
| 696 | } | ||
| 697 | |||
| 698 | static int intelfb_multi_fb_probe(struct drm_device *dev) | ||
| 699 | { | ||
| 700 | |||
| 701 | struct drm_crtc *crtc; | ||
| 702 | int ret = 0; | ||
| 703 | |||
| 704 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
| 705 | ret = intelfb_multi_fb_probe_crtc(dev, crtc); | ||
| 706 | if (ret) | ||
| 707 | return ret; | ||
| 708 | } | ||
| 709 | return ret; | ||
| 710 | } | ||
| 711 | |||
| 712 | static int intelfb_single_fb_probe(struct drm_device *dev) | ||
| 713 | { | ||
| 714 | struct drm_crtc *crtc; | ||
| 715 | struct drm_connector *connector; | ||
| 716 | unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; | ||
| 717 | unsigned int surface_width = 0, surface_height = 0; | ||
| 718 | int new_fb = 0; | ||
| 719 | int crtc_count = 0; | ||
| 720 | int ret, i, conn_count = 0; | ||
| 721 | struct intel_framebuffer *intel_fb; | ||
| 722 | struct fb_info *info; | ||
| 723 | struct intelfb_par *par; | ||
| 724 | struct drm_mode_set *modeset = NULL; | ||
| 725 | |||
| 726 | DRM_DEBUG("\n"); | ||
| 727 | |||
| 728 | /* Get a count of crtcs now in use and new min/maxes width/heights */ | ||
| 729 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
| 730 | if (!drm_helper_crtc_in_use(crtc)) | ||
| 731 | continue; | ||
| 732 | |||
| 733 | crtc_count++; | ||
| 734 | if (!crtc->desired_mode) | ||
| 735 | continue; | ||
| 736 | |||
| 737 | /* Smallest mode determines console size... */ | ||
| 738 | if (crtc->desired_mode->hdisplay < fb_width) | ||
| 739 | fb_width = crtc->desired_mode->hdisplay; | ||
| 740 | |||
| 741 | if (crtc->desired_mode->vdisplay < fb_height) | ||
| 742 | fb_height = crtc->desired_mode->vdisplay; | ||
| 743 | |||
| 744 | /* ... but largest for memory allocation dimensions */ | ||
| 745 | if (crtc->desired_mode->hdisplay > surface_width) | ||
| 746 | surface_width = crtc->desired_mode->hdisplay; | ||
| 747 | |||
| 748 | if (crtc->desired_mode->vdisplay > surface_height) | ||
| 749 | surface_height = crtc->desired_mode->vdisplay; | ||
| 750 | } | ||
| 751 | |||
| 752 | if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { | ||
| 753 | /* hmm everyone went away - assume VGA cable just fell out | ||
| 754 | and will come back later. */ | ||
| 755 | DRM_DEBUG("no CRTCs available?\n"); | ||
| 756 | return 0; | ||
| 757 | } | ||
| 758 | |||
| 759 | //fail | ||
| 760 | /* Find the fb for our new config */ | ||
| 761 | if (list_empty(&dev->mode_config.fb_kernel_list)) { | ||
| 762 | DRM_DEBUG("creating new fb (console size %dx%d, " | ||
| 763 | "buffer size %dx%d)\n", fb_width, fb_height, | ||
| 764 | surface_width, surface_height); | ||
| 765 | ret = intelfb_create(dev, fb_width, fb_height, surface_width, | ||
| 766 | surface_height, &intel_fb); | ||
| 767 | if (ret) | ||
| 768 | return -EINVAL; | ||
| 769 | new_fb = 1; | ||
| 770 | } else { | ||
| 771 | struct drm_framebuffer *fb; | ||
| 772 | |||
| 773 | fb = list_first_entry(&dev->mode_config.fb_kernel_list, | ||
| 774 | struct drm_framebuffer, filp_head); | ||
| 775 | intel_fb = to_intel_framebuffer(fb); | ||
| 776 | |||
| 777 | /* if someone hotplugs something bigger than we have already | ||
| 778 | * allocated, we are pwned. As really we can't resize an | ||
| 779 | * fbdev that is in the wild currently due to fbdev not really | ||
| 780 | * being designed for the lower layers moving stuff around | ||
| 781 | * under it. | ||
| 782 | * - so in the grand style of things - punt. | ||
| 783 | */ | ||
| 784 | if ((fb->width < surface_width) || | ||
| 785 | (fb->height < surface_height)) { | ||
| 786 | DRM_ERROR("fb not large enough for console\n"); | ||
| 787 | return -EINVAL; | ||
| 788 | } | ||
| 789 | } | ||
| 790 | // fail | ||
| 791 | |||
| 792 | info = intel_fb->base.fbdev; | ||
| 793 | par = info->par; | ||
| 794 | |||
| 795 | crtc_count = 0; | ||
| 796 | /* | ||
| 797 | * For each CRTC, set up the connector list for the CRTC's mode | ||
| 798 | * set configuration. | ||
| 799 | */ | ||
| 800 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
| 801 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 802 | |||
| 803 | modeset = &intel_crtc->mode_set; | ||
| 804 | modeset->fb = &intel_fb->base; | ||
| 805 | conn_count = 0; | ||
| 806 | list_for_each_entry(connector, &dev->mode_config.connector_list, | ||
| 807 | head) { | ||
| 808 | if (!connector->encoder) | ||
| 809 | continue; | ||
| 810 | |||
| 811 | if(connector->encoder->crtc == modeset->crtc) { | ||
| 812 | modeset->connectors[conn_count++] = connector; | ||
| 813 | if (conn_count > INTELFB_CONN_LIMIT) | ||
| 814 | BUG(); | ||
| 815 | } | ||
| 816 | } | ||
| 817 | |||
| 818 | /* Zero out remaining connector pointers */ | ||
| 819 | for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) | ||
| 820 | modeset->connectors[i] = NULL; | ||
| 821 | |||
| 822 | par->crtc_ids[crtc_count++] = crtc->base.id; | ||
| 823 | |||
| 824 | modeset->num_connectors = conn_count; | ||
| 825 | if (modeset->mode != modeset->crtc->desired_mode) | ||
| 826 | modeset->mode = modeset->crtc->desired_mode; | ||
| 827 | } | ||
| 828 | par->crtc_count = crtc_count; | ||
| 829 | |||
| 830 | if (new_fb) { | ||
| 831 | info->var.pixclock = -1; | ||
| 832 | if (register_framebuffer(info) < 0) | ||
| 833 | return -EINVAL; | ||
| 834 | } else | ||
| 835 | intelfb_set_par(info); | ||
| 836 | |||
| 837 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, | ||
| 838 | info->fix.id); | ||
| 839 | |||
| 840 | /* Switch back to kernel console on panic */ | ||
| 841 | kernelfb_mode = *modeset; | ||
| 842 | atomic_notifier_chain_register(&panic_notifier_list, &paniced); | ||
| 843 | printk(KERN_INFO "registered panic notifier\n"); | ||
| 844 | |||
| 845 | return 0; | ||
| 846 | } | ||
| 847 | |||
| 848 | /** | ||
| 849 | * intelfb_restore - restore the framebuffer console (kernel) config | ||
| 850 | * | ||
| 851 | * Restore's the kernel's fbcon mode, used for lastclose & panic paths. | ||
| 852 | */ | ||
| 853 | void intelfb_restore(void) | ||
| 854 | { | ||
| 855 | drm_crtc_helper_set_config(&kernelfb_mode); | ||
| 856 | } | ||
| 857 | |||
| 858 | static void intelfb_sysrq(int dummy1, struct tty_struct *dummy3) | ||
| 859 | { | ||
| 860 | intelfb_restore(); | ||
| 861 | } | ||
| 862 | |||
| 863 | static struct sysrq_key_op sysrq_intelfb_restore_op = { | ||
| 864 | .handler = intelfb_sysrq, | ||
| 865 | .help_msg = "force fb", | ||
| 866 | .action_msg = "force restore of fb console", | ||
| 867 | }; | ||
| 868 | |||
| 869 | int intelfb_probe(struct drm_device *dev) | ||
| 870 | { | ||
| 871 | int ret; | ||
| 872 | |||
| 873 | DRM_DEBUG("\n"); | ||
| 874 | |||
| 875 | /* something has changed in the lower levels of hell - deal with it | ||
| 876 | here */ | ||
| 877 | |||
| 878 | /* two modes : a) 1 fb to rule all crtcs. | ||
| 879 | b) one fb per crtc. | ||
| 880 | two actions 1) new connected device | ||
| 881 | 2) device removed. | ||
| 882 | case a/1 : if the fb surface isn't big enough - resize the surface fb. | ||
| 883 | if the fb size isn't big enough - resize fb into surface. | ||
| 884 | if everything big enough configure the new crtc/etc. | ||
| 885 | case a/2 : undo the configuration | ||
| 886 | possibly resize down the fb to fit the new configuration. | ||
| 887 | case b/1 : see if it is on a new crtc - setup a new fb and add it. | ||
| 888 | case b/2 : teardown the new fb. | ||
| 889 | */ | ||
| 890 | |||
| 891 | /* mode a first */ | ||
| 892 | /* search for an fb */ | ||
| 893 | if (i915_fbpercrtc == 1) { | ||
| 894 | ret = intelfb_multi_fb_probe(dev); | ||
| 895 | } else { | ||
| 896 | ret = intelfb_single_fb_probe(dev); | ||
| 897 | } | ||
| 898 | |||
| 899 | register_sysrq_key('g', &sysrq_intelfb_restore_op); | ||
| 900 | |||
| 901 | return ret; | ||
| 902 | } | ||
| 903 | EXPORT_SYMBOL(intelfb_probe); | ||
| 904 | |||
| 905 | int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) | ||
| 906 | { | ||
| 907 | struct fb_info *info; | ||
| 908 | |||
| 909 | if (!fb) | ||
| 910 | return -EINVAL; | ||
| 911 | |||
| 912 | info = fb->fbdev; | ||
| 913 | |||
| 914 | if (info) { | ||
| 915 | unregister_framebuffer(info); | ||
| 916 | iounmap(info->screen_base); | ||
| 917 | framebuffer_release(info); | ||
| 918 | } | ||
| 919 | |||
| 920 | atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); | ||
| 921 | memset(&kernelfb_mode, 0, sizeof(struct drm_mode_set)); | ||
| 922 | return 0; | ||
| 923 | } | ||
| 924 | EXPORT_SYMBOL(intelfb_remove); | ||
| 925 | MODULE_LICENSE("GPL and additional rights"); | ||
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c new file mode 100644 index 000000000000..a5a2f5339e9e --- /dev/null +++ b/drivers/gpu/drm/i915/intel_i2c.c | |||
| @@ -0,0 +1,184 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2006 Dave Airlie <airlied@linux.ie> | ||
| 3 | * Copyright © 2006-2008 Intel Corporation | ||
| 4 | * Jesse Barnes <jesse.barnes@intel.com> | ||
| 5 | * | ||
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 7 | * copy of this software and associated documentation files (the "Software"), | ||
| 8 | * to deal in the Software without restriction, including without limitation | ||
| 9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 11 | * Software is furnished to do so, subject to the following conditions: | ||
| 12 | * | ||
| 13 | * The above copyright notice and this permission notice (including the next | ||
| 14 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 15 | * Software. | ||
| 16 | * | ||
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 23 | * DEALINGS IN THE SOFTWARE. | ||
| 24 | * | ||
| 25 | * Authors: | ||
| 26 | * Eric Anholt <eric@anholt.net> | ||
| 27 | */ | ||
| 28 | #include <linux/i2c.h> | ||
| 29 | #include <linux/i2c-id.h> | ||
| 30 | #include <linux/i2c-algo-bit.h> | ||
| 31 | #include "drmP.h" | ||
| 32 | #include "drm.h" | ||
| 33 | #include "intel_drv.h" | ||
| 34 | #include "i915_drm.h" | ||
| 35 | #include "i915_drv.h" | ||
| 36 | |||
| 37 | /* | ||
| 38 | * Intel GPIO access functions | ||
| 39 | */ | ||
| 40 | |||
| 41 | #define I2C_RISEFALL_TIME 20 | ||
| 42 | |||
| 43 | static int get_clock(void *data) | ||
| 44 | { | ||
| 45 | struct intel_i2c_chan *chan = data; | ||
| 46 | struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; | ||
| 47 | u32 val; | ||
| 48 | |||
| 49 | val = I915_READ(chan->reg); | ||
| 50 | return ((val & GPIO_CLOCK_VAL_IN) != 0); | ||
| 51 | } | ||
| 52 | |||
| 53 | static int get_data(void *data) | ||
| 54 | { | ||
| 55 | struct intel_i2c_chan *chan = data; | ||
| 56 | struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; | ||
| 57 | u32 val; | ||
| 58 | |||
| 59 | val = I915_READ(chan->reg); | ||
| 60 | return ((val & GPIO_DATA_VAL_IN) != 0); | ||
| 61 | } | ||
| 62 | |||
| 63 | static void set_clock(void *data, int state_high) | ||
| 64 | { | ||
| 65 | struct intel_i2c_chan *chan = data; | ||
| 66 | struct drm_device *dev = chan->drm_dev; | ||
| 67 | struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; | ||
| 68 | u32 reserved = 0, clock_bits; | ||
| 69 | |||
| 70 | /* On most chips, these bits must be preserved in software. */ | ||
| 71 | if (!IS_I830(dev) && !IS_845G(dev)) | ||
| 72 | reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | | ||
| 73 | GPIO_CLOCK_PULLUP_DISABLE); | ||
| 74 | |||
| 75 | if (state_high) | ||
| 76 | clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK; | ||
| 77 | else | ||
| 78 | clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | | ||
| 79 | GPIO_CLOCK_VAL_MASK; | ||
| 80 | I915_WRITE(chan->reg, reserved | clock_bits); | ||
| 81 | udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ | ||
| 82 | } | ||
| 83 | |||
| 84 | static void set_data(void *data, int state_high) | ||
| 85 | { | ||
| 86 | struct intel_i2c_chan *chan = data; | ||
| 87 | struct drm_device *dev = chan->drm_dev; | ||
| 88 | struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; | ||
| 89 | u32 reserved = 0, data_bits; | ||
| 90 | |||
| 91 | /* On most chips, these bits must be preserved in software. */ | ||
| 92 | if (!IS_I830(dev) && !IS_845G(dev)) | ||
| 93 | reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | | ||
| 94 | GPIO_CLOCK_PULLUP_DISABLE); | ||
| 95 | |||
| 96 | if (state_high) | ||
| 97 | data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK; | ||
| 98 | else | ||
| 99 | data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | | ||
| 100 | GPIO_DATA_VAL_MASK; | ||
| 101 | |||
| 102 | I915_WRITE(chan->reg, reserved | data_bits); | ||
| 103 | udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ | ||
| 104 | } | ||
| 105 | |||
| 106 | /** | ||
| 107 | * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg | ||
| 108 | * @dev: DRM device | ||
| 109 | * @output: driver specific output device | ||
| 110 | * @reg: GPIO reg to use | ||
| 111 | * @name: name for this bus | ||
| 112 | * | ||
| 113 | * Creates and registers a new i2c bus with the Linux i2c layer, for use | ||
| 114 | * in output probing and control (e.g. DDC or SDVO control functions). | ||
| 115 | * | ||
| 116 | * Possible values for @reg include: | ||
| 117 | * %GPIOA | ||
| 118 | * %GPIOB | ||
| 119 | * %GPIOC | ||
| 120 | * %GPIOD | ||
| 121 | * %GPIOE | ||
| 122 | * %GPIOF | ||
| 123 | * %GPIOG | ||
| 124 | * %GPIOH | ||
| 125 | * see PRM for details on how these different busses are used. | ||
| 126 | */ | ||
| 127 | struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, | ||
| 128 | const char *name) | ||
| 129 | { | ||
| 130 | struct intel_i2c_chan *chan; | ||
| 131 | |||
| 132 | chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL); | ||
| 133 | if (!chan) | ||
| 134 | goto out_free; | ||
| 135 | |||
| 136 | chan->drm_dev = dev; | ||
| 137 | chan->reg = reg; | ||
| 138 | snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name); | ||
| 139 | chan->adapter.owner = THIS_MODULE; | ||
| 140 | #ifndef I2C_HW_B_INTELFB | ||
| 141 | #define I2C_HW_B_INTELFB I2C_HW_B_I810 | ||
| 142 | #endif | ||
| 143 | chan->adapter.id = I2C_HW_B_INTELFB; | ||
| 144 | chan->adapter.algo_data = &chan->algo; | ||
| 145 | chan->adapter.dev.parent = &dev->pdev->dev; | ||
| 146 | chan->algo.setsda = set_data; | ||
| 147 | chan->algo.setscl = set_clock; | ||
| 148 | chan->algo.getsda = get_data; | ||
| 149 | chan->algo.getscl = get_clock; | ||
| 150 | chan->algo.udelay = 20; | ||
| 151 | chan->algo.timeout = usecs_to_jiffies(2200); | ||
| 152 | chan->algo.data = chan; | ||
| 153 | |||
| 154 | i2c_set_adapdata(&chan->adapter, chan); | ||
| 155 | |||
| 156 | if(i2c_bit_add_bus(&chan->adapter)) | ||
| 157 | goto out_free; | ||
| 158 | |||
| 159 | /* JJJ: raise SCL and SDA? */ | ||
| 160 | set_data(chan, 1); | ||
| 161 | set_clock(chan, 1); | ||
| 162 | udelay(20); | ||
| 163 | |||
| 164 | return chan; | ||
| 165 | |||
| 166 | out_free: | ||
| 167 | kfree(chan); | ||
| 168 | return NULL; | ||
| 169 | } | ||
| 170 | |||
| 171 | /** | ||
| 172 | * intel_i2c_destroy - unregister and free i2c bus resources | ||
| 173 | * @output: channel to free | ||
| 174 | * | ||
| 175 | * Unregister the adapter from the i2c layer, then free the structure. | ||
| 176 | */ | ||
| 177 | void intel_i2c_destroy(struct intel_i2c_chan *chan) | ||
| 178 | { | ||
| 179 | if (!chan) | ||
| 180 | return; | ||
| 181 | |||
| 182 | i2c_del_adapter(&chan->adapter); | ||
| 183 | kfree(chan); | ||
| 184 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c new file mode 100644 index 000000000000..ccecfaf6307b --- /dev/null +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
| @@ -0,0 +1,525 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2006-2007 Intel Corporation | ||
| 3 | * Copyright (c) 2006 Dave Airlie <airlied@linux.ie> | ||
| 4 | * | ||
| 5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 6 | * copy of this software and associated documentation files (the "Software"), | ||
| 7 | * to deal in the Software without restriction, including without limitation | ||
| 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 9 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 10 | * Software is furnished to do so, subject to the following conditions: | ||
| 11 | * | ||
| 12 | * The above copyright notice and this permission notice (including the next | ||
| 13 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 14 | * Software. | ||
| 15 | * | ||
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 22 | * DEALINGS IN THE SOFTWARE. | ||
| 23 | * | ||
| 24 | * Authors: | ||
| 25 | * Eric Anholt <eric@anholt.net> | ||
| 26 | * Dave Airlie <airlied@linux.ie> | ||
| 27 | * Jesse Barnes <jesse.barnes@intel.com> | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include <linux/i2c.h> | ||
| 31 | #include "drmP.h" | ||
| 32 | #include "drm.h" | ||
| 33 | #include "drm_crtc.h" | ||
| 34 | #include "drm_edid.h" | ||
| 35 | #include "intel_drv.h" | ||
| 36 | #include "i915_drm.h" | ||
| 37 | #include "i915_drv.h" | ||
| 38 | |||
| 39 | /** | ||
| 40 | * Sets the backlight level. | ||
| 41 | * | ||
| 42 | * \param level backlight level, from 0 to intel_lvds_get_max_backlight(). | ||
| 43 | */ | ||
| 44 | static void intel_lvds_set_backlight(struct drm_device *dev, int level) | ||
| 45 | { | ||
| 46 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 47 | u32 blc_pwm_ctl; | ||
| 48 | |||
| 49 | blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; | ||
| 50 | I915_WRITE(BLC_PWM_CTL, (blc_pwm_ctl | | ||
| 51 | (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); | ||
| 52 | } | ||
| 53 | |||
| 54 | /** | ||
| 55 | * Returns the maximum level of the backlight duty cycle field. | ||
| 56 | */ | ||
| 57 | static u32 intel_lvds_get_max_backlight(struct drm_device *dev) | ||
| 58 | { | ||
| 59 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 60 | |||
| 61 | return ((I915_READ(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >> | ||
| 62 | BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; | ||
| 63 | } | ||
| 64 | |||
| 65 | /** | ||
| 66 | * Sets the power state for the panel. | ||
| 67 | */ | ||
| 68 | static void intel_lvds_set_power(struct drm_device *dev, bool on) | ||
| 69 | { | ||
| 70 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 71 | u32 pp_status; | ||
| 72 | |||
| 73 | if (on) { | ||
| 74 | I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | | ||
| 75 | POWER_TARGET_ON); | ||
| 76 | do { | ||
| 77 | pp_status = I915_READ(PP_STATUS); | ||
| 78 | } while ((pp_status & PP_ON) == 0); | ||
| 79 | |||
| 80 | intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); | ||
| 81 | } else { | ||
| 82 | intel_lvds_set_backlight(dev, 0); | ||
| 83 | |||
| 84 | I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & | ||
| 85 | ~POWER_TARGET_ON); | ||
| 86 | do { | ||
| 87 | pp_status = I915_READ(PP_STATUS); | ||
| 88 | } while (pp_status & PP_ON); | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | static void intel_lvds_dpms(struct drm_encoder *encoder, int mode) | ||
| 93 | { | ||
| 94 | struct drm_device *dev = encoder->dev; | ||
| 95 | |||
| 96 | if (mode == DRM_MODE_DPMS_ON) | ||
| 97 | intel_lvds_set_power(dev, true); | ||
| 98 | else | ||
| 99 | intel_lvds_set_power(dev, false); | ||
| 100 | |||
| 101 | /* XXX: We never power down the LVDS pairs. */ | ||
| 102 | } | ||
| 103 | |||
| 104 | static void intel_lvds_save(struct drm_connector *connector) | ||
| 105 | { | ||
| 106 | struct drm_device *dev = connector->dev; | ||
| 107 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 108 | |||
| 109 | dev_priv->savePP_ON = I915_READ(PP_ON_DELAYS); | ||
| 110 | dev_priv->savePP_OFF = I915_READ(PP_OFF_DELAYS); | ||
| 111 | dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); | ||
| 112 | dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR); | ||
| 113 | dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); | ||
| 114 | dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & | ||
| 115 | BACKLIGHT_DUTY_CYCLE_MASK); | ||
| 116 | |||
| 117 | /* | ||
| 118 | * If the light is off at server startup, just make it full brightness | ||
| 119 | */ | ||
| 120 | if (dev_priv->backlight_duty_cycle == 0) | ||
| 121 | dev_priv->backlight_duty_cycle = | ||
| 122 | intel_lvds_get_max_backlight(dev); | ||
| 123 | } | ||
| 124 | |||
| 125 | static void intel_lvds_restore(struct drm_connector *connector) | ||
| 126 | { | ||
| 127 | struct drm_device *dev = connector->dev; | ||
| 128 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 129 | |||
| 130 | I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); | ||
| 131 | I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON); | ||
| 132 | I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF); | ||
| 133 | I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR); | ||
| 134 | I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); | ||
| 135 | if (dev_priv->savePP_CONTROL & POWER_TARGET_ON) | ||
| 136 | intel_lvds_set_power(dev, true); | ||
| 137 | else | ||
| 138 | intel_lvds_set_power(dev, false); | ||
| 139 | } | ||
| 140 | |||
| 141 | static int intel_lvds_mode_valid(struct drm_connector *connector, | ||
| 142 | struct drm_display_mode *mode) | ||
| 143 | { | ||
| 144 | struct drm_device *dev = connector->dev; | ||
| 145 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 146 | struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode; | ||
| 147 | |||
| 148 | if (fixed_mode) { | ||
| 149 | if (mode->hdisplay > fixed_mode->hdisplay) | ||
| 150 | return MODE_PANEL; | ||
| 151 | if (mode->vdisplay > fixed_mode->vdisplay) | ||
| 152 | return MODE_PANEL; | ||
| 153 | } | ||
| 154 | |||
| 155 | return MODE_OK; | ||
| 156 | } | ||
| 157 | |||
| 158 | static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, | ||
| 159 | struct drm_display_mode *mode, | ||
| 160 | struct drm_display_mode *adjusted_mode) | ||
| 161 | { | ||
| 162 | struct drm_device *dev = encoder->dev; | ||
| 163 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 164 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); | ||
| 165 | struct drm_encoder *tmp_encoder; | ||
| 166 | |||
| 167 | /* Should never happen!! */ | ||
| 168 | if (!IS_I965G(dev) && intel_crtc->pipe == 0) { | ||
| 169 | printk(KERN_ERR "Can't support LVDS on pipe A\n"); | ||
| 170 | return false; | ||
| 171 | } | ||
| 172 | |||
| 173 | /* Should never happen!! */ | ||
| 174 | list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, head) { | ||
| 175 | if (tmp_encoder != encoder && tmp_encoder->crtc == encoder->crtc) { | ||
| 176 | printk(KERN_ERR "Can't enable LVDS and another " | ||
| 177 | "encoder on the same pipe\n"); | ||
| 178 | return false; | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | /* | ||
| 183 | * If we have timings from the BIOS for the panel, put them in | ||
| 184 | * to the adjusted mode. The CRTC will be set up for this mode, | ||
| 185 | * with the panel scaling set up to source from the H/VDisplay | ||
| 186 | * of the original mode. | ||
| 187 | */ | ||
| 188 | if (dev_priv->panel_fixed_mode != NULL) { | ||
| 189 | adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay; | ||
| 190 | adjusted_mode->hsync_start = | ||
| 191 | dev_priv->panel_fixed_mode->hsync_start; | ||
| 192 | adjusted_mode->hsync_end = | ||
| 193 | dev_priv->panel_fixed_mode->hsync_end; | ||
| 194 | adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal; | ||
| 195 | adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay; | ||
| 196 | adjusted_mode->vsync_start = | ||
| 197 | dev_priv->panel_fixed_mode->vsync_start; | ||
| 198 | adjusted_mode->vsync_end = | ||
| 199 | dev_priv->panel_fixed_mode->vsync_end; | ||
| 200 | adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal; | ||
| 201 | adjusted_mode->clock = dev_priv->panel_fixed_mode->clock; | ||
| 202 | drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); | ||
| 203 | } | ||
| 204 | |||
| 205 | /* | ||
| 206 | * XXX: It would be nice to support lower refresh rates on the | ||
| 207 | * panels to reduce power consumption, and perhaps match the | ||
| 208 | * user's requested refresh rate. | ||
| 209 | */ | ||
| 210 | |||
| 211 | return true; | ||
| 212 | } | ||
| 213 | |||
| 214 | static void intel_lvds_prepare(struct drm_encoder *encoder) | ||
| 215 | { | ||
| 216 | struct drm_device *dev = encoder->dev; | ||
| 217 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 218 | |||
| 219 | dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); | ||
| 220 | dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & | ||
| 221 | BACKLIGHT_DUTY_CYCLE_MASK); | ||
| 222 | |||
| 223 | intel_lvds_set_power(dev, false); | ||
| 224 | } | ||
| 225 | |||
| 226 | static void intel_lvds_commit( struct drm_encoder *encoder) | ||
| 227 | { | ||
| 228 | struct drm_device *dev = encoder->dev; | ||
| 229 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 230 | |||
| 231 | if (dev_priv->backlight_duty_cycle == 0) | ||
| 232 | dev_priv->backlight_duty_cycle = | ||
| 233 | intel_lvds_get_max_backlight(dev); | ||
| 234 | |||
| 235 | intel_lvds_set_power(dev, true); | ||
| 236 | } | ||
| 237 | |||
| 238 | static void intel_lvds_mode_set(struct drm_encoder *encoder, | ||
| 239 | struct drm_display_mode *mode, | ||
| 240 | struct drm_display_mode *adjusted_mode) | ||
| 241 | { | ||
| 242 | struct drm_device *dev = encoder->dev; | ||
| 243 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 244 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); | ||
| 245 | u32 pfit_control; | ||
| 246 | |||
| 247 | /* | ||
| 248 | * The LVDS pin pair will already have been turned on in the | ||
| 249 | * intel_crtc_mode_set since it has a large impact on the DPLL | ||
| 250 | * settings. | ||
| 251 | */ | ||
| 252 | |||
| 253 | /* | ||
| 254 | * Enable automatic panel scaling so that non-native modes fill the | ||
| 255 | * screen. Should be enabled before the pipe is enabled, according to | ||
| 256 | * register description and PRM. | ||
| 257 | */ | ||
| 258 | if (mode->hdisplay != adjusted_mode->hdisplay || | ||
| 259 | mode->vdisplay != adjusted_mode->vdisplay) | ||
| 260 | pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | | ||
| 261 | HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR | | ||
| 262 | HORIZ_INTERP_BILINEAR); | ||
| 263 | else | ||
| 264 | pfit_control = 0; | ||
| 265 | |||
| 266 | if (!IS_I965G(dev)) { | ||
| 267 | if (dev_priv->panel_wants_dither) | ||
| 268 | pfit_control |= PANEL_8TO6_DITHER_ENABLE; | ||
| 269 | } | ||
| 270 | else | ||
| 271 | pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT; | ||
| 272 | |||
| 273 | I915_WRITE(PFIT_CONTROL, pfit_control); | ||
| 274 | } | ||
| 275 | |||
| 276 | /** | ||
| 277 | * Detect the LVDS connection. | ||
| 278 | * | ||
| 279 | * This always returns CONNECTOR_STATUS_CONNECTED. This connector should only have | ||
| 280 | * been set up if the LVDS was actually connected anyway. | ||
| 281 | */ | ||
| 282 | static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector) | ||
| 283 | { | ||
| 284 | return connector_status_connected; | ||
| 285 | } | ||
| 286 | |||
| 287 | /** | ||
| 288 | * Return the list of DDC modes if available, or the BIOS fixed mode otherwise. | ||
| 289 | */ | ||
| 290 | static int intel_lvds_get_modes(struct drm_connector *connector) | ||
| 291 | { | ||
| 292 | struct drm_device *dev = connector->dev; | ||
| 293 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 294 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 295 | int ret = 0; | ||
| 296 | |||
| 297 | ret = intel_ddc_get_modes(intel_output); | ||
| 298 | |||
| 299 | if (ret) | ||
| 300 | return ret; | ||
| 301 | |||
| 302 | /* Didn't get an EDID, so | ||
| 303 | * Set wide sync ranges so we get all modes | ||
| 304 | * handed to valid_mode for checking | ||
| 305 | */ | ||
| 306 | connector->display_info.min_vfreq = 0; | ||
| 307 | connector->display_info.max_vfreq = 200; | ||
| 308 | connector->display_info.min_hfreq = 0; | ||
| 309 | connector->display_info.max_hfreq = 200; | ||
| 310 | |||
| 311 | if (dev_priv->panel_fixed_mode != NULL) { | ||
| 312 | struct drm_display_mode *mode; | ||
| 313 | |||
| 314 | mutex_unlock(&dev->mode_config.mutex); | ||
| 315 | mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); | ||
| 316 | drm_mode_probed_add(connector, mode); | ||
| 317 | mutex_unlock(&dev->mode_config.mutex); | ||
| 318 | |||
| 319 | return 1; | ||
| 320 | } | ||
| 321 | |||
| 322 | return 0; | ||
| 323 | } | ||
| 324 | |||
| 325 | /** | ||
| 326 | * intel_lvds_destroy - unregister and free LVDS structures | ||
| 327 | * @connector: connector to free | ||
| 328 | * | ||
| 329 | * Unregister the DDC bus for this connector then free the driver private | ||
| 330 | * structure. | ||
| 331 | */ | ||
| 332 | static void intel_lvds_destroy(struct drm_connector *connector) | ||
| 333 | { | ||
| 334 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 335 | |||
| 336 | if (intel_output->ddc_bus) | ||
| 337 | intel_i2c_destroy(intel_output->ddc_bus); | ||
| 338 | drm_sysfs_connector_remove(connector); | ||
| 339 | drm_connector_cleanup(connector); | ||
| 340 | kfree(connector); | ||
| 341 | } | ||
| 342 | |||
| 343 | static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { | ||
| 344 | .dpms = intel_lvds_dpms, | ||
| 345 | .mode_fixup = intel_lvds_mode_fixup, | ||
| 346 | .prepare = intel_lvds_prepare, | ||
| 347 | .mode_set = intel_lvds_mode_set, | ||
| 348 | .commit = intel_lvds_commit, | ||
| 349 | }; | ||
| 350 | |||
| 351 | static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { | ||
| 352 | .get_modes = intel_lvds_get_modes, | ||
| 353 | .mode_valid = intel_lvds_mode_valid, | ||
| 354 | .best_encoder = intel_best_encoder, | ||
| 355 | }; | ||
| 356 | |||
| 357 | static const struct drm_connector_funcs intel_lvds_connector_funcs = { | ||
| 358 | .save = intel_lvds_save, | ||
| 359 | .restore = intel_lvds_restore, | ||
| 360 | .detect = intel_lvds_detect, | ||
| 361 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
| 362 | .destroy = intel_lvds_destroy, | ||
| 363 | }; | ||
| 364 | |||
| 365 | |||
| 366 | static void intel_lvds_enc_destroy(struct drm_encoder *encoder) | ||
| 367 | { | ||
| 368 | drm_encoder_cleanup(encoder); | ||
| 369 | } | ||
| 370 | |||
| 371 | static const struct drm_encoder_funcs intel_lvds_enc_funcs = { | ||
| 372 | .destroy = intel_lvds_enc_destroy, | ||
| 373 | }; | ||
| 374 | |||
| 375 | |||
| 376 | |||
| 377 | /** | ||
| 378 | * intel_lvds_init - setup LVDS connectors on this device | ||
| 379 | * @dev: drm device | ||
| 380 | * | ||
| 381 | * Create the connector, register the LVDS DDC bus, and try to figure out what | ||
| 382 | * modes we can display on the LVDS panel (if present). | ||
| 383 | */ | ||
| 384 | void intel_lvds_init(struct drm_device *dev) | ||
| 385 | { | ||
| 386 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 387 | struct intel_output *intel_output; | ||
| 388 | struct drm_connector *connector; | ||
| 389 | struct drm_encoder *encoder; | ||
| 390 | struct drm_display_mode *scan; /* *modes, *bios_mode; */ | ||
| 391 | struct drm_crtc *crtc; | ||
| 392 | u32 lvds; | ||
| 393 | int pipe; | ||
| 394 | |||
| 395 | intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); | ||
| 396 | if (!intel_output) { | ||
| 397 | return; | ||
| 398 | } | ||
| 399 | |||
| 400 | connector = &intel_output->base; | ||
| 401 | encoder = &intel_output->enc; | ||
| 402 | drm_connector_init(dev, &intel_output->base, &intel_lvds_connector_funcs, | ||
| 403 | DRM_MODE_CONNECTOR_LVDS); | ||
| 404 | |||
| 405 | drm_encoder_init(dev, &intel_output->enc, &intel_lvds_enc_funcs, | ||
| 406 | DRM_MODE_ENCODER_LVDS); | ||
| 407 | |||
| 408 | drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); | ||
| 409 | intel_output->type = INTEL_OUTPUT_LVDS; | ||
| 410 | |||
| 411 | drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs); | ||
| 412 | drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs); | ||
| 413 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
| 414 | connector->interlace_allowed = false; | ||
| 415 | connector->doublescan_allowed = false; | ||
| 416 | |||
| 417 | |||
| 418 | /* | ||
| 419 | * LVDS discovery: | ||
| 420 | * 1) check for EDID on DDC | ||
| 421 | * 2) check for VBT data | ||
| 422 | * 3) check to see if LVDS is already on | ||
| 423 | * if none of the above, no panel | ||
| 424 | * 4) make sure lid is open | ||
| 425 | * if closed, act like it's not there for now | ||
| 426 | */ | ||
| 427 | |||
| 428 | /* Set up the DDC bus. */ | ||
| 429 | intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); | ||
| 430 | if (!intel_output->ddc_bus) { | ||
| 431 | dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " | ||
| 432 | "failed.\n"); | ||
| 433 | goto failed; | ||
| 434 | } | ||
| 435 | |||
| 436 | /* | ||
| 437 | * Attempt to get the fixed panel mode from DDC. Assume that the | ||
| 438 | * preferred mode is the right one. | ||
| 439 | */ | ||
| 440 | intel_ddc_get_modes(intel_output); | ||
| 441 | |||
| 442 | list_for_each_entry(scan, &connector->probed_modes, head) { | ||
| 443 | mutex_lock(&dev->mode_config.mutex); | ||
| 444 | if (scan->type & DRM_MODE_TYPE_PREFERRED) { | ||
| 445 | dev_priv->panel_fixed_mode = | ||
| 446 | drm_mode_duplicate(dev, scan); | ||
| 447 | mutex_unlock(&dev->mode_config.mutex); | ||
| 448 | goto out; /* FIXME: check for quirks */ | ||
| 449 | } | ||
| 450 | mutex_unlock(&dev->mode_config.mutex); | ||
| 451 | } | ||
| 452 | |||
| 453 | /* Failed to get EDID, what about VBT? */ | ||
| 454 | if (dev_priv->vbt_mode) { | ||
| 455 | mutex_lock(&dev->mode_config.mutex); | ||
| 456 | dev_priv->panel_fixed_mode = | ||
| 457 | drm_mode_duplicate(dev, dev_priv->vbt_mode); | ||
| 458 | mutex_unlock(&dev->mode_config.mutex); | ||
| 459 | } | ||
| 460 | |||
| 461 | /* | ||
| 462 | * If we didn't get EDID, try checking if the panel is already turned | ||
| 463 | * on. If so, assume that whatever is currently programmed is the | ||
| 464 | * correct mode. | ||
| 465 | */ | ||
| 466 | lvds = I915_READ(LVDS); | ||
| 467 | pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; | ||
| 468 | crtc = intel_get_crtc_from_pipe(dev, pipe); | ||
| 469 | |||
| 470 | if (crtc && (lvds & LVDS_PORT_EN)) { | ||
| 471 | dev_priv->panel_fixed_mode = intel_crtc_mode_get(dev, crtc); | ||
| 472 | if (dev_priv->panel_fixed_mode) { | ||
| 473 | dev_priv->panel_fixed_mode->type |= | ||
| 474 | DRM_MODE_TYPE_PREFERRED; | ||
| 475 | goto out; /* FIXME: check for quirks */ | ||
| 476 | } | ||
| 477 | } | ||
| 478 | |||
| 479 | /* If we still don't have a mode after all that, give up. */ | ||
| 480 | if (!dev_priv->panel_fixed_mode) | ||
| 481 | goto failed; | ||
| 482 | |||
| 483 | /* FIXME: detect aopen & mac mini type stuff automatically? */ | ||
| 484 | /* | ||
| 485 | * Blacklist machines with BIOSes that list an LVDS panel without | ||
| 486 | * actually having one. | ||
| 487 | */ | ||
| 488 | if (IS_I945GM(dev)) { | ||
| 489 | /* aopen mini pc */ | ||
| 490 | if (dev->pdev->subsystem_vendor == 0xa0a0) | ||
| 491 | goto failed; | ||
| 492 | |||
| 493 | if ((dev->pdev->subsystem_vendor == 0x8086) && | ||
| 494 | (dev->pdev->subsystem_device == 0x7270)) { | ||
| 495 | /* It's a Mac Mini or Macbook Pro. | ||
| 496 | * | ||
| 497 | * Apple hardware is out to get us. The macbook pro | ||
| 498 | * has a real LVDS panel, but the mac mini does not, | ||
| 499 | * and they have the same device IDs. We'll | ||
| 500 | * distinguish by panel size, on the assumption | ||
| 501 | * that Apple isn't about to make any machines with an | ||
| 502 | * 800x600 display. | ||
| 503 | */ | ||
| 504 | |||
| 505 | if (dev_priv->panel_fixed_mode != NULL && | ||
| 506 | dev_priv->panel_fixed_mode->hdisplay == 800 && | ||
| 507 | dev_priv->panel_fixed_mode->vdisplay == 600) { | ||
| 508 | DRM_DEBUG("Suspected Mac Mini, ignoring the LVDS\n"); | ||
| 509 | goto failed; | ||
| 510 | } | ||
| 511 | } | ||
| 512 | } | ||
| 513 | |||
| 514 | |||
| 515 | out: | ||
| 516 | drm_sysfs_connector_add(connector); | ||
| 517 | return; | ||
| 518 | |||
| 519 | failed: | ||
| 520 | DRM_DEBUG("No LVDS modes found, disabling.\n"); | ||
| 521 | if (intel_output->ddc_bus) | ||
| 522 | intel_i2c_destroy(intel_output->ddc_bus); | ||
| 523 | drm_connector_cleanup(connector); | ||
| 524 | kfree(connector); | ||
| 525 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c new file mode 100644 index 000000000000..e42019e5d661 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_modes.c | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> | ||
| 3 | * Copyright (c) 2007 Intel Corporation | ||
| 4 | * Jesse Barnes <jesse.barnes@intel.com> | ||
| 5 | * | ||
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 7 | * copy of this software and associated documentation files (the "Software"), | ||
| 8 | * to deal in the Software without restriction, including without limitation | ||
| 9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 11 | * Software is furnished to do so, subject to the following conditions: | ||
| 12 | * | ||
| 13 | * The above copyright notice and this permission notice (including the next | ||
| 14 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 15 | * Software. | ||
| 16 | * | ||
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 23 | * DEALINGS IN THE SOFTWARE. | ||
| 24 | */ | ||
| 25 | |||
| 26 | #include <linux/i2c.h> | ||
| 27 | #include <linux/fb.h> | ||
| 28 | #include "drmP.h" | ||
| 29 | #include "intel_drv.h" | ||
| 30 | |||
| 31 | /** | ||
| 32 | * intel_ddc_probe | ||
| 33 | * | ||
| 34 | */ | ||
| 35 | bool intel_ddc_probe(struct intel_output *intel_output) | ||
| 36 | { | ||
| 37 | u8 out_buf[] = { 0x0, 0x0}; | ||
| 38 | u8 buf[2]; | ||
| 39 | int ret; | ||
| 40 | struct i2c_msg msgs[] = { | ||
| 41 | { | ||
| 42 | .addr = 0x50, | ||
| 43 | .flags = 0, | ||
| 44 | .len = 1, | ||
| 45 | .buf = out_buf, | ||
| 46 | }, | ||
| 47 | { | ||
| 48 | .addr = 0x50, | ||
| 49 | .flags = I2C_M_RD, | ||
| 50 | .len = 1, | ||
| 51 | .buf = buf, | ||
| 52 | } | ||
| 53 | }; | ||
| 54 | |||
| 55 | ret = i2c_transfer(&intel_output->ddc_bus->adapter, msgs, 2); | ||
| 56 | if (ret == 2) | ||
| 57 | return true; | ||
| 58 | |||
| 59 | return false; | ||
| 60 | } | ||
| 61 | |||
| 62 | /** | ||
| 63 | * intel_ddc_get_modes - get modelist from monitor | ||
| 64 | * @connector: DRM connector device to use | ||
| 65 | * | ||
| 66 | * Fetch the EDID information from @connector using the DDC bus. | ||
| 67 | */ | ||
| 68 | int intel_ddc_get_modes(struct intel_output *intel_output) | ||
| 69 | { | ||
| 70 | struct edid *edid; | ||
| 71 | int ret = 0; | ||
| 72 | |||
| 73 | edid = drm_get_edid(&intel_output->base, | ||
| 74 | &intel_output->ddc_bus->adapter); | ||
| 75 | if (edid) { | ||
| 76 | drm_mode_connector_update_edid_property(&intel_output->base, | ||
| 77 | edid); | ||
| 78 | ret = drm_add_edid_modes(&intel_output->base, edid); | ||
| 79 | kfree(edid); | ||
| 80 | } | ||
| 81 | |||
| 82 | return ret; | ||
| 83 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c new file mode 100644 index 000000000000..fbbaa4f414a0 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |||
| @@ -0,0 +1,1128 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2006 Dave Airlie <airlied@linux.ie> | ||
| 3 | * Copyright © 2006-2007 Intel Corporation | ||
| 4 | * Jesse Barnes <jesse.barnes@intel.com> | ||
| 5 | * | ||
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 7 | * copy of this software and associated documentation files (the "Software"), | ||
| 8 | * to deal in the Software without restriction, including without limitation | ||
| 9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 11 | * Software is furnished to do so, subject to the following conditions: | ||
| 12 | * | ||
| 13 | * The above copyright notice and this permission notice (including the next | ||
| 14 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 15 | * Software. | ||
| 16 | * | ||
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 23 | * DEALINGS IN THE SOFTWARE. | ||
| 24 | * | ||
| 25 | * Authors: | ||
| 26 | * Eric Anholt <eric@anholt.net> | ||
| 27 | */ | ||
| 28 | #include <linux/i2c.h> | ||
| 29 | #include <linux/delay.h> | ||
| 30 | #include "drmP.h" | ||
| 31 | #include "drm.h" | ||
| 32 | #include "drm_crtc.h" | ||
| 33 | #include "intel_drv.h" | ||
| 34 | #include "i915_drm.h" | ||
| 35 | #include "i915_drv.h" | ||
| 36 | #include "intel_sdvo_regs.h" | ||
| 37 | |||
| 38 | #undef SDVO_DEBUG | ||
| 39 | |||
| 40 | struct intel_sdvo_priv { | ||
| 41 | struct intel_i2c_chan *i2c_bus; | ||
| 42 | int slaveaddr; | ||
| 43 | int output_device; | ||
| 44 | |||
| 45 | u16 active_outputs; | ||
| 46 | |||
| 47 | struct intel_sdvo_caps caps; | ||
| 48 | int pixel_clock_min, pixel_clock_max; | ||
| 49 | |||
| 50 | int save_sdvo_mult; | ||
| 51 | u16 save_active_outputs; | ||
| 52 | struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2; | ||
| 53 | struct intel_sdvo_dtd save_output_dtd[16]; | ||
| 54 | u32 save_SDVOX; | ||
| 55 | }; | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Writes the SDVOB or SDVOC with the given value, but always writes both | ||
| 59 | * SDVOB and SDVOC to work around apparent hardware issues (according to | ||
| 60 | * comments in the BIOS). | ||
| 61 | */ | ||
| 62 | static void intel_sdvo_write_sdvox(struct intel_output *intel_output, u32 val) | ||
| 63 | { | ||
| 64 | struct drm_device *dev = intel_output->base.dev; | ||
| 65 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 66 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
| 67 | u32 bval = val, cval = val; | ||
| 68 | int i; | ||
| 69 | |||
| 70 | if (sdvo_priv->output_device == SDVOB) { | ||
| 71 | cval = I915_READ(SDVOC); | ||
| 72 | } else { | ||
| 73 | bval = I915_READ(SDVOB); | ||
| 74 | } | ||
| 75 | /* | ||
| 76 | * Write the registers twice for luck. Sometimes, | ||
| 77 | * writing them only once doesn't appear to 'stick'. | ||
| 78 | * The BIOS does this too. Yay, magic | ||
| 79 | */ | ||
| 80 | for (i = 0; i < 2; i++) | ||
| 81 | { | ||
| 82 | I915_WRITE(SDVOB, bval); | ||
| 83 | I915_READ(SDVOB); | ||
| 84 | I915_WRITE(SDVOC, cval); | ||
| 85 | I915_READ(SDVOC); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr, | ||
| 90 | u8 *ch) | ||
| 91 | { | ||
| 92 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
| 93 | u8 out_buf[2]; | ||
| 94 | u8 buf[2]; | ||
| 95 | int ret; | ||
| 96 | |||
| 97 | struct i2c_msg msgs[] = { | ||
| 98 | { | ||
| 99 | .addr = sdvo_priv->i2c_bus->slave_addr, | ||
| 100 | .flags = 0, | ||
| 101 | .len = 1, | ||
| 102 | .buf = out_buf, | ||
| 103 | }, | ||
| 104 | { | ||
| 105 | .addr = sdvo_priv->i2c_bus->slave_addr, | ||
| 106 | .flags = I2C_M_RD, | ||
| 107 | .len = 1, | ||
| 108 | .buf = buf, | ||
| 109 | } | ||
| 110 | }; | ||
| 111 | |||
| 112 | out_buf[0] = addr; | ||
| 113 | out_buf[1] = 0; | ||
| 114 | |||
| 115 | if ((ret = i2c_transfer(&sdvo_priv->i2c_bus->adapter, msgs, 2)) == 2) | ||
| 116 | { | ||
| 117 | *ch = buf[0]; | ||
| 118 | return true; | ||
| 119 | } | ||
| 120 | |||
| 121 | DRM_DEBUG("i2c transfer returned %d\n", ret); | ||
| 122 | return false; | ||
| 123 | } | ||
| 124 | |||
| 125 | static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr, | ||
| 126 | u8 ch) | ||
| 127 | { | ||
| 128 | u8 out_buf[2]; | ||
| 129 | struct i2c_msg msgs[] = { | ||
| 130 | { | ||
| 131 | .addr = intel_output->i2c_bus->slave_addr, | ||
| 132 | .flags = 0, | ||
| 133 | .len = 2, | ||
| 134 | .buf = out_buf, | ||
| 135 | } | ||
| 136 | }; | ||
| 137 | |||
| 138 | out_buf[0] = addr; | ||
| 139 | out_buf[1] = ch; | ||
| 140 | |||
| 141 | if (i2c_transfer(&intel_output->i2c_bus->adapter, msgs, 1) == 1) | ||
| 142 | { | ||
| 143 | return true; | ||
| 144 | } | ||
| 145 | return false; | ||
| 146 | } | ||
| 147 | |||
| 148 | #define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd} | ||
| 149 | /** Mapping of command numbers to names, for debug output */ | ||
| 150 | const static struct _sdvo_cmd_name { | ||
| 151 | u8 cmd; | ||
| 152 | char *name; | ||
| 153 | } sdvo_cmd_names[] = { | ||
| 154 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET), | ||
| 155 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS), | ||
| 156 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FIRMWARE_REV), | ||
| 157 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TRAINED_INPUTS), | ||
| 158 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_OUTPUTS), | ||
| 159 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_OUTPUTS), | ||
| 160 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_IN_OUT_MAP), | ||
| 161 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_IN_OUT_MAP), | ||
| 162 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ATTACHED_DISPLAYS), | ||
| 163 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT), | ||
| 164 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG), | ||
| 165 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG), | ||
| 166 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE), | ||
| 167 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT), | ||
| 168 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT), | ||
| 169 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1), | ||
| 170 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART2), | ||
| 171 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), | ||
| 172 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART2), | ||
| 173 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), | ||
| 174 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART1), | ||
| 175 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART2), | ||
| 176 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART1), | ||
| 177 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART2), | ||
| 178 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING), | ||
| 179 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1), | ||
| 180 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2), | ||
| 181 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE), | ||
| 182 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE), | ||
| 183 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS), | ||
| 184 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CLOCK_RATE_MULT), | ||
| 185 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CLOCK_RATE_MULT), | ||
| 186 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS), | ||
| 187 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT), | ||
| 188 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT), | ||
| 189 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT), | ||
| 190 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH), | ||
| 191 | }; | ||
| 192 | |||
| 193 | #define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVOB" : "SDVOC") | ||
| 194 | #define SDVO_PRIV(output) ((struct intel_sdvo_priv *) (output)->dev_priv) | ||
| 195 | |||
| 196 | #ifdef SDVO_DEBUG | ||
| 197 | static void intel_sdvo_debug_write(struct intel_output *intel_output, u8 cmd, | ||
| 198 | void *args, int args_len) | ||
| 199 | { | ||
| 200 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
| 201 | int i; | ||
| 202 | |||
| 203 | DRM_DEBUG("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd); | ||
| 204 | for (i = 0; i < args_len; i++) | ||
| 205 | printk("%02X ", ((u8 *)args)[i]); | ||
| 206 | for (; i < 8; i++) | ||
| 207 | printk(" "); | ||
| 208 | for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) { | ||
| 209 | if (cmd == sdvo_cmd_names[i].cmd) { | ||
| 210 | printk("(%s)", sdvo_cmd_names[i].name); | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0])) | ||
| 215 | printk("(%02X)",cmd); | ||
| 216 | printk("\n"); | ||
| 217 | } | ||
| 218 | #else | ||
| 219 | #define intel_sdvo_debug_write(o, c, a, l) | ||
| 220 | #endif | ||
| 221 | |||
| 222 | static void intel_sdvo_write_cmd(struct intel_output *intel_output, u8 cmd, | ||
| 223 | void *args, int args_len) | ||
| 224 | { | ||
| 225 | int i; | ||
| 226 | |||
| 227 | intel_sdvo_debug_write(intel_output, cmd, args, args_len); | ||
| 228 | |||
| 229 | for (i = 0; i < args_len; i++) { | ||
| 230 | intel_sdvo_write_byte(intel_output, SDVO_I2C_ARG_0 - i, | ||
| 231 | ((u8*)args)[i]); | ||
| 232 | } | ||
| 233 | |||
| 234 | intel_sdvo_write_byte(intel_output, SDVO_I2C_OPCODE, cmd); | ||
| 235 | } | ||
| 236 | |||
| 237 | #ifdef SDVO_DEBUG | ||
| 238 | static const char *cmd_status_names[] = { | ||
| 239 | "Power on", | ||
| 240 | "Success", | ||
| 241 | "Not supported", | ||
| 242 | "Invalid arg", | ||
| 243 | "Pending", | ||
| 244 | "Target not specified", | ||
| 245 | "Scaling not supported" | ||
| 246 | }; | ||
| 247 | |||
| 248 | static void intel_sdvo_debug_response(struct intel_output *intel_output, | ||
| 249 | void *response, int response_len, | ||
| 250 | u8 status) | ||
| 251 | { | ||
| 252 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
| 253 | |||
| 254 | DRM_DEBUG("%s: R: ", SDVO_NAME(sdvo_priv)); | ||
| 255 | for (i = 0; i < response_len; i++) | ||
| 256 | printk("%02X ", ((u8 *)response)[i]); | ||
| 257 | for (; i < 8; i++) | ||
| 258 | printk(" "); | ||
| 259 | if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) | ||
| 260 | printk("(%s)", cmd_status_names[status]); | ||
| 261 | else | ||
| 262 | printk("(??? %d)", status); | ||
| 263 | printk("\n"); | ||
| 264 | } | ||
| 265 | #else | ||
| 266 | #define intel_sdvo_debug_response(o, r, l, s) | ||
| 267 | #endif | ||
| 268 | |||
| 269 | static u8 intel_sdvo_read_response(struct intel_output *intel_output, | ||
| 270 | void *response, int response_len) | ||
| 271 | { | ||
| 272 | int i; | ||
| 273 | u8 status; | ||
| 274 | u8 retry = 50; | ||
| 275 | |||
| 276 | while (retry--) { | ||
| 277 | /* Read the command response */ | ||
| 278 | for (i = 0; i < response_len; i++) { | ||
| 279 | intel_sdvo_read_byte(intel_output, | ||
| 280 | SDVO_I2C_RETURN_0 + i, | ||
| 281 | &((u8 *)response)[i]); | ||
| 282 | } | ||
| 283 | |||
| 284 | /* read the return status */ | ||
| 285 | intel_sdvo_read_byte(intel_output, SDVO_I2C_CMD_STATUS, | ||
| 286 | &status); | ||
| 287 | |||
| 288 | intel_sdvo_debug_response(intel_output, response, response_len, | ||
| 289 | status); | ||
| 290 | if (status != SDVO_CMD_STATUS_PENDING) | ||
| 291 | return status; | ||
| 292 | |||
| 293 | mdelay(50); | ||
| 294 | } | ||
| 295 | |||
| 296 | return status; | ||
| 297 | } | ||
| 298 | |||
| 299 | static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) | ||
| 300 | { | ||
| 301 | if (mode->clock >= 100000) | ||
| 302 | return 1; | ||
| 303 | else if (mode->clock >= 50000) | ||
| 304 | return 2; | ||
| 305 | else | ||
| 306 | return 4; | ||
| 307 | } | ||
| 308 | |||
| 309 | /** | ||
| 310 | * Don't check status code from this as it switches the bus back to the | ||
| 311 | * SDVO chips which defeats the purpose of doing a bus switch in the first | ||
| 312 | * place. | ||
| 313 | */ | ||
| 314 | static void intel_sdvo_set_control_bus_switch(struct intel_output *intel_output, | ||
| 315 | u8 target) | ||
| 316 | { | ||
| 317 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); | ||
| 318 | } | ||
| 319 | |||
| 320 | static bool intel_sdvo_set_target_input(struct intel_output *intel_output, bool target_0, bool target_1) | ||
| 321 | { | ||
| 322 | struct intel_sdvo_set_target_input_args targets = {0}; | ||
| 323 | u8 status; | ||
| 324 | |||
| 325 | if (target_0 && target_1) | ||
| 326 | return SDVO_CMD_STATUS_NOTSUPP; | ||
| 327 | |||
| 328 | if (target_1) | ||
| 329 | targets.target_1 = 1; | ||
| 330 | |||
| 331 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_TARGET_INPUT, &targets, | ||
| 332 | sizeof(targets)); | ||
| 333 | |||
| 334 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
| 335 | |||
| 336 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
| 337 | } | ||
| 338 | |||
| 339 | /** | ||
| 340 | * Return whether each input is trained. | ||
| 341 | * | ||
| 342 | * This function is making an assumption about the layout of the response, | ||
| 343 | * which should be checked against the docs. | ||
| 344 | */ | ||
| 345 | static bool intel_sdvo_get_trained_inputs(struct intel_output *intel_output, bool *input_1, bool *input_2) | ||
| 346 | { | ||
| 347 | struct intel_sdvo_get_trained_inputs_response response; | ||
| 348 | u8 status; | ||
| 349 | |||
| 350 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); | ||
| 351 | status = intel_sdvo_read_response(intel_output, &response, sizeof(response)); | ||
| 352 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
| 353 | return false; | ||
| 354 | |||
| 355 | *input_1 = response.input0_trained; | ||
| 356 | *input_2 = response.input1_trained; | ||
| 357 | return true; | ||
| 358 | } | ||
| 359 | |||
| 360 | static bool intel_sdvo_get_active_outputs(struct intel_output *intel_output, | ||
| 361 | u16 *outputs) | ||
| 362 | { | ||
| 363 | u8 status; | ||
| 364 | |||
| 365 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0); | ||
| 366 | status = intel_sdvo_read_response(intel_output, outputs, sizeof(*outputs)); | ||
| 367 | |||
| 368 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
| 369 | } | ||
| 370 | |||
| 371 | static bool intel_sdvo_set_active_outputs(struct intel_output *intel_output, | ||
| 372 | u16 outputs) | ||
| 373 | { | ||
| 374 | u8 status; | ||
| 375 | |||
| 376 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, | ||
| 377 | sizeof(outputs)); | ||
| 378 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
| 379 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
| 380 | } | ||
| 381 | |||
| 382 | static bool intel_sdvo_set_encoder_power_state(struct intel_output *intel_output, | ||
| 383 | int mode) | ||
| 384 | { | ||
| 385 | u8 status, state = SDVO_ENCODER_STATE_ON; | ||
| 386 | |||
| 387 | switch (mode) { | ||
| 388 | case DRM_MODE_DPMS_ON: | ||
| 389 | state = SDVO_ENCODER_STATE_ON; | ||
| 390 | break; | ||
| 391 | case DRM_MODE_DPMS_STANDBY: | ||
| 392 | state = SDVO_ENCODER_STATE_STANDBY; | ||
| 393 | break; | ||
| 394 | case DRM_MODE_DPMS_SUSPEND: | ||
| 395 | state = SDVO_ENCODER_STATE_SUSPEND; | ||
| 396 | break; | ||
| 397 | case DRM_MODE_DPMS_OFF: | ||
| 398 | state = SDVO_ENCODER_STATE_OFF; | ||
| 399 | break; | ||
| 400 | } | ||
| 401 | |||
| 402 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ENCODER_POWER_STATE, &state, | ||
| 403 | sizeof(state)); | ||
| 404 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
| 405 | |||
| 406 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
| 407 | } | ||
| 408 | |||
| 409 | static bool intel_sdvo_get_input_pixel_clock_range(struct intel_output *intel_output, | ||
| 410 | int *clock_min, | ||
| 411 | int *clock_max) | ||
| 412 | { | ||
| 413 | struct intel_sdvo_pixel_clock_range clocks; | ||
| 414 | u8 status; | ||
| 415 | |||
| 416 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, | ||
| 417 | NULL, 0); | ||
| 418 | |||
| 419 | status = intel_sdvo_read_response(intel_output, &clocks, sizeof(clocks)); | ||
| 420 | |||
| 421 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
| 422 | return false; | ||
| 423 | |||
| 424 | /* Convert the values from units of 10 kHz to kHz. */ | ||
| 425 | *clock_min = clocks.min * 10; | ||
| 426 | *clock_max = clocks.max * 10; | ||
| 427 | |||
| 428 | return true; | ||
| 429 | } | ||
| 430 | |||
| 431 | static bool intel_sdvo_set_target_output(struct intel_output *intel_output, | ||
| 432 | u16 outputs) | ||
| 433 | { | ||
| 434 | u8 status; | ||
| 435 | |||
| 436 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_TARGET_OUTPUT, &outputs, | ||
| 437 | sizeof(outputs)); | ||
| 438 | |||
| 439 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
| 440 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
| 441 | } | ||
| 442 | |||
| 443 | static bool intel_sdvo_get_timing(struct intel_output *intel_output, u8 cmd, | ||
| 444 | struct intel_sdvo_dtd *dtd) | ||
| 445 | { | ||
| 446 | u8 status; | ||
| 447 | |||
| 448 | intel_sdvo_write_cmd(intel_output, cmd, NULL, 0); | ||
| 449 | status = intel_sdvo_read_response(intel_output, &dtd->part1, | ||
| 450 | sizeof(dtd->part1)); | ||
| 451 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
| 452 | return false; | ||
| 453 | |||
| 454 | intel_sdvo_write_cmd(intel_output, cmd + 1, NULL, 0); | ||
| 455 | status = intel_sdvo_read_response(intel_output, &dtd->part2, | ||
| 456 | sizeof(dtd->part2)); | ||
| 457 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
| 458 | return false; | ||
| 459 | |||
| 460 | return true; | ||
| 461 | } | ||
| 462 | |||
| 463 | static bool intel_sdvo_get_input_timing(struct intel_output *intel_output, | ||
| 464 | struct intel_sdvo_dtd *dtd) | ||
| 465 | { | ||
| 466 | return intel_sdvo_get_timing(intel_output, | ||
| 467 | SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd); | ||
| 468 | } | ||
| 469 | |||
| 470 | static bool intel_sdvo_get_output_timing(struct intel_output *intel_output, | ||
| 471 | struct intel_sdvo_dtd *dtd) | ||
| 472 | { | ||
| 473 | return intel_sdvo_get_timing(intel_output, | ||
| 474 | SDVO_CMD_GET_OUTPUT_TIMINGS_PART1, dtd); | ||
| 475 | } | ||
| 476 | |||
| 477 | static bool intel_sdvo_set_timing(struct intel_output *intel_output, u8 cmd, | ||
| 478 | struct intel_sdvo_dtd *dtd) | ||
| 479 | { | ||
| 480 | u8 status; | ||
| 481 | |||
| 482 | intel_sdvo_write_cmd(intel_output, cmd, &dtd->part1, sizeof(dtd->part1)); | ||
| 483 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
| 484 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
| 485 | return false; | ||
| 486 | |||
| 487 | intel_sdvo_write_cmd(intel_output, cmd + 1, &dtd->part2, sizeof(dtd->part2)); | ||
| 488 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
| 489 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
| 490 | return false; | ||
| 491 | |||
| 492 | return true; | ||
| 493 | } | ||
| 494 | |||
| 495 | static bool intel_sdvo_set_input_timing(struct intel_output *intel_output, | ||
| 496 | struct intel_sdvo_dtd *dtd) | ||
| 497 | { | ||
| 498 | return intel_sdvo_set_timing(intel_output, | ||
| 499 | SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd); | ||
| 500 | } | ||
| 501 | |||
| 502 | static bool intel_sdvo_set_output_timing(struct intel_output *intel_output, | ||
| 503 | struct intel_sdvo_dtd *dtd) | ||
| 504 | { | ||
| 505 | return intel_sdvo_set_timing(intel_output, | ||
| 506 | SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); | ||
| 507 | } | ||
| 508 | |||
| 509 | |||
| 510 | static int intel_sdvo_get_clock_rate_mult(struct intel_output *intel_output) | ||
| 511 | { | ||
| 512 | u8 response, status; | ||
| 513 | |||
| 514 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0); | ||
| 515 | status = intel_sdvo_read_response(intel_output, &response, 1); | ||
| 516 | |||
| 517 | if (status != SDVO_CMD_STATUS_SUCCESS) { | ||
| 518 | DRM_DEBUG("Couldn't get SDVO clock rate multiplier\n"); | ||
| 519 | return SDVO_CLOCK_RATE_MULT_1X; | ||
| 520 | } else { | ||
| 521 | DRM_DEBUG("Current clock rate multiplier: %d\n", response); | ||
| 522 | } | ||
| 523 | |||
| 524 | return response; | ||
| 525 | } | ||
| 526 | |||
| 527 | static bool intel_sdvo_set_clock_rate_mult(struct intel_output *intel_output, u8 val) | ||
| 528 | { | ||
| 529 | u8 status; | ||
| 530 | |||
| 531 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); | ||
| 532 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
| 533 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
| 534 | return false; | ||
| 535 | |||
| 536 | return true; | ||
| 537 | } | ||
| 538 | |||
| 539 | static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, | ||
| 540 | struct drm_display_mode *mode, | ||
| 541 | struct drm_display_mode *adjusted_mode) | ||
| 542 | { | ||
| 543 | /* Make the CRTC code factor in the SDVO pixel multiplier. The SDVO | ||
| 544 | * device will be told of the multiplier during mode_set. | ||
| 545 | */ | ||
| 546 | adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); | ||
| 547 | return true; | ||
| 548 | } | ||
| 549 | |||
| 550 | static void intel_sdvo_mode_set(struct drm_encoder *encoder, | ||
| 551 | struct drm_display_mode *mode, | ||
| 552 | struct drm_display_mode *adjusted_mode) | ||
| 553 | { | ||
| 554 | struct drm_device *dev = encoder->dev; | ||
| 555 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 556 | struct drm_crtc *crtc = encoder->crtc; | ||
| 557 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 558 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
| 559 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
| 560 | u16 width, height; | ||
| 561 | u16 h_blank_len, h_sync_len, v_blank_len, v_sync_len; | ||
| 562 | u16 h_sync_offset, v_sync_offset; | ||
| 563 | u32 sdvox; | ||
| 564 | struct intel_sdvo_dtd output_dtd; | ||
| 565 | int sdvo_pixel_multiply; | ||
| 566 | |||
| 567 | if (!mode) | ||
| 568 | return; | ||
| 569 | |||
| 570 | width = mode->crtc_hdisplay; | ||
| 571 | height = mode->crtc_vdisplay; | ||
| 572 | |||
| 573 | /* do some mode translations */ | ||
| 574 | h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start; | ||
| 575 | h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; | ||
| 576 | |||
| 577 | v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start; | ||
| 578 | v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; | ||
| 579 | |||
| 580 | h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start; | ||
| 581 | v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start; | ||
| 582 | |||
| 583 | output_dtd.part1.clock = mode->clock / 10; | ||
| 584 | output_dtd.part1.h_active = width & 0xff; | ||
| 585 | output_dtd.part1.h_blank = h_blank_len & 0xff; | ||
| 586 | output_dtd.part1.h_high = (((width >> 8) & 0xf) << 4) | | ||
| 587 | ((h_blank_len >> 8) & 0xf); | ||
| 588 | output_dtd.part1.v_active = height & 0xff; | ||
| 589 | output_dtd.part1.v_blank = v_blank_len & 0xff; | ||
| 590 | output_dtd.part1.v_high = (((height >> 8) & 0xf) << 4) | | ||
| 591 | ((v_blank_len >> 8) & 0xf); | ||
| 592 | |||
| 593 | output_dtd.part2.h_sync_off = h_sync_offset; | ||
| 594 | output_dtd.part2.h_sync_width = h_sync_len & 0xff; | ||
| 595 | output_dtd.part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 | | ||
| 596 | (v_sync_len & 0xf); | ||
| 597 | output_dtd.part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) | | ||
| 598 | ((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) | | ||
| 599 | ((v_sync_len & 0x30) >> 4); | ||
| 600 | |||
| 601 | output_dtd.part2.dtd_flags = 0x18; | ||
| 602 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
| 603 | output_dtd.part2.dtd_flags |= 0x2; | ||
| 604 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
| 605 | output_dtd.part2.dtd_flags |= 0x4; | ||
| 606 | |||
| 607 | output_dtd.part2.sdvo_flags = 0; | ||
| 608 | output_dtd.part2.v_sync_off_high = v_sync_offset & 0xc0; | ||
| 609 | output_dtd.part2.reserved = 0; | ||
| 610 | |||
| 611 | /* Set the output timing to the screen */ | ||
| 612 | intel_sdvo_set_target_output(intel_output, sdvo_priv->active_outputs); | ||
| 613 | intel_sdvo_set_output_timing(intel_output, &output_dtd); | ||
| 614 | |||
| 615 | /* Set the input timing to the screen. Assume always input 0. */ | ||
| 616 | intel_sdvo_set_target_input(intel_output, true, false); | ||
| 617 | |||
| 618 | /* We would like to use i830_sdvo_create_preferred_input_timing() to | ||
| 619 | * provide the device with a timing it can support, if it supports that | ||
| 620 | * feature. However, presumably we would need to adjust the CRTC to | ||
| 621 | * output the preferred timing, and we don't support that currently. | ||
| 622 | */ | ||
| 623 | intel_sdvo_set_input_timing(intel_output, &output_dtd); | ||
| 624 | |||
| 625 | switch (intel_sdvo_get_pixel_multiplier(mode)) { | ||
| 626 | case 1: | ||
| 627 | intel_sdvo_set_clock_rate_mult(intel_output, | ||
| 628 | SDVO_CLOCK_RATE_MULT_1X); | ||
| 629 | break; | ||
| 630 | case 2: | ||
| 631 | intel_sdvo_set_clock_rate_mult(intel_output, | ||
| 632 | SDVO_CLOCK_RATE_MULT_2X); | ||
| 633 | break; | ||
| 634 | case 4: | ||
| 635 | intel_sdvo_set_clock_rate_mult(intel_output, | ||
| 636 | SDVO_CLOCK_RATE_MULT_4X); | ||
| 637 | break; | ||
| 638 | } | ||
| 639 | |||
| 640 | /* Set the SDVO control regs. */ | ||
| 641 | if (0/*IS_I965GM(dev)*/) { | ||
| 642 | sdvox = SDVO_BORDER_ENABLE; | ||
| 643 | } else { | ||
| 644 | sdvox = I915_READ(sdvo_priv->output_device); | ||
| 645 | switch (sdvo_priv->output_device) { | ||
| 646 | case SDVOB: | ||
| 647 | sdvox &= SDVOB_PRESERVE_MASK; | ||
| 648 | break; | ||
| 649 | case SDVOC: | ||
| 650 | sdvox &= SDVOC_PRESERVE_MASK; | ||
| 651 | break; | ||
| 652 | } | ||
| 653 | sdvox |= (9 << 19) | SDVO_BORDER_ENABLE; | ||
| 654 | } | ||
| 655 | if (intel_crtc->pipe == 1) | ||
| 656 | sdvox |= SDVO_PIPE_B_SELECT; | ||
| 657 | |||
| 658 | sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode); | ||
| 659 | if (IS_I965G(dev)) { | ||
| 660 | /* done in crtc_mode_set as the dpll_md reg must be written | ||
| 661 | early */ | ||
| 662 | } else if (IS_I945G(dev) || IS_I945GM(dev)) { | ||
| 663 | /* done in crtc_mode_set as it lives inside the | ||
| 664 | dpll register */ | ||
| 665 | } else { | ||
| 666 | sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; | ||
| 667 | } | ||
| 668 | |||
| 669 | intel_sdvo_write_sdvox(intel_output, sdvox); | ||
| 670 | } | ||
| 671 | |||
| 672 | static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) | ||
| 673 | { | ||
| 674 | struct drm_device *dev = encoder->dev; | ||
| 675 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 676 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
| 677 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
| 678 | u32 temp; | ||
| 679 | |||
| 680 | if (mode != DRM_MODE_DPMS_ON) { | ||
| 681 | intel_sdvo_set_active_outputs(intel_output, 0); | ||
| 682 | if (0) | ||
| 683 | intel_sdvo_set_encoder_power_state(intel_output, mode); | ||
| 684 | |||
| 685 | if (mode == DRM_MODE_DPMS_OFF) { | ||
| 686 | temp = I915_READ(sdvo_priv->output_device); | ||
| 687 | if ((temp & SDVO_ENABLE) != 0) { | ||
| 688 | intel_sdvo_write_sdvox(intel_output, temp & ~SDVO_ENABLE); | ||
| 689 | } | ||
| 690 | } | ||
| 691 | } else { | ||
| 692 | bool input1, input2; | ||
| 693 | int i; | ||
| 694 | u8 status; | ||
| 695 | |||
| 696 | temp = I915_READ(sdvo_priv->output_device); | ||
| 697 | if ((temp & SDVO_ENABLE) == 0) | ||
| 698 | intel_sdvo_write_sdvox(intel_output, temp | SDVO_ENABLE); | ||
| 699 | for (i = 0; i < 2; i++) | ||
| 700 | intel_wait_for_vblank(dev); | ||
| 701 | |||
| 702 | status = intel_sdvo_get_trained_inputs(intel_output, &input1, | ||
| 703 | &input2); | ||
| 704 | |||
| 705 | |||
| 706 | /* Warn if the device reported failure to sync. | ||
| 707 | * A lot of SDVO devices fail to notify of sync, but it's | ||
| 708 | * a given it the status is a success, we succeeded. | ||
| 709 | */ | ||
| 710 | if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { | ||
| 711 | DRM_DEBUG("First %s output reported failure to sync\n", | ||
| 712 | SDVO_NAME(sdvo_priv)); | ||
| 713 | } | ||
| 714 | |||
| 715 | if (0) | ||
| 716 | intel_sdvo_set_encoder_power_state(intel_output, mode); | ||
| 717 | intel_sdvo_set_active_outputs(intel_output, sdvo_priv->active_outputs); | ||
| 718 | } | ||
| 719 | return; | ||
| 720 | } | ||
| 721 | |||
| 722 | static void intel_sdvo_save(struct drm_connector *connector) | ||
| 723 | { | ||
| 724 | struct drm_device *dev = connector->dev; | ||
| 725 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 726 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 727 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
| 728 | int o; | ||
| 729 | |||
| 730 | sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(intel_output); | ||
| 731 | intel_sdvo_get_active_outputs(intel_output, &sdvo_priv->save_active_outputs); | ||
| 732 | |||
| 733 | if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { | ||
| 734 | intel_sdvo_set_target_input(intel_output, true, false); | ||
| 735 | intel_sdvo_get_input_timing(intel_output, | ||
| 736 | &sdvo_priv->save_input_dtd_1); | ||
| 737 | } | ||
| 738 | |||
| 739 | if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { | ||
| 740 | intel_sdvo_set_target_input(intel_output, false, true); | ||
| 741 | intel_sdvo_get_input_timing(intel_output, | ||
| 742 | &sdvo_priv->save_input_dtd_2); | ||
| 743 | } | ||
| 744 | |||
| 745 | for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) | ||
| 746 | { | ||
| 747 | u16 this_output = (1 << o); | ||
| 748 | if (sdvo_priv->caps.output_flags & this_output) | ||
| 749 | { | ||
| 750 | intel_sdvo_set_target_output(intel_output, this_output); | ||
| 751 | intel_sdvo_get_output_timing(intel_output, | ||
| 752 | &sdvo_priv->save_output_dtd[o]); | ||
| 753 | } | ||
| 754 | } | ||
| 755 | |||
| 756 | sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->output_device); | ||
| 757 | } | ||
| 758 | |||
| 759 | static void intel_sdvo_restore(struct drm_connector *connector) | ||
| 760 | { | ||
| 761 | struct drm_device *dev = connector->dev; | ||
| 762 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 763 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 764 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
| 765 | int o; | ||
| 766 | int i; | ||
| 767 | bool input1, input2; | ||
| 768 | u8 status; | ||
| 769 | |||
| 770 | intel_sdvo_set_active_outputs(intel_output, 0); | ||
| 771 | |||
| 772 | for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) | ||
| 773 | { | ||
| 774 | u16 this_output = (1 << o); | ||
| 775 | if (sdvo_priv->caps.output_flags & this_output) { | ||
| 776 | intel_sdvo_set_target_output(intel_output, this_output); | ||
| 777 | intel_sdvo_set_output_timing(intel_output, &sdvo_priv->save_output_dtd[o]); | ||
| 778 | } | ||
| 779 | } | ||
| 780 | |||
| 781 | if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { | ||
| 782 | intel_sdvo_set_target_input(intel_output, true, false); | ||
| 783 | intel_sdvo_set_input_timing(intel_output, &sdvo_priv->save_input_dtd_1); | ||
| 784 | } | ||
| 785 | |||
| 786 | if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { | ||
| 787 | intel_sdvo_set_target_input(intel_output, false, true); | ||
| 788 | intel_sdvo_set_input_timing(intel_output, &sdvo_priv->save_input_dtd_2); | ||
| 789 | } | ||
| 790 | |||
| 791 | intel_sdvo_set_clock_rate_mult(intel_output, sdvo_priv->save_sdvo_mult); | ||
| 792 | |||
| 793 | I915_WRITE(sdvo_priv->output_device, sdvo_priv->save_SDVOX); | ||
| 794 | |||
| 795 | if (sdvo_priv->save_SDVOX & SDVO_ENABLE) | ||
| 796 | { | ||
| 797 | for (i = 0; i < 2; i++) | ||
| 798 | intel_wait_for_vblank(dev); | ||
| 799 | status = intel_sdvo_get_trained_inputs(intel_output, &input1, &input2); | ||
| 800 | if (status == SDVO_CMD_STATUS_SUCCESS && !input1) | ||
| 801 | DRM_DEBUG("First %s output reported failure to sync\n", | ||
| 802 | SDVO_NAME(sdvo_priv)); | ||
| 803 | } | ||
| 804 | |||
| 805 | intel_sdvo_set_active_outputs(intel_output, sdvo_priv->save_active_outputs); | ||
| 806 | } | ||
| 807 | |||
| 808 | static int intel_sdvo_mode_valid(struct drm_connector *connector, | ||
| 809 | struct drm_display_mode *mode) | ||
| 810 | { | ||
| 811 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 812 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
| 813 | |||
| 814 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
| 815 | return MODE_NO_DBLESCAN; | ||
| 816 | |||
| 817 | if (sdvo_priv->pixel_clock_min > mode->clock) | ||
| 818 | return MODE_CLOCK_LOW; | ||
| 819 | |||
| 820 | if (sdvo_priv->pixel_clock_max < mode->clock) | ||
| 821 | return MODE_CLOCK_HIGH; | ||
| 822 | |||
| 823 | return MODE_OK; | ||
| 824 | } | ||
| 825 | |||
| 826 | static bool intel_sdvo_get_capabilities(struct intel_output *intel_output, struct intel_sdvo_caps *caps) | ||
| 827 | { | ||
| 828 | u8 status; | ||
| 829 | |||
| 830 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); | ||
| 831 | status = intel_sdvo_read_response(intel_output, caps, sizeof(*caps)); | ||
| 832 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
| 833 | return false; | ||
| 834 | |||
| 835 | return true; | ||
| 836 | } | ||
| 837 | |||
| 838 | struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB) | ||
| 839 | { | ||
| 840 | struct drm_connector *connector = NULL; | ||
| 841 | struct intel_output *iout = NULL; | ||
| 842 | struct intel_sdvo_priv *sdvo; | ||
| 843 | |||
| 844 | /* find the sdvo connector */ | ||
| 845 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
| 846 | iout = to_intel_output(connector); | ||
| 847 | |||
| 848 | if (iout->type != INTEL_OUTPUT_SDVO) | ||
| 849 | continue; | ||
| 850 | |||
| 851 | sdvo = iout->dev_priv; | ||
| 852 | |||
| 853 | if (sdvo->output_device == SDVOB && sdvoB) | ||
| 854 | return connector; | ||
| 855 | |||
| 856 | if (sdvo->output_device == SDVOC && !sdvoB) | ||
| 857 | return connector; | ||
| 858 | |||
| 859 | } | ||
| 860 | |||
| 861 | return NULL; | ||
| 862 | } | ||
| 863 | |||
| 864 | int intel_sdvo_supports_hotplug(struct drm_connector *connector) | ||
| 865 | { | ||
| 866 | u8 response[2]; | ||
| 867 | u8 status; | ||
| 868 | struct intel_output *intel_output; | ||
| 869 | DRM_DEBUG("\n"); | ||
| 870 | |||
| 871 | if (!connector) | ||
| 872 | return 0; | ||
| 873 | |||
| 874 | intel_output = to_intel_output(connector); | ||
| 875 | |||
| 876 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); | ||
| 877 | status = intel_sdvo_read_response(intel_output, &response, 2); | ||
| 878 | |||
| 879 | if (response[0] !=0) | ||
| 880 | return 1; | ||
| 881 | |||
| 882 | return 0; | ||
| 883 | } | ||
| 884 | |||
| 885 | void intel_sdvo_set_hotplug(struct drm_connector *connector, int on) | ||
| 886 | { | ||
| 887 | u8 response[2]; | ||
| 888 | u8 status; | ||
| 889 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 890 | |||
| 891 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); | ||
| 892 | intel_sdvo_read_response(intel_output, &response, 2); | ||
| 893 | |||
| 894 | if (on) { | ||
| 895 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); | ||
| 896 | status = intel_sdvo_read_response(intel_output, &response, 2); | ||
| 897 | |||
| 898 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); | ||
| 899 | } else { | ||
| 900 | response[0] = 0; | ||
| 901 | response[1] = 0; | ||
| 902 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); | ||
| 903 | } | ||
| 904 | |||
| 905 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); | ||
| 906 | intel_sdvo_read_response(intel_output, &response, 2); | ||
| 907 | } | ||
| 908 | |||
| 909 | static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector) | ||
| 910 | { | ||
| 911 | u8 response[2]; | ||
| 912 | u8 status; | ||
| 913 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 914 | |||
| 915 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); | ||
| 916 | status = intel_sdvo_read_response(intel_output, &response, 2); | ||
| 917 | |||
| 918 | DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]); | ||
| 919 | if ((response[0] != 0) || (response[1] != 0)) | ||
| 920 | return connector_status_connected; | ||
| 921 | else | ||
| 922 | return connector_status_disconnected; | ||
| 923 | } | ||
| 924 | |||
| 925 | static int intel_sdvo_get_modes(struct drm_connector *connector) | ||
| 926 | { | ||
| 927 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 928 | |||
| 929 | /* set the bus switch and get the modes */ | ||
| 930 | intel_sdvo_set_control_bus_switch(intel_output, SDVO_CONTROL_BUS_DDC2); | ||
| 931 | intel_ddc_get_modes(intel_output); | ||
| 932 | |||
| 933 | if (list_empty(&connector->probed_modes)) | ||
| 934 | return 0; | ||
| 935 | return 1; | ||
| 936 | } | ||
| 937 | |||
| 938 | static void intel_sdvo_destroy(struct drm_connector *connector) | ||
| 939 | { | ||
| 940 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 941 | |||
| 942 | if (intel_output->i2c_bus) | ||
| 943 | intel_i2c_destroy(intel_output->i2c_bus); | ||
| 944 | drm_sysfs_connector_remove(connector); | ||
| 945 | drm_connector_cleanup(connector); | ||
| 946 | kfree(intel_output); | ||
| 947 | } | ||
| 948 | |||
| 949 | static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { | ||
| 950 | .dpms = intel_sdvo_dpms, | ||
| 951 | .mode_fixup = intel_sdvo_mode_fixup, | ||
| 952 | .prepare = intel_encoder_prepare, | ||
| 953 | .mode_set = intel_sdvo_mode_set, | ||
| 954 | .commit = intel_encoder_commit, | ||
| 955 | }; | ||
| 956 | |||
| 957 | static const struct drm_connector_funcs intel_sdvo_connector_funcs = { | ||
| 958 | .save = intel_sdvo_save, | ||
| 959 | .restore = intel_sdvo_restore, | ||
| 960 | .detect = intel_sdvo_detect, | ||
| 961 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
| 962 | .destroy = intel_sdvo_destroy, | ||
| 963 | }; | ||
| 964 | |||
| 965 | static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = { | ||
| 966 | .get_modes = intel_sdvo_get_modes, | ||
| 967 | .mode_valid = intel_sdvo_mode_valid, | ||
| 968 | .best_encoder = intel_best_encoder, | ||
| 969 | }; | ||
| 970 | |||
| 971 | static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) | ||
| 972 | { | ||
| 973 | drm_encoder_cleanup(encoder); | ||
| 974 | } | ||
| 975 | |||
| 976 | static const struct drm_encoder_funcs intel_sdvo_enc_funcs = { | ||
| 977 | .destroy = intel_sdvo_enc_destroy, | ||
| 978 | }; | ||
| 979 | |||
| 980 | |||
| 981 | void intel_sdvo_init(struct drm_device *dev, int output_device) | ||
| 982 | { | ||
| 983 | struct drm_connector *connector; | ||
| 984 | struct intel_output *intel_output; | ||
| 985 | struct intel_sdvo_priv *sdvo_priv; | ||
| 986 | struct intel_i2c_chan *i2cbus = NULL; | ||
| 987 | int connector_type; | ||
| 988 | u8 ch[0x40]; | ||
| 989 | int i; | ||
| 990 | int encoder_type, output_id; | ||
| 991 | |||
| 992 | intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL); | ||
| 993 | if (!intel_output) { | ||
| 994 | return; | ||
| 995 | } | ||
| 996 | |||
| 997 | connector = &intel_output->base; | ||
| 998 | |||
| 999 | drm_connector_init(dev, connector, &intel_sdvo_connector_funcs, | ||
| 1000 | DRM_MODE_CONNECTOR_Unknown); | ||
| 1001 | drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs); | ||
| 1002 | sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); | ||
| 1003 | intel_output->type = INTEL_OUTPUT_SDVO; | ||
| 1004 | |||
| 1005 | connector->interlace_allowed = 0; | ||
| 1006 | connector->doublescan_allowed = 0; | ||
| 1007 | |||
| 1008 | /* setup the DDC bus. */ | ||
| 1009 | if (output_device == SDVOB) | ||
| 1010 | i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB"); | ||
| 1011 | else | ||
| 1012 | i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); | ||
| 1013 | |||
| 1014 | if (!i2cbus) | ||
| 1015 | goto err_connector; | ||
| 1016 | |||
| 1017 | sdvo_priv->i2c_bus = i2cbus; | ||
| 1018 | |||
| 1019 | if (output_device == SDVOB) { | ||
| 1020 | output_id = 1; | ||
| 1021 | sdvo_priv->i2c_bus->slave_addr = 0x38; | ||
| 1022 | } else { | ||
| 1023 | output_id = 2; | ||
| 1024 | sdvo_priv->i2c_bus->slave_addr = 0x39; | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | sdvo_priv->output_device = output_device; | ||
| 1028 | intel_output->i2c_bus = i2cbus; | ||
| 1029 | intel_output->dev_priv = sdvo_priv; | ||
| 1030 | |||
| 1031 | |||
| 1032 | /* Read the regs to test if we can talk to the device */ | ||
| 1033 | for (i = 0; i < 0x40; i++) { | ||
| 1034 | if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) { | ||
| 1035 | DRM_DEBUG("No SDVO device found on SDVO%c\n", | ||
| 1036 | output_device == SDVOB ? 'B' : 'C'); | ||
| 1037 | goto err_i2c; | ||
| 1038 | } | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps); | ||
| 1042 | |||
| 1043 | memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs)); | ||
| 1044 | |||
| 1045 | /* TODO, CVBS, SVID, YPRPB & SCART outputs. */ | ||
| 1046 | if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) | ||
| 1047 | { | ||
| 1048 | sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0; | ||
| 1049 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
| 1050 | encoder_type = DRM_MODE_ENCODER_DAC; | ||
| 1051 | connector_type = DRM_MODE_CONNECTOR_VGA; | ||
| 1052 | } | ||
| 1053 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) | ||
| 1054 | { | ||
| 1055 | sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1; | ||
| 1056 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
| 1057 | encoder_type = DRM_MODE_ENCODER_DAC; | ||
| 1058 | connector_type = DRM_MODE_CONNECTOR_VGA; | ||
| 1059 | } | ||
| 1060 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) | ||
| 1061 | { | ||
| 1062 | sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0; | ||
| 1063 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
| 1064 | encoder_type = DRM_MODE_ENCODER_TMDS; | ||
| 1065 | connector_type = DRM_MODE_CONNECTOR_DVID; | ||
| 1066 | } | ||
| 1067 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1) | ||
| 1068 | { | ||
| 1069 | sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1; | ||
| 1070 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
| 1071 | encoder_type = DRM_MODE_ENCODER_TMDS; | ||
| 1072 | connector_type = DRM_MODE_CONNECTOR_DVID; | ||
| 1073 | } | ||
| 1074 | else | ||
| 1075 | { | ||
| 1076 | unsigned char bytes[2]; | ||
| 1077 | |||
| 1078 | memcpy (bytes, &sdvo_priv->caps.output_flags, 2); | ||
| 1079 | DRM_DEBUG("%s: No active RGB or TMDS outputs (0x%02x%02x)\n", | ||
| 1080 | SDVO_NAME(sdvo_priv), | ||
| 1081 | bytes[0], bytes[1]); | ||
| 1082 | goto err_i2c; | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type); | ||
| 1086 | drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs); | ||
| 1087 | connector->connector_type = connector_type; | ||
| 1088 | |||
| 1089 | drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); | ||
| 1090 | drm_sysfs_connector_add(connector); | ||
| 1091 | |||
| 1092 | /* Set the input timing to the screen. Assume always input 0. */ | ||
| 1093 | intel_sdvo_set_target_input(intel_output, true, false); | ||
| 1094 | |||
| 1095 | intel_sdvo_get_input_pixel_clock_range(intel_output, | ||
| 1096 | &sdvo_priv->pixel_clock_min, | ||
| 1097 | &sdvo_priv->pixel_clock_max); | ||
| 1098 | |||
| 1099 | |||
| 1100 | DRM_DEBUG("%s device VID/DID: %02X:%02X.%02X, " | ||
| 1101 | "clock range %dMHz - %dMHz, " | ||
| 1102 | "input 1: %c, input 2: %c, " | ||
| 1103 | "output 1: %c, output 2: %c\n", | ||
| 1104 | SDVO_NAME(sdvo_priv), | ||
| 1105 | sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id, | ||
| 1106 | sdvo_priv->caps.device_rev_id, | ||
| 1107 | sdvo_priv->pixel_clock_min / 1000, | ||
| 1108 | sdvo_priv->pixel_clock_max / 1000, | ||
| 1109 | (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', | ||
| 1110 | (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', | ||
| 1111 | /* check currently supported outputs */ | ||
| 1112 | sdvo_priv->caps.output_flags & | ||
| 1113 | (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', | ||
| 1114 | sdvo_priv->caps.output_flags & | ||
| 1115 | (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); | ||
| 1116 | |||
| 1117 | intel_output->ddc_bus = i2cbus; | ||
| 1118 | |||
| 1119 | return; | ||
| 1120 | |||
| 1121 | err_i2c: | ||
| 1122 | intel_i2c_destroy(intel_output->i2c_bus); | ||
| 1123 | err_connector: | ||
| 1124 | drm_connector_cleanup(connector); | ||
| 1125 | kfree(intel_output); | ||
| 1126 | |||
| 1127 | return; | ||
| 1128 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h new file mode 100644 index 000000000000..861a43f8693c --- /dev/null +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h | |||
| @@ -0,0 +1,327 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2006-2007 Intel Corporation | ||
| 3 | * | ||
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 5 | * copy of this software and associated documentation files (the "Software"), | ||
| 6 | * to deal in the Software without restriction, including without limitation | ||
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 9 | * Software is furnished to do so, subject to the following conditions: | ||
| 10 | * | ||
| 11 | * The above copyright notice and this permission notice (including the next | ||
| 12 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 13 | * Software. | ||
| 14 | * | ||
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 21 | * DEALINGS IN THE SOFTWARE. | ||
| 22 | * | ||
| 23 | * Authors: | ||
| 24 | * Eric Anholt <eric@anholt.net> | ||
| 25 | */ | ||
| 26 | |||
| 27 | /** | ||
| 28 | * @file SDVO command definitions and structures. | ||
| 29 | */ | ||
| 30 | |||
| 31 | #define SDVO_OUTPUT_FIRST (0) | ||
| 32 | #define SDVO_OUTPUT_TMDS0 (1 << 0) | ||
| 33 | #define SDVO_OUTPUT_RGB0 (1 << 1) | ||
| 34 | #define SDVO_OUTPUT_CVBS0 (1 << 2) | ||
| 35 | #define SDVO_OUTPUT_SVID0 (1 << 3) | ||
| 36 | #define SDVO_OUTPUT_YPRPB0 (1 << 4) | ||
| 37 | #define SDVO_OUTPUT_SCART0 (1 << 5) | ||
| 38 | #define SDVO_OUTPUT_LVDS0 (1 << 6) | ||
| 39 | #define SDVO_OUTPUT_TMDS1 (1 << 8) | ||
| 40 | #define SDVO_OUTPUT_RGB1 (1 << 9) | ||
| 41 | #define SDVO_OUTPUT_CVBS1 (1 << 10) | ||
| 42 | #define SDVO_OUTPUT_SVID1 (1 << 11) | ||
| 43 | #define SDVO_OUTPUT_YPRPB1 (1 << 12) | ||
| 44 | #define SDVO_OUTPUT_SCART1 (1 << 13) | ||
| 45 | #define SDVO_OUTPUT_LVDS1 (1 << 14) | ||
| 46 | #define SDVO_OUTPUT_LAST (14) | ||
| 47 | |||
| 48 | struct intel_sdvo_caps { | ||
| 49 | u8 vendor_id; | ||
| 50 | u8 device_id; | ||
| 51 | u8 device_rev_id; | ||
| 52 | u8 sdvo_version_major; | ||
| 53 | u8 sdvo_version_minor; | ||
| 54 | unsigned int sdvo_inputs_mask:2; | ||
| 55 | unsigned int smooth_scaling:1; | ||
| 56 | unsigned int sharp_scaling:1; | ||
| 57 | unsigned int up_scaling:1; | ||
| 58 | unsigned int down_scaling:1; | ||
| 59 | unsigned int stall_support:1; | ||
| 60 | unsigned int pad:1; | ||
| 61 | u16 output_flags; | ||
| 62 | } __attribute__((packed)); | ||
| 63 | |||
| 64 | /** This matches the EDID DTD structure, more or less */ | ||
| 65 | struct intel_sdvo_dtd { | ||
| 66 | struct { | ||
| 67 | u16 clock; /**< pixel clock, in 10kHz units */ | ||
| 68 | u8 h_active; /**< lower 8 bits (pixels) */ | ||
| 69 | u8 h_blank; /**< lower 8 bits (pixels) */ | ||
| 70 | u8 h_high; /**< upper 4 bits each h_active, h_blank */ | ||
| 71 | u8 v_active; /**< lower 8 bits (lines) */ | ||
| 72 | u8 v_blank; /**< lower 8 bits (lines) */ | ||
| 73 | u8 v_high; /**< upper 4 bits each v_active, v_blank */ | ||
| 74 | } part1; | ||
| 75 | |||
| 76 | struct { | ||
| 77 | u8 h_sync_off; /**< lower 8 bits, from hblank start */ | ||
| 78 | u8 h_sync_width; /**< lower 8 bits (pixels) */ | ||
| 79 | /** lower 4 bits each vsync offset, vsync width */ | ||
| 80 | u8 v_sync_off_width; | ||
| 81 | /** | ||
| 82 | * 2 high bits of hsync offset, 2 high bits of hsync width, | ||
| 83 | * bits 4-5 of vsync offset, and 2 high bits of vsync width. | ||
| 84 | */ | ||
| 85 | u8 sync_off_width_high; | ||
| 86 | u8 dtd_flags; | ||
| 87 | u8 sdvo_flags; | ||
| 88 | /** bits 6-7 of vsync offset at bits 6-7 */ | ||
| 89 | u8 v_sync_off_high; | ||
| 90 | u8 reserved; | ||
| 91 | } part2; | ||
| 92 | } __attribute__((packed)); | ||
| 93 | |||
| 94 | struct intel_sdvo_pixel_clock_range { | ||
| 95 | u16 min; /**< pixel clock, in 10kHz units */ | ||
| 96 | u16 max; /**< pixel clock, in 10kHz units */ | ||
| 97 | } __attribute__((packed)); | ||
| 98 | |||
| 99 | struct intel_sdvo_preferred_input_timing_args { | ||
| 100 | u16 clock; | ||
| 101 | u16 width; | ||
| 102 | u16 height; | ||
| 103 | } __attribute__((packed)); | ||
| 104 | |||
| 105 | /* I2C registers for SDVO */ | ||
| 106 | #define SDVO_I2C_ARG_0 0x07 | ||
| 107 | #define SDVO_I2C_ARG_1 0x06 | ||
| 108 | #define SDVO_I2C_ARG_2 0x05 | ||
| 109 | #define SDVO_I2C_ARG_3 0x04 | ||
| 110 | #define SDVO_I2C_ARG_4 0x03 | ||
| 111 | #define SDVO_I2C_ARG_5 0x02 | ||
| 112 | #define SDVO_I2C_ARG_6 0x01 | ||
| 113 | #define SDVO_I2C_ARG_7 0x00 | ||
| 114 | #define SDVO_I2C_OPCODE 0x08 | ||
| 115 | #define SDVO_I2C_CMD_STATUS 0x09 | ||
| 116 | #define SDVO_I2C_RETURN_0 0x0a | ||
| 117 | #define SDVO_I2C_RETURN_1 0x0b | ||
| 118 | #define SDVO_I2C_RETURN_2 0x0c | ||
| 119 | #define SDVO_I2C_RETURN_3 0x0d | ||
| 120 | #define SDVO_I2C_RETURN_4 0x0e | ||
| 121 | #define SDVO_I2C_RETURN_5 0x0f | ||
| 122 | #define SDVO_I2C_RETURN_6 0x10 | ||
| 123 | #define SDVO_I2C_RETURN_7 0x11 | ||
| 124 | #define SDVO_I2C_VENDOR_BEGIN 0x20 | ||
| 125 | |||
| 126 | /* Status results */ | ||
| 127 | #define SDVO_CMD_STATUS_POWER_ON 0x0 | ||
| 128 | #define SDVO_CMD_STATUS_SUCCESS 0x1 | ||
| 129 | #define SDVO_CMD_STATUS_NOTSUPP 0x2 | ||
| 130 | #define SDVO_CMD_STATUS_INVALID_ARG 0x3 | ||
| 131 | #define SDVO_CMD_STATUS_PENDING 0x4 | ||
| 132 | #define SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED 0x5 | ||
| 133 | #define SDVO_CMD_STATUS_SCALING_NOT_SUPP 0x6 | ||
| 134 | |||
| 135 | /* SDVO commands, argument/result registers */ | ||
| 136 | |||
| 137 | #define SDVO_CMD_RESET 0x01 | ||
| 138 | |||
| 139 | /** Returns a struct intel_sdvo_caps */ | ||
| 140 | #define SDVO_CMD_GET_DEVICE_CAPS 0x02 | ||
| 141 | |||
| 142 | #define SDVO_CMD_GET_FIRMWARE_REV 0x86 | ||
| 143 | # define SDVO_DEVICE_FIRMWARE_MINOR SDVO_I2C_RETURN_0 | ||
| 144 | # define SDVO_DEVICE_FIRMWARE_MAJOR SDVO_I2C_RETURN_1 | ||
| 145 | # define SDVO_DEVICE_FIRMWARE_PATCH SDVO_I2C_RETURN_2 | ||
| 146 | |||
| 147 | /** | ||
| 148 | * Reports which inputs are trained (managed to sync). | ||
| 149 | * | ||
| 150 | * Devices must have trained within 2 vsyncs of a mode change. | ||
| 151 | */ | ||
| 152 | #define SDVO_CMD_GET_TRAINED_INPUTS 0x03 | ||
| 153 | struct intel_sdvo_get_trained_inputs_response { | ||
| 154 | unsigned int input0_trained:1; | ||
| 155 | unsigned int input1_trained:1; | ||
| 156 | unsigned int pad:6; | ||
| 157 | } __attribute__((packed)); | ||
| 158 | |||
| 159 | /** Returns a struct intel_sdvo_output_flags of active outputs. */ | ||
| 160 | #define SDVO_CMD_GET_ACTIVE_OUTPUTS 0x04 | ||
| 161 | |||
| 162 | /** | ||
| 163 | * Sets the current set of active outputs. | ||
| 164 | * | ||
| 165 | * Takes a struct intel_sdvo_output_flags. Must be preceded by a SET_IN_OUT_MAP | ||
| 166 | * on multi-output devices. | ||
| 167 | */ | ||
| 168 | #define SDVO_CMD_SET_ACTIVE_OUTPUTS 0x05 | ||
| 169 | |||
| 170 | /** | ||
| 171 | * Returns the current mapping of SDVO inputs to outputs on the device. | ||
| 172 | * | ||
| 173 | * Returns two struct intel_sdvo_output_flags structures. | ||
| 174 | */ | ||
| 175 | #define SDVO_CMD_GET_IN_OUT_MAP 0x06 | ||
| 176 | |||
| 177 | /** | ||
| 178 | * Sets the current mapping of SDVO inputs to outputs on the device. | ||
| 179 | * | ||
| 180 | * Takes two struct i380_sdvo_output_flags structures. | ||
| 181 | */ | ||
| 182 | #define SDVO_CMD_SET_IN_OUT_MAP 0x07 | ||
| 183 | |||
| 184 | /** | ||
| 185 | * Returns a struct intel_sdvo_output_flags of attached displays. | ||
| 186 | */ | ||
| 187 | #define SDVO_CMD_GET_ATTACHED_DISPLAYS 0x0b | ||
| 188 | |||
| 189 | /** | ||
| 190 | * Returns a struct intel_sdvo_ouptut_flags of displays supporting hot plugging. | ||
| 191 | */ | ||
| 192 | #define SDVO_CMD_GET_HOT_PLUG_SUPPORT 0x0c | ||
| 193 | |||
| 194 | /** | ||
| 195 | * Takes a struct intel_sdvo_output_flags. | ||
| 196 | */ | ||
| 197 | #define SDVO_CMD_SET_ACTIVE_HOT_PLUG 0x0d | ||
| 198 | |||
| 199 | /** | ||
| 200 | * Returns a struct intel_sdvo_output_flags of displays with hot plug | ||
| 201 | * interrupts enabled. | ||
| 202 | */ | ||
| 203 | #define SDVO_CMD_GET_ACTIVE_HOT_PLUG 0x0e | ||
| 204 | |||
| 205 | #define SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE 0x0f | ||
| 206 | struct intel_sdvo_get_interrupt_event_source_response { | ||
| 207 | u16 interrupt_status; | ||
| 208 | unsigned int ambient_light_interrupt:1; | ||
| 209 | unsigned int pad:7; | ||
| 210 | } __attribute__((packed)); | ||
| 211 | |||
| 212 | /** | ||
| 213 | * Selects which input is affected by future input commands. | ||
| 214 | * | ||
| 215 | * Commands affected include SET_INPUT_TIMINGS_PART[12], | ||
| 216 | * GET_INPUT_TIMINGS_PART[12], GET_PREFERRED_INPUT_TIMINGS_PART[12], | ||
| 217 | * GET_INPUT_PIXEL_CLOCK_RANGE, and CREATE_PREFERRED_INPUT_TIMINGS. | ||
| 218 | */ | ||
| 219 | #define SDVO_CMD_SET_TARGET_INPUT 0x10 | ||
| 220 | struct intel_sdvo_set_target_input_args { | ||
| 221 | unsigned int target_1:1; | ||
| 222 | unsigned int pad:7; | ||
| 223 | } __attribute__((packed)); | ||
| 224 | |||
| 225 | /** | ||
| 226 | * Takes a struct intel_sdvo_output_flags of which outputs are targetted by | ||
| 227 | * future output commands. | ||
| 228 | * | ||
| 229 | * Affected commands inclue SET_OUTPUT_TIMINGS_PART[12], | ||
| 230 | * GET_OUTPUT_TIMINGS_PART[12], and GET_OUTPUT_PIXEL_CLOCK_RANGE. | ||
| 231 | */ | ||
| 232 | #define SDVO_CMD_SET_TARGET_OUTPUT 0x11 | ||
| 233 | |||
| 234 | #define SDVO_CMD_GET_INPUT_TIMINGS_PART1 0x12 | ||
| 235 | #define SDVO_CMD_GET_INPUT_TIMINGS_PART2 0x13 | ||
| 236 | #define SDVO_CMD_SET_INPUT_TIMINGS_PART1 0x14 | ||
| 237 | #define SDVO_CMD_SET_INPUT_TIMINGS_PART2 0x15 | ||
| 238 | #define SDVO_CMD_SET_OUTPUT_TIMINGS_PART1 0x16 | ||
| 239 | #define SDVO_CMD_SET_OUTPUT_TIMINGS_PART2 0x17 | ||
| 240 | #define SDVO_CMD_GET_OUTPUT_TIMINGS_PART1 0x18 | ||
| 241 | #define SDVO_CMD_GET_OUTPUT_TIMINGS_PART2 0x19 | ||
| 242 | /* Part 1 */ | ||
| 243 | # define SDVO_DTD_CLOCK_LOW SDVO_I2C_ARG_0 | ||
| 244 | # define SDVO_DTD_CLOCK_HIGH SDVO_I2C_ARG_1 | ||
| 245 | # define SDVO_DTD_H_ACTIVE SDVO_I2C_ARG_2 | ||
| 246 | # define SDVO_DTD_H_BLANK SDVO_I2C_ARG_3 | ||
| 247 | # define SDVO_DTD_H_HIGH SDVO_I2C_ARG_4 | ||
| 248 | # define SDVO_DTD_V_ACTIVE SDVO_I2C_ARG_5 | ||
| 249 | # define SDVO_DTD_V_BLANK SDVO_I2C_ARG_6 | ||
| 250 | # define SDVO_DTD_V_HIGH SDVO_I2C_ARG_7 | ||
| 251 | /* Part 2 */ | ||
| 252 | # define SDVO_DTD_HSYNC_OFF SDVO_I2C_ARG_0 | ||
| 253 | # define SDVO_DTD_HSYNC_WIDTH SDVO_I2C_ARG_1 | ||
| 254 | # define SDVO_DTD_VSYNC_OFF_WIDTH SDVO_I2C_ARG_2 | ||
| 255 | # define SDVO_DTD_SYNC_OFF_WIDTH_HIGH SDVO_I2C_ARG_3 | ||
| 256 | # define SDVO_DTD_DTD_FLAGS SDVO_I2C_ARG_4 | ||
| 257 | # define SDVO_DTD_DTD_FLAG_INTERLACED (1 << 7) | ||
| 258 | # define SDVO_DTD_DTD_FLAG_STEREO_MASK (3 << 5) | ||
| 259 | # define SDVO_DTD_DTD_FLAG_INPUT_MASK (3 << 3) | ||
| 260 | # define SDVO_DTD_DTD_FLAG_SYNC_MASK (3 << 1) | ||
| 261 | # define SDVO_DTD_SDVO_FLAS SDVO_I2C_ARG_5 | ||
| 262 | # define SDVO_DTD_SDVO_FLAG_STALL (1 << 7) | ||
| 263 | # define SDVO_DTD_SDVO_FLAG_CENTERED (0 << 6) | ||
| 264 | # define SDVO_DTD_SDVO_FLAG_UPPER_LEFT (1 << 6) | ||
| 265 | # define SDVO_DTD_SDVO_FLAG_SCALING_MASK (3 << 4) | ||
| 266 | # define SDVO_DTD_SDVO_FLAG_SCALING_NONE (0 << 4) | ||
| 267 | # define SDVO_DTD_SDVO_FLAG_SCALING_SHARP (1 << 4) | ||
| 268 | # define SDVO_DTD_SDVO_FLAG_SCALING_SMOOTH (2 << 4) | ||
| 269 | # define SDVO_DTD_VSYNC_OFF_HIGH SDVO_I2C_ARG_6 | ||
| 270 | |||
| 271 | /** | ||
| 272 | * Generates a DTD based on the given width, height, and flags. | ||
| 273 | * | ||
| 274 | * This will be supported by any device supporting scaling or interlaced | ||
| 275 | * modes. | ||
| 276 | */ | ||
| 277 | #define SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING 0x1a | ||
| 278 | # define SDVO_PREFERRED_INPUT_TIMING_CLOCK_LOW SDVO_I2C_ARG_0 | ||
| 279 | # define SDVO_PREFERRED_INPUT_TIMING_CLOCK_HIGH SDVO_I2C_ARG_1 | ||
| 280 | # define SDVO_PREFERRED_INPUT_TIMING_WIDTH_LOW SDVO_I2C_ARG_2 | ||
| 281 | # define SDVO_PREFERRED_INPUT_TIMING_WIDTH_HIGH SDVO_I2C_ARG_3 | ||
| 282 | # define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_LOW SDVO_I2C_ARG_4 | ||
| 283 | # define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_HIGH SDVO_I2C_ARG_5 | ||
| 284 | # define SDVO_PREFERRED_INPUT_TIMING_FLAGS SDVO_I2C_ARG_6 | ||
| 285 | # define SDVO_PREFERRED_INPUT_TIMING_FLAGS_INTERLACED (1 << 0) | ||
| 286 | # define SDVO_PREFERRED_INPUT_TIMING_FLAGS_SCALED (1 << 1) | ||
| 287 | |||
| 288 | #define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1 0x1b | ||
| 289 | #define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2 0x1c | ||
| 290 | |||
| 291 | /** Returns a struct intel_sdvo_pixel_clock_range */ | ||
| 292 | #define SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE 0x1d | ||
| 293 | /** Returns a struct intel_sdvo_pixel_clock_range */ | ||
| 294 | #define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE 0x1e | ||
| 295 | |||
| 296 | /** Returns a byte bitfield containing SDVO_CLOCK_RATE_MULT_* flags */ | ||
| 297 | #define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS 0x1f | ||
| 298 | |||
| 299 | /** Returns a byte containing a SDVO_CLOCK_RATE_MULT_* flag */ | ||
| 300 | #define SDVO_CMD_GET_CLOCK_RATE_MULT 0x20 | ||
| 301 | /** Takes a byte containing a SDVO_CLOCK_RATE_MULT_* flag */ | ||
| 302 | #define SDVO_CMD_SET_CLOCK_RATE_MULT 0x21 | ||
| 303 | # define SDVO_CLOCK_RATE_MULT_1X (1 << 0) | ||
| 304 | # define SDVO_CLOCK_RATE_MULT_2X (1 << 1) | ||
| 305 | # define SDVO_CLOCK_RATE_MULT_4X (1 << 3) | ||
| 306 | |||
| 307 | #define SDVO_CMD_GET_SUPPORTED_TV_FORMATS 0x27 | ||
| 308 | |||
| 309 | #define SDVO_CMD_GET_TV_FORMAT 0x28 | ||
| 310 | |||
| 311 | #define SDVO_CMD_SET_TV_FORMAT 0x29 | ||
| 312 | |||
| 313 | #define SDVO_CMD_GET_SUPPORTED_POWER_STATES 0x2a | ||
| 314 | #define SDVO_CMD_GET_ENCODER_POWER_STATE 0x2b | ||
| 315 | #define SDVO_CMD_SET_ENCODER_POWER_STATE 0x2c | ||
| 316 | # define SDVO_ENCODER_STATE_ON (1 << 0) | ||
| 317 | # define SDVO_ENCODER_STATE_STANDBY (1 << 1) | ||
| 318 | # define SDVO_ENCODER_STATE_SUSPEND (1 << 2) | ||
| 319 | # define SDVO_ENCODER_STATE_OFF (1 << 3) | ||
| 320 | |||
| 321 | #define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT 0x93 | ||
| 322 | |||
| 323 | #define SDVO_CMD_SET_CONTROL_BUS_SWITCH 0x7a | ||
| 324 | # define SDVO_CONTROL_BUS_PROM 0x0 | ||
| 325 | # define SDVO_CONTROL_BUS_DDC1 0x1 | ||
| 326 | # define SDVO_CONTROL_BUS_DDC2 0x2 | ||
| 327 | # define SDVO_CONTROL_BUS_DDC3 0x3 | ||
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c new file mode 100644 index 000000000000..fbb35dc56f5c --- /dev/null +++ b/drivers/gpu/drm/i915/intel_tv.c | |||
| @@ -0,0 +1,1725 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2006-2008 Intel Corporation | ||
| 3 | * Jesse Barnes <jesse.barnes@intel.com> | ||
| 4 | * | ||
| 5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 6 | * copy of this software and associated documentation files (the "Software"), | ||
| 7 | * to deal in the Software without restriction, including without limitation | ||
| 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 9 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 10 | * Software is furnished to do so, subject to the following conditions: | ||
| 11 | * | ||
| 12 | * The above copyright notice and this permission notice (including the next | ||
| 13 | * paragraph) shall be included in all copies or substantial portions of the | ||
| 14 | * Software. | ||
| 15 | * | ||
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
| 22 | * DEALINGS IN THE SOFTWARE. | ||
| 23 | * | ||
| 24 | * Authors: | ||
| 25 | * Eric Anholt <eric@anholt.net> | ||
| 26 | * | ||
| 27 | */ | ||
| 28 | |||
| 29 | /** @file | ||
| 30 | * Integrated TV-out support for the 915GM and 945GM. | ||
| 31 | */ | ||
| 32 | |||
| 33 | #include "drmP.h" | ||
| 34 | #include "drm.h" | ||
| 35 | #include "drm_crtc.h" | ||
| 36 | #include "drm_edid.h" | ||
| 37 | #include "intel_drv.h" | ||
| 38 | #include "i915_drm.h" | ||
| 39 | #include "i915_drv.h" | ||
| 40 | |||
| 41 | enum tv_margin { | ||
| 42 | TV_MARGIN_LEFT, TV_MARGIN_TOP, | ||
| 43 | TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM | ||
| 44 | }; | ||
| 45 | |||
| 46 | /** Private structure for the integrated TV support */ | ||
| 47 | struct intel_tv_priv { | ||
| 48 | int type; | ||
| 49 | char *tv_format; | ||
| 50 | int margin[4]; | ||
| 51 | u32 save_TV_H_CTL_1; | ||
| 52 | u32 save_TV_H_CTL_2; | ||
| 53 | u32 save_TV_H_CTL_3; | ||
| 54 | u32 save_TV_V_CTL_1; | ||
| 55 | u32 save_TV_V_CTL_2; | ||
| 56 | u32 save_TV_V_CTL_3; | ||
| 57 | u32 save_TV_V_CTL_4; | ||
| 58 | u32 save_TV_V_CTL_5; | ||
| 59 | u32 save_TV_V_CTL_6; | ||
| 60 | u32 save_TV_V_CTL_7; | ||
| 61 | u32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3; | ||
| 62 | |||
| 63 | u32 save_TV_CSC_Y; | ||
| 64 | u32 save_TV_CSC_Y2; | ||
| 65 | u32 save_TV_CSC_U; | ||
| 66 | u32 save_TV_CSC_U2; | ||
| 67 | u32 save_TV_CSC_V; | ||
| 68 | u32 save_TV_CSC_V2; | ||
| 69 | u32 save_TV_CLR_KNOBS; | ||
| 70 | u32 save_TV_CLR_LEVEL; | ||
| 71 | u32 save_TV_WIN_POS; | ||
| 72 | u32 save_TV_WIN_SIZE; | ||
| 73 | u32 save_TV_FILTER_CTL_1; | ||
| 74 | u32 save_TV_FILTER_CTL_2; | ||
| 75 | u32 save_TV_FILTER_CTL_3; | ||
| 76 | |||
| 77 | u32 save_TV_H_LUMA[60]; | ||
| 78 | u32 save_TV_H_CHROMA[60]; | ||
| 79 | u32 save_TV_V_LUMA[43]; | ||
| 80 | u32 save_TV_V_CHROMA[43]; | ||
| 81 | |||
| 82 | u32 save_TV_DAC; | ||
| 83 | u32 save_TV_CTL; | ||
| 84 | }; | ||
| 85 | |||
| 86 | struct video_levels { | ||
| 87 | int blank, black, burst; | ||
| 88 | }; | ||
| 89 | |||
| 90 | struct color_conversion { | ||
| 91 | u16 ry, gy, by, ay; | ||
| 92 | u16 ru, gu, bu, au; | ||
| 93 | u16 rv, gv, bv, av; | ||
| 94 | }; | ||
| 95 | |||
| 96 | static const u32 filter_table[] = { | ||
| 97 | 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140, | ||
| 98 | 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000, | ||
| 99 | 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160, | ||
| 100 | 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780, | ||
| 101 | 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50, | ||
| 102 | 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20, | ||
| 103 | 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0, | ||
| 104 | 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0, | ||
| 105 | 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020, | ||
| 106 | 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140, | ||
| 107 | 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20, | ||
| 108 | 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848, | ||
| 109 | 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900, | ||
| 110 | 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080, | ||
| 111 | 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060, | ||
| 112 | 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140, | ||
| 113 | 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000, | ||
| 114 | 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160, | ||
| 115 | 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780, | ||
| 116 | 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50, | ||
| 117 | 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20, | ||
| 118 | 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0, | ||
| 119 | 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0, | ||
| 120 | 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020, | ||
| 121 | 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140, | ||
| 122 | 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20, | ||
| 123 | 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848, | ||
| 124 | 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900, | ||
| 125 | 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080, | ||
| 126 | 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060, | ||
| 127 | 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0, | ||
| 128 | 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540, | ||
| 129 | 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00, | ||
| 130 | 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000, | ||
| 131 | 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00, | ||
| 132 | 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40, | ||
| 133 | 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240, | ||
| 134 | 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00, | ||
| 135 | 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0, | ||
| 136 | 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840, | ||
| 137 | 0x28003100, 0x28002F00, 0x00003100, 0x36403000, | ||
| 138 | 0x2D002CC0, 0x30003640, 0x2D0036C0, | ||
| 139 | 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540, | ||
| 140 | 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00, | ||
| 141 | 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000, | ||
| 142 | 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00, | ||
| 143 | 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40, | ||
| 144 | 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240, | ||
| 145 | 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00, | ||
| 146 | 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0, | ||
| 147 | 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840, | ||
| 148 | 0x28003100, 0x28002F00, 0x00003100, | ||
| 149 | }; | ||
| 150 | |||
| 151 | /* | ||
| 152 | * Color conversion values have 3 separate fixed point formats: | ||
| 153 | * | ||
| 154 | * 10 bit fields (ay, au) | ||
| 155 | * 1.9 fixed point (b.bbbbbbbbb) | ||
| 156 | * 11 bit fields (ry, by, ru, gu, gv) | ||
| 157 | * exp.mantissa (ee.mmmmmmmmm) | ||
| 158 | * ee = 00 = 10^-1 (0.mmmmmmmmm) | ||
| 159 | * ee = 01 = 10^-2 (0.0mmmmmmmmm) | ||
| 160 | * ee = 10 = 10^-3 (0.00mmmmmmmmm) | ||
| 161 | * ee = 11 = 10^-4 (0.000mmmmmmmmm) | ||
| 162 | * 12 bit fields (gy, rv, bu) | ||
| 163 | * exp.mantissa (eee.mmmmmmmmm) | ||
| 164 | * eee = 000 = 10^-1 (0.mmmmmmmmm) | ||
| 165 | * eee = 001 = 10^-2 (0.0mmmmmmmmm) | ||
| 166 | * eee = 010 = 10^-3 (0.00mmmmmmmmm) | ||
| 167 | * eee = 011 = 10^-4 (0.000mmmmmmmmm) | ||
| 168 | * eee = 100 = reserved | ||
| 169 | * eee = 101 = reserved | ||
| 170 | * eee = 110 = reserved | ||
| 171 | * eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation) | ||
| 172 | * | ||
| 173 | * Saturation and contrast are 8 bits, with their own representation: | ||
| 174 | * 8 bit field (saturation, contrast) | ||
| 175 | * exp.mantissa (ee.mmmmmm) | ||
| 176 | * ee = 00 = 10^-1 (0.mmmmmm) | ||
| 177 | * ee = 01 = 10^0 (m.mmmmm) | ||
| 178 | * ee = 10 = 10^1 (mm.mmmm) | ||
| 179 | * ee = 11 = 10^2 (mmm.mmm) | ||
| 180 | * | ||
| 181 | * Simple conversion function: | ||
| 182 | * | ||
| 183 | * static u32 | ||
| 184 | * float_to_csc_11(float f) | ||
| 185 | * { | ||
| 186 | * u32 exp; | ||
| 187 | * u32 mant; | ||
| 188 | * u32 ret; | ||
| 189 | * | ||
| 190 | * if (f < 0) | ||
| 191 | * f = -f; | ||
| 192 | * | ||
| 193 | * if (f >= 1) { | ||
| 194 | * exp = 0x7; | ||
| 195 | * mant = 1 << 8; | ||
| 196 | * } else { | ||
| 197 | * for (exp = 0; exp < 3 && f < 0.5; exp++) | ||
| 198 | * f *= 2.0; | ||
| 199 | * mant = (f * (1 << 9) + 0.5); | ||
| 200 | * if (mant >= (1 << 9)) | ||
| 201 | * mant = (1 << 9) - 1; | ||
| 202 | * } | ||
| 203 | * ret = (exp << 9) | mant; | ||
| 204 | * return ret; | ||
| 205 | * } | ||
| 206 | */ | ||
| 207 | |||
| 208 | /* | ||
| 209 | * Behold, magic numbers! If we plant them they might grow a big | ||
| 210 | * s-video cable to the sky... or something. | ||
| 211 | * | ||
| 212 | * Pre-converted to appropriate hex value. | ||
| 213 | */ | ||
| 214 | |||
| 215 | /* | ||
| 216 | * PAL & NTSC values for composite & s-video connections | ||
| 217 | */ | ||
| 218 | static const struct color_conversion ntsc_m_csc_composite = { | ||
| 219 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, | ||
| 220 | .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00, | ||
| 221 | .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00, | ||
| 222 | }; | ||
| 223 | |||
| 224 | static const struct video_levels ntsc_m_levels_composite = { | ||
| 225 | .blank = 225, .black = 267, .burst = 113, | ||
| 226 | }; | ||
| 227 | |||
| 228 | static const struct color_conversion ntsc_m_csc_svideo = { | ||
| 229 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134, | ||
| 230 | .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00, | ||
| 231 | .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00, | ||
| 232 | }; | ||
| 233 | |||
| 234 | static const struct video_levels ntsc_m_levels_svideo = { | ||
| 235 | .blank = 266, .black = 316, .burst = 133, | ||
| 236 | }; | ||
| 237 | |||
| 238 | static const struct color_conversion ntsc_j_csc_composite = { | ||
| 239 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119, | ||
| 240 | .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0f00, | ||
| 241 | .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0f00, | ||
| 242 | }; | ||
| 243 | |||
| 244 | static const struct video_levels ntsc_j_levels_composite = { | ||
| 245 | .blank = 225, .black = 225, .burst = 113, | ||
| 246 | }; | ||
| 247 | |||
| 248 | static const struct color_conversion ntsc_j_csc_svideo = { | ||
| 249 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c, | ||
| 250 | .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0f00, | ||
| 251 | .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0f00, | ||
| 252 | }; | ||
| 253 | |||
| 254 | static const struct video_levels ntsc_j_levels_svideo = { | ||
| 255 | .blank = 266, .black = 266, .burst = 133, | ||
| 256 | }; | ||
| 257 | |||
| 258 | static const struct color_conversion pal_csc_composite = { | ||
| 259 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113, | ||
| 260 | .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0f00, | ||
| 261 | .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0f00, | ||
| 262 | }; | ||
| 263 | |||
| 264 | static const struct video_levels pal_levels_composite = { | ||
| 265 | .blank = 237, .black = 237, .burst = 118, | ||
| 266 | }; | ||
| 267 | |||
| 268 | static const struct color_conversion pal_csc_svideo = { | ||
| 269 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145, | ||
| 270 | .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0f00, | ||
| 271 | .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0f00, | ||
| 272 | }; | ||
| 273 | |||
| 274 | static const struct video_levels pal_levels_svideo = { | ||
| 275 | .blank = 280, .black = 280, .burst = 139, | ||
| 276 | }; | ||
| 277 | |||
| 278 | static const struct color_conversion pal_m_csc_composite = { | ||
| 279 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, | ||
| 280 | .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00, | ||
| 281 | .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00, | ||
| 282 | }; | ||
| 283 | |||
| 284 | static const struct video_levels pal_m_levels_composite = { | ||
| 285 | .blank = 225, .black = 267, .burst = 113, | ||
| 286 | }; | ||
| 287 | |||
| 288 | static const struct color_conversion pal_m_csc_svideo = { | ||
| 289 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134, | ||
| 290 | .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00, | ||
| 291 | .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00, | ||
| 292 | }; | ||
| 293 | |||
| 294 | static const struct video_levels pal_m_levels_svideo = { | ||
| 295 | .blank = 266, .black = 316, .burst = 133, | ||
| 296 | }; | ||
| 297 | |||
| 298 | static const struct color_conversion pal_n_csc_composite = { | ||
| 299 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, | ||
| 300 | .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00, | ||
| 301 | .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00, | ||
| 302 | }; | ||
| 303 | |||
| 304 | static const struct video_levels pal_n_levels_composite = { | ||
| 305 | .blank = 225, .black = 267, .burst = 118, | ||
| 306 | }; | ||
| 307 | |||
| 308 | static const struct color_conversion pal_n_csc_svideo = { | ||
| 309 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134, | ||
| 310 | .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00, | ||
| 311 | .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00, | ||
| 312 | }; | ||
| 313 | |||
| 314 | static const struct video_levels pal_n_levels_svideo = { | ||
| 315 | .blank = 266, .black = 316, .burst = 139, | ||
| 316 | }; | ||
| 317 | |||
| 318 | /* | ||
| 319 | * Component connections | ||
| 320 | */ | ||
| 321 | static const struct color_conversion sdtv_csc_yprpb = { | ||
| 322 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0146, | ||
| 323 | .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0f00, | ||
| 324 | .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0f00, | ||
| 325 | }; | ||
| 326 | |||
| 327 | static const struct color_conversion sdtv_csc_rgb = { | ||
| 328 | .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166, | ||
| 329 | .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166, | ||
| 330 | .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166, | ||
| 331 | }; | ||
| 332 | |||
| 333 | static const struct color_conversion hdtv_csc_yprpb = { | ||
| 334 | .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0146, | ||
| 335 | .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0f00, | ||
| 336 | .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0f00, | ||
| 337 | }; | ||
| 338 | |||
| 339 | static const struct color_conversion hdtv_csc_rgb = { | ||
| 340 | .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166, | ||
| 341 | .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166, | ||
| 342 | .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166, | ||
| 343 | }; | ||
| 344 | |||
| 345 | static const struct video_levels component_levels = { | ||
| 346 | .blank = 279, .black = 279, .burst = 0, | ||
| 347 | }; | ||
| 348 | |||
| 349 | |||
| 350 | struct tv_mode { | ||
| 351 | char *name; | ||
| 352 | int clock; | ||
| 353 | int refresh; /* in millihertz (for precision) */ | ||
| 354 | u32 oversample; | ||
| 355 | int hsync_end, hblank_start, hblank_end, htotal; | ||
| 356 | bool progressive, trilevel_sync, component_only; | ||
| 357 | int vsync_start_f1, vsync_start_f2, vsync_len; | ||
| 358 | bool veq_ena; | ||
| 359 | int veq_start_f1, veq_start_f2, veq_len; | ||
| 360 | int vi_end_f1, vi_end_f2, nbr_end; | ||
| 361 | bool burst_ena; | ||
| 362 | int hburst_start, hburst_len; | ||
| 363 | int vburst_start_f1, vburst_end_f1; | ||
| 364 | int vburst_start_f2, vburst_end_f2; | ||
| 365 | int vburst_start_f3, vburst_end_f3; | ||
| 366 | int vburst_start_f4, vburst_end_f4; | ||
| 367 | /* | ||
| 368 | * subcarrier programming | ||
| 369 | */ | ||
| 370 | int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc; | ||
| 371 | u32 sc_reset; | ||
| 372 | bool pal_burst; | ||
| 373 | /* | ||
| 374 | * blank/black levels | ||
| 375 | */ | ||
| 376 | const struct video_levels *composite_levels, *svideo_levels; | ||
| 377 | const struct color_conversion *composite_color, *svideo_color; | ||
| 378 | const u32 *filter_table; | ||
| 379 | int max_srcw; | ||
| 380 | }; | ||
| 381 | |||
| 382 | |||
| 383 | /* | ||
| 384 | * Sub carrier DDA | ||
| 385 | * | ||
| 386 | * I think this works as follows: | ||
| 387 | * | ||
| 388 | * subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096 | ||
| 389 | * | ||
| 390 | * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value | ||
| 391 | * | ||
| 392 | * So, | ||
| 393 | * dda1_ideal = subcarrier/pixel * 4096 | ||
| 394 | * dda1_inc = floor (dda1_ideal) | ||
| 395 | * dda2 = dda1_ideal - dda1_inc | ||
| 396 | * | ||
| 397 | * then pick a ratio for dda2 that gives the closest approximation. If | ||
| 398 | * you can't get close enough, you can play with dda3 as well. This | ||
| 399 | * seems likely to happen when dda2 is small as the jumps would be larger | ||
| 400 | * | ||
| 401 | * To invert this, | ||
| 402 | * | ||
| 403 | * pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size) | ||
| 404 | * | ||
| 405 | * The constants below were all computed using a 107.520MHz clock | ||
| 406 | */ | ||
| 407 | |||
| 408 | /** | ||
| 409 | * Register programming values for TV modes. | ||
| 410 | * | ||
| 411 | * These values account for -1s required. | ||
| 412 | */ | ||
| 413 | |||
| 414 | const static struct tv_mode tv_modes[] = { | ||
| 415 | { | ||
| 416 | .name = "NTSC-M", | ||
| 417 | .clock = 107520, | ||
| 418 | .refresh = 29970, | ||
| 419 | .oversample = TV_OVERSAMPLE_8X, | ||
| 420 | .component_only = 0, | ||
| 421 | /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ | ||
| 422 | |||
| 423 | .hsync_end = 64, .hblank_end = 124, | ||
| 424 | .hblank_start = 836, .htotal = 857, | ||
| 425 | |||
| 426 | .progressive = false, .trilevel_sync = false, | ||
| 427 | |||
| 428 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, | ||
| 429 | .vsync_len = 6, | ||
| 430 | |||
| 431 | .veq_ena = true, .veq_start_f1 = 0, | ||
| 432 | .veq_start_f2 = 1, .veq_len = 18, | ||
| 433 | |||
| 434 | .vi_end_f1 = 20, .vi_end_f2 = 21, | ||
| 435 | .nbr_end = 240, | ||
| 436 | |||
| 437 | .burst_ena = true, | ||
| 438 | .hburst_start = 72, .hburst_len = 34, | ||
| 439 | .vburst_start_f1 = 9, .vburst_end_f1 = 240, | ||
| 440 | .vburst_start_f2 = 10, .vburst_end_f2 = 240, | ||
| 441 | .vburst_start_f3 = 9, .vburst_end_f3 = 240, | ||
| 442 | .vburst_start_f4 = 10, .vburst_end_f4 = 240, | ||
| 443 | |||
| 444 | /* desired 3.5800000 actual 3.5800000 clock 107.52 */ | ||
| 445 | .dda1_inc = 136, | ||
| 446 | .dda2_inc = 7624, .dda2_size = 20013, | ||
| 447 | .dda3_inc = 0, .dda3_size = 0, | ||
| 448 | .sc_reset = TV_SC_RESET_EVERY_4, | ||
| 449 | .pal_burst = false, | ||
| 450 | |||
| 451 | .composite_levels = &ntsc_m_levels_composite, | ||
| 452 | .composite_color = &ntsc_m_csc_composite, | ||
| 453 | .svideo_levels = &ntsc_m_levels_svideo, | ||
| 454 | .svideo_color = &ntsc_m_csc_svideo, | ||
| 455 | |||
| 456 | .filter_table = filter_table, | ||
| 457 | }, | ||
| 458 | { | ||
| 459 | .name = "NTSC-443", | ||
| 460 | .clock = 107520, | ||
| 461 | .refresh = 29970, | ||
| 462 | .oversample = TV_OVERSAMPLE_8X, | ||
| 463 | .component_only = 0, | ||
| 464 | /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */ | ||
| 465 | .hsync_end = 64, .hblank_end = 124, | ||
| 466 | .hblank_start = 836, .htotal = 857, | ||
| 467 | |||
| 468 | .progressive = false, .trilevel_sync = false, | ||
| 469 | |||
| 470 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, | ||
| 471 | .vsync_len = 6, | ||
| 472 | |||
| 473 | .veq_ena = true, .veq_start_f1 = 0, | ||
| 474 | .veq_start_f2 = 1, .veq_len = 18, | ||
| 475 | |||
| 476 | .vi_end_f1 = 20, .vi_end_f2 = 21, | ||
| 477 | .nbr_end = 240, | ||
| 478 | |||
| 479 | .burst_ena = 8, | ||
| 480 | .hburst_start = 72, .hburst_len = 34, | ||
| 481 | .vburst_start_f1 = 9, .vburst_end_f1 = 240, | ||
| 482 | .vburst_start_f2 = 10, .vburst_end_f2 = 240, | ||
| 483 | .vburst_start_f3 = 9, .vburst_end_f3 = 240, | ||
| 484 | .vburst_start_f4 = 10, .vburst_end_f4 = 240, | ||
| 485 | |||
| 486 | /* desired 4.4336180 actual 4.4336180 clock 107.52 */ | ||
| 487 | .dda1_inc = 168, | ||
| 488 | .dda2_inc = 18557, .dda2_size = 20625, | ||
| 489 | .dda3_inc = 0, .dda3_size = 0, | ||
| 490 | .sc_reset = TV_SC_RESET_EVERY_8, | ||
| 491 | .pal_burst = true, | ||
| 492 | |||
| 493 | .composite_levels = &ntsc_m_levels_composite, | ||
| 494 | .composite_color = &ntsc_m_csc_composite, | ||
| 495 | .svideo_levels = &ntsc_m_levels_svideo, | ||
| 496 | .svideo_color = &ntsc_m_csc_svideo, | ||
| 497 | |||
| 498 | .filter_table = filter_table, | ||
| 499 | }, | ||
| 500 | { | ||
| 501 | .name = "NTSC-J", | ||
| 502 | .clock = 107520, | ||
| 503 | .refresh = 29970, | ||
| 504 | .oversample = TV_OVERSAMPLE_8X, | ||
| 505 | .component_only = 0, | ||
| 506 | |||
| 507 | /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ | ||
| 508 | .hsync_end = 64, .hblank_end = 124, | ||
| 509 | .hblank_start = 836, .htotal = 857, | ||
| 510 | |||
| 511 | .progressive = false, .trilevel_sync = false, | ||
| 512 | |||
| 513 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, | ||
| 514 | .vsync_len = 6, | ||
| 515 | |||
| 516 | .veq_ena = true, .veq_start_f1 = 0, | ||
| 517 | .veq_start_f2 = 1, .veq_len = 18, | ||
| 518 | |||
| 519 | .vi_end_f1 = 20, .vi_end_f2 = 21, | ||
| 520 | .nbr_end = 240, | ||
| 521 | |||
| 522 | .burst_ena = true, | ||
| 523 | .hburst_start = 72, .hburst_len = 34, | ||
| 524 | .vburst_start_f1 = 9, .vburst_end_f1 = 240, | ||
| 525 | .vburst_start_f2 = 10, .vburst_end_f2 = 240, | ||
| 526 | .vburst_start_f3 = 9, .vburst_end_f3 = 240, | ||
| 527 | .vburst_start_f4 = 10, .vburst_end_f4 = 240, | ||
| 528 | |||
| 529 | /* desired 3.5800000 actual 3.5800000 clock 107.52 */ | ||
| 530 | .dda1_inc = 136, | ||
| 531 | .dda2_inc = 7624, .dda2_size = 20013, | ||
| 532 | .dda3_inc = 0, .dda3_size = 0, | ||
| 533 | .sc_reset = TV_SC_RESET_EVERY_4, | ||
| 534 | .pal_burst = false, | ||
| 535 | |||
| 536 | .composite_levels = &ntsc_j_levels_composite, | ||
| 537 | .composite_color = &ntsc_j_csc_composite, | ||
| 538 | .svideo_levels = &ntsc_j_levels_svideo, | ||
| 539 | .svideo_color = &ntsc_j_csc_svideo, | ||
| 540 | |||
| 541 | .filter_table = filter_table, | ||
| 542 | }, | ||
| 543 | { | ||
| 544 | .name = "PAL-M", | ||
| 545 | .clock = 107520, | ||
| 546 | .refresh = 29970, | ||
| 547 | .oversample = TV_OVERSAMPLE_8X, | ||
| 548 | .component_only = 0, | ||
| 549 | |||
| 550 | /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ | ||
| 551 | .hsync_end = 64, .hblank_end = 124, | ||
| 552 | .hblank_start = 836, .htotal = 857, | ||
| 553 | |||
| 554 | .progressive = false, .trilevel_sync = false, | ||
| 555 | |||
| 556 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, | ||
| 557 | .vsync_len = 6, | ||
| 558 | |||
| 559 | .veq_ena = true, .veq_start_f1 = 0, | ||
| 560 | .veq_start_f2 = 1, .veq_len = 18, | ||
| 561 | |||
| 562 | .vi_end_f1 = 20, .vi_end_f2 = 21, | ||
| 563 | .nbr_end = 240, | ||
| 564 | |||
| 565 | .burst_ena = true, | ||
| 566 | .hburst_start = 72, .hburst_len = 34, | ||
| 567 | .vburst_start_f1 = 9, .vburst_end_f1 = 240, | ||
| 568 | .vburst_start_f2 = 10, .vburst_end_f2 = 240, | ||
| 569 | .vburst_start_f3 = 9, .vburst_end_f3 = 240, | ||
| 570 | .vburst_start_f4 = 10, .vburst_end_f4 = 240, | ||
| 571 | |||
| 572 | /* desired 3.5800000 actual 3.5800000 clock 107.52 */ | ||
| 573 | .dda1_inc = 136, | ||
| 574 | .dda2_inc = 7624, .dda2_size = 20013, | ||
| 575 | .dda3_inc = 0, .dda3_size = 0, | ||
| 576 | .sc_reset = TV_SC_RESET_EVERY_4, | ||
| 577 | .pal_burst = false, | ||
| 578 | |||
| 579 | .composite_levels = &pal_m_levels_composite, | ||
| 580 | .composite_color = &pal_m_csc_composite, | ||
| 581 | .svideo_levels = &pal_m_levels_svideo, | ||
| 582 | .svideo_color = &pal_m_csc_svideo, | ||
| 583 | |||
| 584 | .filter_table = filter_table, | ||
| 585 | }, | ||
| 586 | { | ||
| 587 | /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */ | ||
| 588 | .name = "PAL-N", | ||
| 589 | .clock = 107520, | ||
| 590 | .refresh = 25000, | ||
| 591 | .oversample = TV_OVERSAMPLE_8X, | ||
| 592 | .component_only = 0, | ||
| 593 | |||
| 594 | .hsync_end = 64, .hblank_end = 128, | ||
| 595 | .hblank_start = 844, .htotal = 863, | ||
| 596 | |||
| 597 | .progressive = false, .trilevel_sync = false, | ||
| 598 | |||
| 599 | |||
| 600 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, | ||
| 601 | .vsync_len = 6, | ||
| 602 | |||
| 603 | .veq_ena = true, .veq_start_f1 = 0, | ||
| 604 | .veq_start_f2 = 1, .veq_len = 18, | ||
| 605 | |||
| 606 | .vi_end_f1 = 24, .vi_end_f2 = 25, | ||
| 607 | .nbr_end = 286, | ||
| 608 | |||
| 609 | .burst_ena = true, | ||
| 610 | .hburst_start = 73, .hburst_len = 34, | ||
| 611 | .vburst_start_f1 = 8, .vburst_end_f1 = 285, | ||
| 612 | .vburst_start_f2 = 8, .vburst_end_f2 = 286, | ||
| 613 | .vburst_start_f3 = 9, .vburst_end_f3 = 286, | ||
| 614 | .vburst_start_f4 = 9, .vburst_end_f4 = 285, | ||
| 615 | |||
| 616 | |||
| 617 | /* desired 4.4336180 actual 4.4336180 clock 107.52 */ | ||
| 618 | .dda1_inc = 168, | ||
| 619 | .dda2_inc = 18557, .dda2_size = 20625, | ||
| 620 | .dda3_inc = 0, .dda3_size = 0, | ||
| 621 | .sc_reset = TV_SC_RESET_EVERY_8, | ||
| 622 | .pal_burst = true, | ||
| 623 | |||
| 624 | .composite_levels = &pal_n_levels_composite, | ||
| 625 | .composite_color = &pal_n_csc_composite, | ||
| 626 | .svideo_levels = &pal_n_levels_svideo, | ||
| 627 | .svideo_color = &pal_n_csc_svideo, | ||
| 628 | |||
| 629 | .filter_table = filter_table, | ||
| 630 | }, | ||
| 631 | { | ||
| 632 | /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */ | ||
| 633 | .name = "PAL", | ||
| 634 | .clock = 107520, | ||
| 635 | .refresh = 25000, | ||
| 636 | .oversample = TV_OVERSAMPLE_8X, | ||
| 637 | .component_only = 0, | ||
| 638 | |||
| 639 | .hsync_end = 64, .hblank_end = 128, | ||
| 640 | .hblank_start = 844, .htotal = 863, | ||
| 641 | |||
| 642 | .progressive = false, .trilevel_sync = false, | ||
| 643 | |||
| 644 | .vsync_start_f1 = 5, .vsync_start_f2 = 6, | ||
| 645 | .vsync_len = 5, | ||
| 646 | |||
| 647 | .veq_ena = true, .veq_start_f1 = 0, | ||
| 648 | .veq_start_f2 = 1, .veq_len = 15, | ||
| 649 | |||
| 650 | .vi_end_f1 = 24, .vi_end_f2 = 25, | ||
| 651 | .nbr_end = 286, | ||
| 652 | |||
| 653 | .burst_ena = true, | ||
| 654 | .hburst_start = 73, .hburst_len = 32, | ||
| 655 | .vburst_start_f1 = 8, .vburst_end_f1 = 285, | ||
| 656 | .vburst_start_f2 = 8, .vburst_end_f2 = 286, | ||
| 657 | .vburst_start_f3 = 9, .vburst_end_f3 = 286, | ||
| 658 | .vburst_start_f4 = 9, .vburst_end_f4 = 285, | ||
| 659 | |||
| 660 | /* desired 4.4336180 actual 4.4336180 clock 107.52 */ | ||
| 661 | .dda1_inc = 168, | ||
| 662 | .dda2_inc = 18557, .dda2_size = 20625, | ||
| 663 | .dda3_inc = 0, .dda3_size = 0, | ||
| 664 | .sc_reset = TV_SC_RESET_EVERY_8, | ||
| 665 | .pal_burst = true, | ||
| 666 | |||
| 667 | .composite_levels = &pal_levels_composite, | ||
| 668 | .composite_color = &pal_csc_composite, | ||
| 669 | .svideo_levels = &pal_levels_svideo, | ||
| 670 | .svideo_color = &pal_csc_svideo, | ||
| 671 | |||
| 672 | .filter_table = filter_table, | ||
| 673 | }, | ||
| 674 | { | ||
| 675 | .name = "480p@59.94Hz", | ||
| 676 | .clock = 107520, | ||
| 677 | .refresh = 59940, | ||
| 678 | .oversample = TV_OVERSAMPLE_4X, | ||
| 679 | .component_only = 1, | ||
| 680 | |||
| 681 | .hsync_end = 64, .hblank_end = 122, | ||
| 682 | .hblank_start = 842, .htotal = 857, | ||
| 683 | |||
| 684 | .progressive = true,.trilevel_sync = false, | ||
| 685 | |||
| 686 | .vsync_start_f1 = 12, .vsync_start_f2 = 12, | ||
| 687 | .vsync_len = 12, | ||
| 688 | |||
| 689 | .veq_ena = false, | ||
| 690 | |||
| 691 | .vi_end_f1 = 44, .vi_end_f2 = 44, | ||
| 692 | .nbr_end = 496, | ||
| 693 | |||
| 694 | .burst_ena = false, | ||
| 695 | |||
| 696 | .filter_table = filter_table, | ||
| 697 | }, | ||
| 698 | { | ||
| 699 | .name = "480p@60Hz", | ||
| 700 | .clock = 107520, | ||
| 701 | .refresh = 60000, | ||
| 702 | .oversample = TV_OVERSAMPLE_4X, | ||
| 703 | .component_only = 1, | ||
| 704 | |||
| 705 | .hsync_end = 64, .hblank_end = 122, | ||
| 706 | .hblank_start = 842, .htotal = 856, | ||
| 707 | |||
| 708 | .progressive = true,.trilevel_sync = false, | ||
| 709 | |||
| 710 | .vsync_start_f1 = 12, .vsync_start_f2 = 12, | ||
| 711 | .vsync_len = 12, | ||
| 712 | |||
| 713 | .veq_ena = false, | ||
| 714 | |||
| 715 | .vi_end_f1 = 44, .vi_end_f2 = 44, | ||
| 716 | .nbr_end = 496, | ||
| 717 | |||
| 718 | .burst_ena = false, | ||
| 719 | |||
| 720 | .filter_table = filter_table, | ||
| 721 | }, | ||
| 722 | { | ||
| 723 | .name = "576p", | ||
| 724 | .clock = 107520, | ||
| 725 | .refresh = 50000, | ||
| 726 | .oversample = TV_OVERSAMPLE_4X, | ||
| 727 | .component_only = 1, | ||
| 728 | |||
| 729 | .hsync_end = 64, .hblank_end = 139, | ||
| 730 | .hblank_start = 859, .htotal = 863, | ||
| 731 | |||
| 732 | .progressive = true, .trilevel_sync = false, | ||
| 733 | |||
| 734 | .vsync_start_f1 = 10, .vsync_start_f2 = 10, | ||
| 735 | .vsync_len = 10, | ||
| 736 | |||
| 737 | .veq_ena = false, | ||
| 738 | |||
| 739 | .vi_end_f1 = 48, .vi_end_f2 = 48, | ||
| 740 | .nbr_end = 575, | ||
| 741 | |||
| 742 | .burst_ena = false, | ||
| 743 | |||
| 744 | .filter_table = filter_table, | ||
| 745 | }, | ||
| 746 | { | ||
| 747 | .name = "720p@60Hz", | ||
| 748 | .clock = 148800, | ||
| 749 | .refresh = 60000, | ||
| 750 | .oversample = TV_OVERSAMPLE_2X, | ||
| 751 | .component_only = 1, | ||
| 752 | |||
| 753 | .hsync_end = 80, .hblank_end = 300, | ||
| 754 | .hblank_start = 1580, .htotal = 1649, | ||
| 755 | |||
| 756 | .progressive = true, .trilevel_sync = true, | ||
| 757 | |||
| 758 | .vsync_start_f1 = 10, .vsync_start_f2 = 10, | ||
| 759 | .vsync_len = 10, | ||
| 760 | |||
| 761 | .veq_ena = false, | ||
| 762 | |||
| 763 | .vi_end_f1 = 29, .vi_end_f2 = 29, | ||
| 764 | .nbr_end = 719, | ||
| 765 | |||
| 766 | .burst_ena = false, | ||
| 767 | |||
| 768 | .filter_table = filter_table, | ||
| 769 | }, | ||
| 770 | { | ||
| 771 | .name = "720p@59.94Hz", | ||
| 772 | .clock = 148800, | ||
| 773 | .refresh = 59940, | ||
| 774 | .oversample = TV_OVERSAMPLE_2X, | ||
| 775 | .component_only = 1, | ||
| 776 | |||
| 777 | .hsync_end = 80, .hblank_end = 300, | ||
| 778 | .hblank_start = 1580, .htotal = 1651, | ||
| 779 | |||
| 780 | .progressive = true, .trilevel_sync = true, | ||
| 781 | |||
| 782 | .vsync_start_f1 = 10, .vsync_start_f2 = 10, | ||
| 783 | .vsync_len = 10, | ||
| 784 | |||
| 785 | .veq_ena = false, | ||
| 786 | |||
| 787 | .vi_end_f1 = 29, .vi_end_f2 = 29, | ||
| 788 | .nbr_end = 719, | ||
| 789 | |||
| 790 | .burst_ena = false, | ||
| 791 | |||
| 792 | .filter_table = filter_table, | ||
| 793 | }, | ||
| 794 | { | ||
| 795 | .name = "720p@50Hz", | ||
| 796 | .clock = 148800, | ||
| 797 | .refresh = 50000, | ||
| 798 | .oversample = TV_OVERSAMPLE_2X, | ||
| 799 | .component_only = 1, | ||
| 800 | |||
| 801 | .hsync_end = 80, .hblank_end = 300, | ||
| 802 | .hblank_start = 1580, .htotal = 1979, | ||
| 803 | |||
| 804 | .progressive = true, .trilevel_sync = true, | ||
| 805 | |||
| 806 | .vsync_start_f1 = 10, .vsync_start_f2 = 10, | ||
| 807 | .vsync_len = 10, | ||
| 808 | |||
| 809 | .veq_ena = false, | ||
| 810 | |||
| 811 | .vi_end_f1 = 29, .vi_end_f2 = 29, | ||
| 812 | .nbr_end = 719, | ||
| 813 | |||
| 814 | .burst_ena = false, | ||
| 815 | |||
| 816 | .filter_table = filter_table, | ||
| 817 | .max_srcw = 800 | ||
| 818 | }, | ||
| 819 | { | ||
| 820 | .name = "1080i@50Hz", | ||
| 821 | .clock = 148800, | ||
| 822 | .refresh = 25000, | ||
| 823 | .oversample = TV_OVERSAMPLE_2X, | ||
| 824 | .component_only = 1, | ||
| 825 | |||
| 826 | .hsync_end = 88, .hblank_end = 235, | ||
| 827 | .hblank_start = 2155, .htotal = 2639, | ||
| 828 | |||
| 829 | .progressive = false, .trilevel_sync = true, | ||
| 830 | |||
| 831 | .vsync_start_f1 = 4, .vsync_start_f2 = 5, | ||
| 832 | .vsync_len = 10, | ||
| 833 | |||
| 834 | .veq_ena = true, .veq_start_f1 = 4, | ||
| 835 | .veq_start_f2 = 4, .veq_len = 10, | ||
| 836 | |||
| 837 | |||
| 838 | .vi_end_f1 = 21, .vi_end_f2 = 22, | ||
| 839 | .nbr_end = 539, | ||
| 840 | |||
| 841 | .burst_ena = false, | ||
| 842 | |||
| 843 | .filter_table = filter_table, | ||
| 844 | }, | ||
| 845 | { | ||
| 846 | .name = "1080i@60Hz", | ||
| 847 | .clock = 148800, | ||
| 848 | .refresh = 30000, | ||
| 849 | .oversample = TV_OVERSAMPLE_2X, | ||
| 850 | .component_only = 1, | ||
| 851 | |||
| 852 | .hsync_end = 88, .hblank_end = 235, | ||
| 853 | .hblank_start = 2155, .htotal = 2199, | ||
| 854 | |||
| 855 | .progressive = false, .trilevel_sync = true, | ||
| 856 | |||
| 857 | .vsync_start_f1 = 4, .vsync_start_f2 = 5, | ||
| 858 | .vsync_len = 10, | ||
| 859 | |||
| 860 | .veq_ena = true, .veq_start_f1 = 4, | ||
| 861 | .veq_start_f2 = 4, .veq_len = 10, | ||
| 862 | |||
| 863 | |||
| 864 | .vi_end_f1 = 21, .vi_end_f2 = 22, | ||
| 865 | .nbr_end = 539, | ||
| 866 | |||
| 867 | .burst_ena = false, | ||
| 868 | |||
| 869 | .filter_table = filter_table, | ||
| 870 | }, | ||
| 871 | { | ||
| 872 | .name = "1080i@59.94Hz", | ||
| 873 | .clock = 148800, | ||
| 874 | .refresh = 29970, | ||
| 875 | .oversample = TV_OVERSAMPLE_2X, | ||
| 876 | .component_only = 1, | ||
| 877 | |||
| 878 | .hsync_end = 88, .hblank_end = 235, | ||
| 879 | .hblank_start = 2155, .htotal = 2200, | ||
| 880 | |||
| 881 | .progressive = false, .trilevel_sync = true, | ||
| 882 | |||
| 883 | .vsync_start_f1 = 4, .vsync_start_f2 = 5, | ||
| 884 | .vsync_len = 10, | ||
| 885 | |||
| 886 | .veq_ena = true, .veq_start_f1 = 4, | ||
| 887 | .veq_start_f2 = 4, .veq_len = 10, | ||
| 888 | |||
| 889 | |||
| 890 | .vi_end_f1 = 21, .vi_end_f2 = 22, | ||
| 891 | .nbr_end = 539, | ||
| 892 | |||
| 893 | .burst_ena = false, | ||
| 894 | |||
| 895 | .filter_table = filter_table, | ||
| 896 | }, | ||
| 897 | }; | ||
| 898 | |||
| 899 | #define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0]) | ||
| 900 | |||
| 901 | static void | ||
| 902 | intel_tv_dpms(struct drm_encoder *encoder, int mode) | ||
| 903 | { | ||
| 904 | struct drm_device *dev = encoder->dev; | ||
| 905 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 906 | |||
| 907 | switch(mode) { | ||
| 908 | case DRM_MODE_DPMS_ON: | ||
| 909 | I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE); | ||
| 910 | break; | ||
| 911 | case DRM_MODE_DPMS_STANDBY: | ||
| 912 | case DRM_MODE_DPMS_SUSPEND: | ||
| 913 | case DRM_MODE_DPMS_OFF: | ||
| 914 | I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE); | ||
| 915 | break; | ||
| 916 | } | ||
| 917 | } | ||
| 918 | |||
| 919 | static void | ||
| 920 | intel_tv_save(struct drm_connector *connector) | ||
| 921 | { | ||
| 922 | struct drm_device *dev = connector->dev; | ||
| 923 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 924 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 925 | struct intel_tv_priv *tv_priv = intel_output->dev_priv; | ||
| 926 | int i; | ||
| 927 | |||
| 928 | tv_priv->save_TV_H_CTL_1 = I915_READ(TV_H_CTL_1); | ||
| 929 | tv_priv->save_TV_H_CTL_2 = I915_READ(TV_H_CTL_2); | ||
| 930 | tv_priv->save_TV_H_CTL_3 = I915_READ(TV_H_CTL_3); | ||
| 931 | tv_priv->save_TV_V_CTL_1 = I915_READ(TV_V_CTL_1); | ||
| 932 | tv_priv->save_TV_V_CTL_2 = I915_READ(TV_V_CTL_2); | ||
| 933 | tv_priv->save_TV_V_CTL_3 = I915_READ(TV_V_CTL_3); | ||
| 934 | tv_priv->save_TV_V_CTL_4 = I915_READ(TV_V_CTL_4); | ||
| 935 | tv_priv->save_TV_V_CTL_5 = I915_READ(TV_V_CTL_5); | ||
| 936 | tv_priv->save_TV_V_CTL_6 = I915_READ(TV_V_CTL_6); | ||
| 937 | tv_priv->save_TV_V_CTL_7 = I915_READ(TV_V_CTL_7); | ||
| 938 | tv_priv->save_TV_SC_CTL_1 = I915_READ(TV_SC_CTL_1); | ||
| 939 | tv_priv->save_TV_SC_CTL_2 = I915_READ(TV_SC_CTL_2); | ||
| 940 | tv_priv->save_TV_SC_CTL_3 = I915_READ(TV_SC_CTL_3); | ||
| 941 | |||
| 942 | tv_priv->save_TV_CSC_Y = I915_READ(TV_CSC_Y); | ||
| 943 | tv_priv->save_TV_CSC_Y2 = I915_READ(TV_CSC_Y2); | ||
| 944 | tv_priv->save_TV_CSC_U = I915_READ(TV_CSC_U); | ||
| 945 | tv_priv->save_TV_CSC_U2 = I915_READ(TV_CSC_U2); | ||
| 946 | tv_priv->save_TV_CSC_V = I915_READ(TV_CSC_V); | ||
| 947 | tv_priv->save_TV_CSC_V2 = I915_READ(TV_CSC_V2); | ||
| 948 | tv_priv->save_TV_CLR_KNOBS = I915_READ(TV_CLR_KNOBS); | ||
| 949 | tv_priv->save_TV_CLR_LEVEL = I915_READ(TV_CLR_LEVEL); | ||
| 950 | tv_priv->save_TV_WIN_POS = I915_READ(TV_WIN_POS); | ||
| 951 | tv_priv->save_TV_WIN_SIZE = I915_READ(TV_WIN_SIZE); | ||
| 952 | tv_priv->save_TV_FILTER_CTL_1 = I915_READ(TV_FILTER_CTL_1); | ||
| 953 | tv_priv->save_TV_FILTER_CTL_2 = I915_READ(TV_FILTER_CTL_2); | ||
| 954 | tv_priv->save_TV_FILTER_CTL_3 = I915_READ(TV_FILTER_CTL_3); | ||
| 955 | |||
| 956 | for (i = 0; i < 60; i++) | ||
| 957 | tv_priv->save_TV_H_LUMA[i] = I915_READ(TV_H_LUMA_0 + (i <<2)); | ||
| 958 | for (i = 0; i < 60; i++) | ||
| 959 | tv_priv->save_TV_H_CHROMA[i] = I915_READ(TV_H_CHROMA_0 + (i <<2)); | ||
| 960 | for (i = 0; i < 43; i++) | ||
| 961 | tv_priv->save_TV_V_LUMA[i] = I915_READ(TV_V_LUMA_0 + (i <<2)); | ||
| 962 | for (i = 0; i < 43; i++) | ||
| 963 | tv_priv->save_TV_V_CHROMA[i] = I915_READ(TV_V_CHROMA_0 + (i <<2)); | ||
| 964 | |||
| 965 | tv_priv->save_TV_DAC = I915_READ(TV_DAC); | ||
| 966 | tv_priv->save_TV_CTL = I915_READ(TV_CTL); | ||
| 967 | } | ||
| 968 | |||
| 969 | static void | ||
| 970 | intel_tv_restore(struct drm_connector *connector) | ||
| 971 | { | ||
| 972 | struct drm_device *dev = connector->dev; | ||
| 973 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 974 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 975 | struct intel_tv_priv *tv_priv = intel_output->dev_priv; | ||
| 976 | struct drm_crtc *crtc = connector->encoder->crtc; | ||
| 977 | struct intel_crtc *intel_crtc; | ||
| 978 | int i; | ||
| 979 | |||
| 980 | /* FIXME: No CRTC? */ | ||
| 981 | if (!crtc) | ||
| 982 | return; | ||
| 983 | |||
| 984 | intel_crtc = to_intel_crtc(crtc); | ||
| 985 | I915_WRITE(TV_H_CTL_1, tv_priv->save_TV_H_CTL_1); | ||
| 986 | I915_WRITE(TV_H_CTL_2, tv_priv->save_TV_H_CTL_2); | ||
| 987 | I915_WRITE(TV_H_CTL_3, tv_priv->save_TV_H_CTL_3); | ||
| 988 | I915_WRITE(TV_V_CTL_1, tv_priv->save_TV_V_CTL_1); | ||
| 989 | I915_WRITE(TV_V_CTL_2, tv_priv->save_TV_V_CTL_2); | ||
| 990 | I915_WRITE(TV_V_CTL_3, tv_priv->save_TV_V_CTL_3); | ||
| 991 | I915_WRITE(TV_V_CTL_4, tv_priv->save_TV_V_CTL_4); | ||
| 992 | I915_WRITE(TV_V_CTL_5, tv_priv->save_TV_V_CTL_5); | ||
| 993 | I915_WRITE(TV_V_CTL_6, tv_priv->save_TV_V_CTL_6); | ||
| 994 | I915_WRITE(TV_V_CTL_7, tv_priv->save_TV_V_CTL_7); | ||
| 995 | I915_WRITE(TV_SC_CTL_1, tv_priv->save_TV_SC_CTL_1); | ||
| 996 | I915_WRITE(TV_SC_CTL_2, tv_priv->save_TV_SC_CTL_2); | ||
| 997 | I915_WRITE(TV_SC_CTL_3, tv_priv->save_TV_SC_CTL_3); | ||
| 998 | |||
| 999 | I915_WRITE(TV_CSC_Y, tv_priv->save_TV_CSC_Y); | ||
| 1000 | I915_WRITE(TV_CSC_Y2, tv_priv->save_TV_CSC_Y2); | ||
| 1001 | I915_WRITE(TV_CSC_U, tv_priv->save_TV_CSC_U); | ||
| 1002 | I915_WRITE(TV_CSC_U2, tv_priv->save_TV_CSC_U2); | ||
| 1003 | I915_WRITE(TV_CSC_V, tv_priv->save_TV_CSC_V); | ||
| 1004 | I915_WRITE(TV_CSC_V2, tv_priv->save_TV_CSC_V2); | ||
| 1005 | I915_WRITE(TV_CLR_KNOBS, tv_priv->save_TV_CLR_KNOBS); | ||
| 1006 | I915_WRITE(TV_CLR_LEVEL, tv_priv->save_TV_CLR_LEVEL); | ||
| 1007 | |||
| 1008 | { | ||
| 1009 | int pipeconf_reg = (intel_crtc->pipe == 0) ? | ||
| 1010 | PIPEACONF : PIPEBCONF; | ||
| 1011 | int dspcntr_reg = (intel_crtc->plane == 0) ? | ||
| 1012 | DSPACNTR : DSPBCNTR; | ||
| 1013 | int pipeconf = I915_READ(pipeconf_reg); | ||
| 1014 | int dspcntr = I915_READ(dspcntr_reg); | ||
| 1015 | int dspbase_reg = (intel_crtc->plane == 0) ? | ||
| 1016 | DSPAADDR : DSPBADDR; | ||
| 1017 | /* Pipe must be off here */ | ||
| 1018 | I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); | ||
| 1019 | /* Flush the plane changes */ | ||
| 1020 | I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); | ||
| 1021 | |||
| 1022 | if (!IS_I9XX(dev)) { | ||
| 1023 | /* Wait for vblank for the disable to take effect */ | ||
| 1024 | intel_wait_for_vblank(dev); | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); | ||
| 1028 | /* Wait for vblank for the disable to take effect. */ | ||
| 1029 | intel_wait_for_vblank(dev); | ||
| 1030 | |||
| 1031 | /* Filter ctl must be set before TV_WIN_SIZE */ | ||
| 1032 | I915_WRITE(TV_FILTER_CTL_1, tv_priv->save_TV_FILTER_CTL_1); | ||
| 1033 | I915_WRITE(TV_FILTER_CTL_2, tv_priv->save_TV_FILTER_CTL_2); | ||
| 1034 | I915_WRITE(TV_FILTER_CTL_3, tv_priv->save_TV_FILTER_CTL_3); | ||
| 1035 | I915_WRITE(TV_WIN_POS, tv_priv->save_TV_WIN_POS); | ||
| 1036 | I915_WRITE(TV_WIN_SIZE, tv_priv->save_TV_WIN_SIZE); | ||
| 1037 | I915_WRITE(pipeconf_reg, pipeconf); | ||
| 1038 | I915_WRITE(dspcntr_reg, dspcntr); | ||
| 1039 | /* Flush the plane changes */ | ||
| 1040 | I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | for (i = 0; i < 60; i++) | ||
| 1044 | I915_WRITE(TV_H_LUMA_0 + (i <<2), tv_priv->save_TV_H_LUMA[i]); | ||
| 1045 | for (i = 0; i < 60; i++) | ||
| 1046 | I915_WRITE(TV_H_CHROMA_0 + (i <<2), tv_priv->save_TV_H_CHROMA[i]); | ||
| 1047 | for (i = 0; i < 43; i++) | ||
| 1048 | I915_WRITE(TV_V_LUMA_0 + (i <<2), tv_priv->save_TV_V_LUMA[i]); | ||
| 1049 | for (i = 0; i < 43; i++) | ||
| 1050 | I915_WRITE(TV_V_CHROMA_0 + (i <<2), tv_priv->save_TV_V_CHROMA[i]); | ||
| 1051 | |||
| 1052 | I915_WRITE(TV_DAC, tv_priv->save_TV_DAC); | ||
| 1053 | I915_WRITE(TV_CTL, tv_priv->save_TV_CTL); | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | static const struct tv_mode * | ||
| 1057 | intel_tv_mode_lookup (char *tv_format) | ||
| 1058 | { | ||
| 1059 | int i; | ||
| 1060 | |||
| 1061 | for (i = 0; i < sizeof(tv_modes) / sizeof (tv_modes[0]); i++) { | ||
| 1062 | const struct tv_mode *tv_mode = &tv_modes[i]; | ||
| 1063 | |||
| 1064 | if (!strcmp(tv_format, tv_mode->name)) | ||
| 1065 | return tv_mode; | ||
| 1066 | } | ||
| 1067 | return NULL; | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | static const struct tv_mode * | ||
| 1071 | intel_tv_mode_find (struct intel_output *intel_output) | ||
| 1072 | { | ||
| 1073 | struct intel_tv_priv *tv_priv = intel_output->dev_priv; | ||
| 1074 | |||
| 1075 | return intel_tv_mode_lookup(tv_priv->tv_format); | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | static enum drm_mode_status | ||
| 1079 | intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) | ||
| 1080 | { | ||
| 1081 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 1082 | const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output); | ||
| 1083 | |||
| 1084 | /* Ensure TV refresh is close to desired refresh */ | ||
| 1085 | if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 1) | ||
| 1086 | return MODE_OK; | ||
| 1087 | return MODE_CLOCK_RANGE; | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | |||
| 1091 | static bool | ||
| 1092 | intel_tv_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, | ||
| 1093 | struct drm_display_mode *adjusted_mode) | ||
| 1094 | { | ||
| 1095 | struct drm_device *dev = encoder->dev; | ||
| 1096 | struct drm_mode_config *drm_config = &dev->mode_config; | ||
| 1097 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
| 1098 | const struct tv_mode *tv_mode = intel_tv_mode_find (intel_output); | ||
| 1099 | struct drm_encoder *other_encoder; | ||
| 1100 | |||
| 1101 | if (!tv_mode) | ||
| 1102 | return false; | ||
| 1103 | |||
| 1104 | /* FIXME: lock encoder list */ | ||
| 1105 | list_for_each_entry(other_encoder, &drm_config->encoder_list, head) { | ||
| 1106 | if (other_encoder != encoder && | ||
| 1107 | other_encoder->crtc == encoder->crtc) | ||
| 1108 | return false; | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | adjusted_mode->clock = tv_mode->clock; | ||
| 1112 | return true; | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | static void | ||
| 1116 | intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, | ||
| 1117 | struct drm_display_mode *adjusted_mode) | ||
| 1118 | { | ||
| 1119 | struct drm_device *dev = encoder->dev; | ||
| 1120 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 1121 | struct drm_crtc *crtc = encoder->crtc; | ||
| 1122 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
| 1123 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
| 1124 | struct intel_tv_priv *tv_priv = intel_output->dev_priv; | ||
| 1125 | const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output); | ||
| 1126 | u32 tv_ctl; | ||
| 1127 | u32 hctl1, hctl2, hctl3; | ||
| 1128 | u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7; | ||
| 1129 | u32 scctl1, scctl2, scctl3; | ||
| 1130 | int i, j; | ||
| 1131 | const struct video_levels *video_levels; | ||
| 1132 | const struct color_conversion *color_conversion; | ||
| 1133 | bool burst_ena; | ||
| 1134 | |||
| 1135 | if (!tv_mode) | ||
| 1136 | return; /* can't happen (mode_prepare prevents this) */ | ||
| 1137 | |||
| 1138 | tv_ctl = 0; | ||
| 1139 | |||
| 1140 | switch (tv_priv->type) { | ||
| 1141 | default: | ||
| 1142 | case DRM_MODE_CONNECTOR_Unknown: | ||
| 1143 | case DRM_MODE_CONNECTOR_Composite: | ||
| 1144 | tv_ctl |= TV_ENC_OUTPUT_COMPOSITE; | ||
| 1145 | video_levels = tv_mode->composite_levels; | ||
| 1146 | color_conversion = tv_mode->composite_color; | ||
| 1147 | burst_ena = tv_mode->burst_ena; | ||
| 1148 | break; | ||
| 1149 | case DRM_MODE_CONNECTOR_Component: | ||
| 1150 | tv_ctl |= TV_ENC_OUTPUT_COMPONENT; | ||
| 1151 | video_levels = &component_levels; | ||
| 1152 | if (tv_mode->burst_ena) | ||
| 1153 | color_conversion = &sdtv_csc_yprpb; | ||
| 1154 | else | ||
| 1155 | color_conversion = &hdtv_csc_yprpb; | ||
| 1156 | burst_ena = false; | ||
| 1157 | break; | ||
| 1158 | case DRM_MODE_CONNECTOR_SVIDEO: | ||
| 1159 | tv_ctl |= TV_ENC_OUTPUT_SVIDEO; | ||
| 1160 | video_levels = tv_mode->svideo_levels; | ||
| 1161 | color_conversion = tv_mode->svideo_color; | ||
| 1162 | burst_ena = tv_mode->burst_ena; | ||
| 1163 | break; | ||
| 1164 | } | ||
| 1165 | hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) | | ||
| 1166 | (tv_mode->htotal << TV_HTOTAL_SHIFT); | ||
| 1167 | |||
| 1168 | hctl2 = (tv_mode->hburst_start << 16) | | ||
| 1169 | (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT); | ||
| 1170 | |||
| 1171 | if (burst_ena) | ||
| 1172 | hctl2 |= TV_BURST_ENA; | ||
| 1173 | |||
| 1174 | hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) | | ||
| 1175 | (tv_mode->hblank_end << TV_HBLANK_END_SHIFT); | ||
| 1176 | |||
| 1177 | vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) | | ||
| 1178 | (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) | | ||
| 1179 | (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT); | ||
| 1180 | |||
| 1181 | vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) | | ||
| 1182 | (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) | | ||
| 1183 | (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT); | ||
| 1184 | |||
| 1185 | vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) | | ||
| 1186 | (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) | | ||
| 1187 | (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT); | ||
| 1188 | |||
| 1189 | if (tv_mode->veq_ena) | ||
| 1190 | vctl3 |= TV_EQUAL_ENA; | ||
| 1191 | |||
| 1192 | vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) | | ||
| 1193 | (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT); | ||
| 1194 | |||
| 1195 | vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) | | ||
| 1196 | (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT); | ||
| 1197 | |||
| 1198 | vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) | | ||
| 1199 | (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT); | ||
| 1200 | |||
| 1201 | vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) | | ||
| 1202 | (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT); | ||
| 1203 | |||
| 1204 | if (intel_crtc->pipe == 1) | ||
| 1205 | tv_ctl |= TV_ENC_PIPEB_SELECT; | ||
| 1206 | tv_ctl |= tv_mode->oversample; | ||
| 1207 | |||
| 1208 | if (tv_mode->progressive) | ||
| 1209 | tv_ctl |= TV_PROGRESSIVE; | ||
| 1210 | if (tv_mode->trilevel_sync) | ||
| 1211 | tv_ctl |= TV_TRILEVEL_SYNC; | ||
| 1212 | if (tv_mode->pal_burst) | ||
| 1213 | tv_ctl |= TV_PAL_BURST; | ||
| 1214 | scctl1 = 0; | ||
| 1215 | /* dda1 implies valid video levels */ | ||
| 1216 | if (tv_mode->dda1_inc) { | ||
| 1217 | scctl1 |= TV_SC_DDA1_EN; | ||
| 1218 | scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT; | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | if (tv_mode->dda2_inc) | ||
| 1222 | scctl1 |= TV_SC_DDA2_EN; | ||
| 1223 | |||
| 1224 | if (tv_mode->dda3_inc) | ||
| 1225 | scctl1 |= TV_SC_DDA3_EN; | ||
| 1226 | |||
| 1227 | scctl1 |= tv_mode->sc_reset; | ||
| 1228 | scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT; | ||
| 1229 | |||
| 1230 | scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT | | ||
| 1231 | tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT; | ||
| 1232 | |||
| 1233 | scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT | | ||
| 1234 | tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT; | ||
| 1235 | |||
| 1236 | /* Enable two fixes for the chips that need them. */ | ||
| 1237 | if (dev->pci_device < 0x2772) | ||
| 1238 | tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX; | ||
| 1239 | |||
| 1240 | I915_WRITE(TV_H_CTL_1, hctl1); | ||
| 1241 | I915_WRITE(TV_H_CTL_2, hctl2); | ||
| 1242 | I915_WRITE(TV_H_CTL_3, hctl3); | ||
| 1243 | I915_WRITE(TV_V_CTL_1, vctl1); | ||
| 1244 | I915_WRITE(TV_V_CTL_2, vctl2); | ||
| 1245 | I915_WRITE(TV_V_CTL_3, vctl3); | ||
| 1246 | I915_WRITE(TV_V_CTL_4, vctl4); | ||
| 1247 | I915_WRITE(TV_V_CTL_5, vctl5); | ||
| 1248 | I915_WRITE(TV_V_CTL_6, vctl6); | ||
| 1249 | I915_WRITE(TV_V_CTL_7, vctl7); | ||
| 1250 | I915_WRITE(TV_SC_CTL_1, scctl1); | ||
| 1251 | I915_WRITE(TV_SC_CTL_2, scctl2); | ||
| 1252 | I915_WRITE(TV_SC_CTL_3, scctl3); | ||
| 1253 | |||
| 1254 | if (color_conversion) { | ||
| 1255 | I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) | | ||
| 1256 | color_conversion->gy); | ||
| 1257 | I915_WRITE(TV_CSC_Y2,(color_conversion->by << 16) | | ||
| 1258 | color_conversion->ay); | ||
| 1259 | I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) | | ||
| 1260 | color_conversion->gu); | ||
| 1261 | I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) | | ||
| 1262 | color_conversion->au); | ||
| 1263 | I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) | | ||
| 1264 | color_conversion->gv); | ||
| 1265 | I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) | | ||
| 1266 | color_conversion->av); | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | I915_WRITE(TV_CLR_KNOBS, 0x00606000); | ||
| 1270 | if (video_levels) | ||
| 1271 | I915_WRITE(TV_CLR_LEVEL, | ||
| 1272 | ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | | ||
| 1273 | (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); | ||
| 1274 | { | ||
| 1275 | int pipeconf_reg = (intel_crtc->pipe == 0) ? | ||
| 1276 | PIPEACONF : PIPEBCONF; | ||
| 1277 | int dspcntr_reg = (intel_crtc->plane == 0) ? | ||
| 1278 | DSPACNTR : DSPBCNTR; | ||
| 1279 | int pipeconf = I915_READ(pipeconf_reg); | ||
| 1280 | int dspcntr = I915_READ(dspcntr_reg); | ||
| 1281 | int dspbase_reg = (intel_crtc->plane == 0) ? | ||
| 1282 | DSPAADDR : DSPBADDR; | ||
| 1283 | int xpos = 0x0, ypos = 0x0; | ||
| 1284 | unsigned int xsize, ysize; | ||
| 1285 | /* Pipe must be off here */ | ||
| 1286 | I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); | ||
| 1287 | /* Flush the plane changes */ | ||
| 1288 | I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); | ||
| 1289 | |||
| 1290 | /* Wait for vblank for the disable to take effect */ | ||
| 1291 | if (!IS_I9XX(dev)) | ||
| 1292 | intel_wait_for_vblank(dev); | ||
| 1293 | |||
| 1294 | I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); | ||
| 1295 | /* Wait for vblank for the disable to take effect. */ | ||
| 1296 | intel_wait_for_vblank(dev); | ||
| 1297 | |||
| 1298 | /* Filter ctl must be set before TV_WIN_SIZE */ | ||
| 1299 | I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE); | ||
| 1300 | xsize = tv_mode->hblank_start - tv_mode->hblank_end; | ||
| 1301 | if (tv_mode->progressive) | ||
| 1302 | ysize = tv_mode->nbr_end + 1; | ||
| 1303 | else | ||
| 1304 | ysize = 2*tv_mode->nbr_end + 1; | ||
| 1305 | |||
| 1306 | xpos += tv_priv->margin[TV_MARGIN_LEFT]; | ||
| 1307 | ypos += tv_priv->margin[TV_MARGIN_TOP]; | ||
| 1308 | xsize -= (tv_priv->margin[TV_MARGIN_LEFT] + | ||
| 1309 | tv_priv->margin[TV_MARGIN_RIGHT]); | ||
| 1310 | ysize -= (tv_priv->margin[TV_MARGIN_TOP] + | ||
| 1311 | tv_priv->margin[TV_MARGIN_BOTTOM]); | ||
| 1312 | I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos); | ||
| 1313 | I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize); | ||
| 1314 | |||
| 1315 | I915_WRITE(pipeconf_reg, pipeconf); | ||
| 1316 | I915_WRITE(dspcntr_reg, dspcntr); | ||
| 1317 | /* Flush the plane changes */ | ||
| 1318 | I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); | ||
| 1319 | } | ||
| 1320 | |||
| 1321 | j = 0; | ||
| 1322 | for (i = 0; i < 60; i++) | ||
| 1323 | I915_WRITE(TV_H_LUMA_0 + (i<<2), tv_mode->filter_table[j++]); | ||
| 1324 | for (i = 0; i < 60; i++) | ||
| 1325 | I915_WRITE(TV_H_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]); | ||
| 1326 | for (i = 0; i < 43; i++) | ||
| 1327 | I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]); | ||
| 1328 | for (i = 0; i < 43; i++) | ||
| 1329 | I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]); | ||
| 1330 | I915_WRITE(TV_DAC, 0); | ||
| 1331 | I915_WRITE(TV_CTL, tv_ctl); | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | static const struct drm_display_mode reported_modes[] = { | ||
| 1335 | { | ||
| 1336 | .name = "NTSC 480i", | ||
| 1337 | .clock = 107520, | ||
| 1338 | .hdisplay = 1280, | ||
| 1339 | .hsync_start = 1368, | ||
| 1340 | .hsync_end = 1496, | ||
| 1341 | .htotal = 1712, | ||
| 1342 | |||
| 1343 | .vdisplay = 1024, | ||
| 1344 | .vsync_start = 1027, | ||
| 1345 | .vsync_end = 1034, | ||
| 1346 | .vtotal = 1104, | ||
| 1347 | .type = DRM_MODE_TYPE_DRIVER, | ||
| 1348 | }, | ||
| 1349 | }; | ||
| 1350 | |||
| 1351 | /** | ||
| 1352 | * Detects TV presence by checking for load. | ||
| 1353 | * | ||
| 1354 | * Requires that the current pipe's DPLL is active. | ||
| 1355 | |||
| 1356 | * \return true if TV is connected. | ||
| 1357 | * \return false if TV is disconnected. | ||
| 1358 | */ | ||
| 1359 | static int | ||
| 1360 | intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output) | ||
| 1361 | { | ||
| 1362 | struct drm_encoder *encoder = &intel_output->enc; | ||
| 1363 | struct drm_device *dev = encoder->dev; | ||
| 1364 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 1365 | unsigned long irqflags; | ||
| 1366 | u32 tv_ctl, save_tv_ctl; | ||
| 1367 | u32 tv_dac, save_tv_dac; | ||
| 1368 | int type = DRM_MODE_CONNECTOR_Unknown; | ||
| 1369 | |||
| 1370 | tv_dac = I915_READ(TV_DAC); | ||
| 1371 | |||
| 1372 | /* Disable TV interrupts around load detect or we'll recurse */ | ||
| 1373 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); | ||
| 1374 | i915_disable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE | | ||
| 1375 | PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); | ||
| 1376 | spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); | ||
| 1377 | |||
| 1378 | /* | ||
| 1379 | * Detect TV by polling) | ||
| 1380 | */ | ||
| 1381 | if (intel_output->load_detect_temp) { | ||
| 1382 | /* TV not currently running, prod it with destructive detect */ | ||
| 1383 | save_tv_dac = tv_dac; | ||
| 1384 | tv_ctl = I915_READ(TV_CTL); | ||
| 1385 | save_tv_ctl = tv_ctl; | ||
| 1386 | tv_ctl &= ~TV_ENC_ENABLE; | ||
| 1387 | tv_ctl &= ~TV_TEST_MODE_MASK; | ||
| 1388 | tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; | ||
| 1389 | tv_dac &= ~TVDAC_SENSE_MASK; | ||
| 1390 | tv_dac |= (TVDAC_STATE_CHG_EN | | ||
| 1391 | TVDAC_A_SENSE_CTL | | ||
| 1392 | TVDAC_B_SENSE_CTL | | ||
| 1393 | TVDAC_C_SENSE_CTL | | ||
| 1394 | DAC_CTL_OVERRIDE | | ||
| 1395 | DAC_A_0_7_V | | ||
| 1396 | DAC_B_0_7_V | | ||
| 1397 | DAC_C_0_7_V); | ||
| 1398 | I915_WRITE(TV_CTL, tv_ctl); | ||
| 1399 | I915_WRITE(TV_DAC, tv_dac); | ||
| 1400 | intel_wait_for_vblank(dev); | ||
| 1401 | tv_dac = I915_READ(TV_DAC); | ||
| 1402 | I915_WRITE(TV_DAC, save_tv_dac); | ||
| 1403 | I915_WRITE(TV_CTL, save_tv_ctl); | ||
| 1404 | } | ||
| 1405 | /* | ||
| 1406 | * A B C | ||
| 1407 | * 0 1 1 Composite | ||
| 1408 | * 1 0 X svideo | ||
| 1409 | * 0 0 0 Component | ||
| 1410 | */ | ||
| 1411 | if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) { | ||
| 1412 | DRM_DEBUG("Detected Composite TV connection\n"); | ||
| 1413 | type = DRM_MODE_CONNECTOR_Composite; | ||
| 1414 | } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) { | ||
| 1415 | DRM_DEBUG("Detected S-Video TV connection\n"); | ||
| 1416 | type = DRM_MODE_CONNECTOR_SVIDEO; | ||
| 1417 | } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) { | ||
| 1418 | DRM_DEBUG("Detected Component TV connection\n"); | ||
| 1419 | type = DRM_MODE_CONNECTOR_Component; | ||
| 1420 | } else { | ||
| 1421 | DRM_DEBUG("No TV connection detected\n"); | ||
| 1422 | type = -1; | ||
| 1423 | } | ||
| 1424 | |||
| 1425 | /* Restore interrupt config */ | ||
| 1426 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); | ||
| 1427 | i915_enable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE | | ||
| 1428 | PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); | ||
| 1429 | spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); | ||
| 1430 | |||
| 1431 | return type; | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | /** | ||
| 1435 | * Detect the TV connection. | ||
| 1436 | * | ||
| 1437 | * Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure | ||
| 1438 | * we have a pipe programmed in order to probe the TV. | ||
| 1439 | */ | ||
| 1440 | static enum drm_connector_status | ||
| 1441 | intel_tv_detect(struct drm_connector *connector) | ||
| 1442 | { | ||
| 1443 | struct drm_crtc *crtc; | ||
| 1444 | struct drm_display_mode mode; | ||
| 1445 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 1446 | struct intel_tv_priv *tv_priv = intel_output->dev_priv; | ||
| 1447 | struct drm_encoder *encoder = &intel_output->enc; | ||
| 1448 | int dpms_mode; | ||
| 1449 | int type = tv_priv->type; | ||
| 1450 | |||
| 1451 | mode = reported_modes[0]; | ||
| 1452 | drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); | ||
| 1453 | |||
| 1454 | if (encoder->crtc) { | ||
| 1455 | type = intel_tv_detect_type(encoder->crtc, intel_output); | ||
| 1456 | } else { | ||
| 1457 | crtc = intel_get_load_detect_pipe(intel_output, &mode, &dpms_mode); | ||
| 1458 | if (crtc) { | ||
| 1459 | type = intel_tv_detect_type(crtc, intel_output); | ||
| 1460 | intel_release_load_detect_pipe(intel_output, dpms_mode); | ||
| 1461 | } else | ||
| 1462 | type = -1; | ||
| 1463 | } | ||
| 1464 | |||
| 1465 | if (type < 0) | ||
| 1466 | return connector_status_disconnected; | ||
| 1467 | |||
| 1468 | return connector_status_connected; | ||
| 1469 | } | ||
| 1470 | |||
| 1471 | static struct input_res { | ||
| 1472 | char *name; | ||
| 1473 | int w, h; | ||
| 1474 | } input_res_table[] = | ||
| 1475 | { | ||
| 1476 | {"640x480", 640, 480}, | ||
| 1477 | {"800x600", 800, 600}, | ||
| 1478 | {"1024x768", 1024, 768}, | ||
| 1479 | {"1280x1024", 1280, 1024}, | ||
| 1480 | {"848x480", 848, 480}, | ||
| 1481 | {"1280x720", 1280, 720}, | ||
| 1482 | {"1920x1080", 1920, 1080}, | ||
| 1483 | }; | ||
| 1484 | |||
| 1485 | /** | ||
| 1486 | * Stub get_modes function. | ||
| 1487 | * | ||
| 1488 | * This should probably return a set of fixed modes, unless we can figure out | ||
| 1489 | * how to probe modes off of TV connections. | ||
| 1490 | */ | ||
| 1491 | |||
| 1492 | static int | ||
| 1493 | intel_tv_get_modes(struct drm_connector *connector) | ||
| 1494 | { | ||
| 1495 | struct drm_display_mode *mode_ptr; | ||
| 1496 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 1497 | const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output); | ||
| 1498 | int j; | ||
| 1499 | |||
| 1500 | for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]); | ||
| 1501 | j++) { | ||
| 1502 | struct input_res *input = &input_res_table[j]; | ||
| 1503 | unsigned int hactive_s = input->w; | ||
| 1504 | unsigned int vactive_s = input->h; | ||
| 1505 | |||
| 1506 | if (tv_mode->max_srcw && input->w > tv_mode->max_srcw) | ||
| 1507 | continue; | ||
| 1508 | |||
| 1509 | if (input->w > 1024 && (!tv_mode->progressive | ||
| 1510 | && !tv_mode->component_only)) | ||
| 1511 | continue; | ||
| 1512 | |||
| 1513 | mode_ptr = drm_calloc(1, sizeof(struct drm_display_mode), | ||
| 1514 | DRM_MEM_DRIVER); | ||
| 1515 | strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN); | ||
| 1516 | |||
| 1517 | mode_ptr->hdisplay = hactive_s; | ||
| 1518 | mode_ptr->hsync_start = hactive_s + 1; | ||
| 1519 | mode_ptr->hsync_end = hactive_s + 64; | ||
| 1520 | if (mode_ptr->hsync_end <= mode_ptr->hsync_start) | ||
| 1521 | mode_ptr->hsync_end = mode_ptr->hsync_start + 1; | ||
| 1522 | mode_ptr->htotal = hactive_s + 96; | ||
| 1523 | |||
| 1524 | mode_ptr->vdisplay = vactive_s; | ||
| 1525 | mode_ptr->vsync_start = vactive_s + 1; | ||
| 1526 | mode_ptr->vsync_end = vactive_s + 32; | ||
| 1527 | if (mode_ptr->vsync_end <= mode_ptr->vsync_start) | ||
| 1528 | mode_ptr->vsync_end = mode_ptr->vsync_start + 1; | ||
| 1529 | mode_ptr->vtotal = vactive_s + 33; | ||
| 1530 | |||
| 1531 | mode_ptr->clock = (int) (tv_mode->refresh * | ||
| 1532 | mode_ptr->vtotal * | ||
| 1533 | mode_ptr->htotal / 1000) / 1000; | ||
| 1534 | |||
| 1535 | mode_ptr->type = DRM_MODE_TYPE_DRIVER; | ||
| 1536 | drm_mode_probed_add(connector, mode_ptr); | ||
| 1537 | } | ||
| 1538 | |||
| 1539 | return 0; | ||
| 1540 | } | ||
| 1541 | |||
| 1542 | static void | ||
| 1543 | intel_tv_destroy (struct drm_connector *connector) | ||
| 1544 | { | ||
| 1545 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 1546 | |||
| 1547 | drm_sysfs_connector_remove(connector); | ||
| 1548 | drm_connector_cleanup(connector); | ||
| 1549 | drm_free(intel_output, sizeof(struct intel_output) + sizeof(struct intel_tv_priv), | ||
| 1550 | DRM_MEM_DRIVER); | ||
| 1551 | } | ||
| 1552 | |||
| 1553 | |||
| 1554 | static int | ||
| 1555 | intel_tv_set_property(struct drm_connector *connector, struct drm_property *property, | ||
| 1556 | uint64_t val) | ||
| 1557 | { | ||
| 1558 | struct drm_device *dev = connector->dev; | ||
| 1559 | struct intel_output *intel_output = to_intel_output(connector); | ||
| 1560 | struct intel_tv_priv *tv_priv = intel_output->dev_priv; | ||
| 1561 | int ret = 0; | ||
| 1562 | |||
| 1563 | ret = drm_connector_property_set_value(connector, property, val); | ||
| 1564 | if (ret < 0) | ||
| 1565 | goto out; | ||
| 1566 | |||
| 1567 | if (property == dev->mode_config.tv_left_margin_property) | ||
| 1568 | tv_priv->margin[TV_MARGIN_LEFT] = val; | ||
| 1569 | else if (property == dev->mode_config.tv_right_margin_property) | ||
| 1570 | tv_priv->margin[TV_MARGIN_RIGHT] = val; | ||
| 1571 | else if (property == dev->mode_config.tv_top_margin_property) | ||
| 1572 | tv_priv->margin[TV_MARGIN_TOP] = val; | ||
| 1573 | else if (property == dev->mode_config.tv_bottom_margin_property) | ||
| 1574 | tv_priv->margin[TV_MARGIN_BOTTOM] = val; | ||
| 1575 | else if (property == dev->mode_config.tv_mode_property) { | ||
| 1576 | if (val >= NUM_TV_MODES) { | ||
| 1577 | ret = -EINVAL; | ||
| 1578 | goto out; | ||
| 1579 | } | ||
| 1580 | tv_priv->tv_format = tv_modes[val].name; | ||
| 1581 | intel_tv_mode_set(&intel_output->enc, NULL, NULL); | ||
| 1582 | } else { | ||
| 1583 | ret = -EINVAL; | ||
| 1584 | goto out; | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | intel_tv_mode_set(&intel_output->enc, NULL, NULL); | ||
| 1588 | out: | ||
| 1589 | return ret; | ||
| 1590 | } | ||
| 1591 | |||
| 1592 | static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = { | ||
| 1593 | .dpms = intel_tv_dpms, | ||
| 1594 | .mode_fixup = intel_tv_mode_fixup, | ||
| 1595 | .prepare = intel_encoder_prepare, | ||
| 1596 | .mode_set = intel_tv_mode_set, | ||
| 1597 | .commit = intel_encoder_commit, | ||
| 1598 | }; | ||
| 1599 | |||
| 1600 | static const struct drm_connector_funcs intel_tv_connector_funcs = { | ||
| 1601 | .save = intel_tv_save, | ||
| 1602 | .restore = intel_tv_restore, | ||
| 1603 | .detect = intel_tv_detect, | ||
| 1604 | .destroy = intel_tv_destroy, | ||
| 1605 | .set_property = intel_tv_set_property, | ||
| 1606 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
| 1607 | }; | ||
| 1608 | |||
| 1609 | static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = { | ||
| 1610 | .mode_valid = intel_tv_mode_valid, | ||
| 1611 | .get_modes = intel_tv_get_modes, | ||
| 1612 | .best_encoder = intel_best_encoder, | ||
| 1613 | }; | ||
| 1614 | |||
| 1615 | static void intel_tv_enc_destroy(struct drm_encoder *encoder) | ||
| 1616 | { | ||
| 1617 | drm_encoder_cleanup(encoder); | ||
| 1618 | } | ||
| 1619 | |||
| 1620 | static const struct drm_encoder_funcs intel_tv_enc_funcs = { | ||
| 1621 | .destroy = intel_tv_enc_destroy, | ||
| 1622 | }; | ||
| 1623 | |||
| 1624 | |||
| 1625 | void | ||
| 1626 | intel_tv_init(struct drm_device *dev) | ||
| 1627 | { | ||
| 1628 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 1629 | struct drm_connector *connector; | ||
| 1630 | struct intel_output *intel_output; | ||
| 1631 | struct intel_tv_priv *tv_priv; | ||
| 1632 | u32 tv_dac_on, tv_dac_off, save_tv_dac; | ||
| 1633 | char **tv_format_names; | ||
| 1634 | int i, initial_mode = 0; | ||
| 1635 | |||
| 1636 | if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) | ||
| 1637 | return; | ||
| 1638 | |||
| 1639 | /* Even if we have an encoder we may not have a connector */ | ||
| 1640 | if (!dev_priv->int_tv_support) | ||
| 1641 | return; | ||
| 1642 | |||
| 1643 | /* | ||
| 1644 | * Sanity check the TV output by checking to see if the | ||
| 1645 | * DAC register holds a value | ||
| 1646 | */ | ||
| 1647 | save_tv_dac = I915_READ(TV_DAC); | ||
| 1648 | |||
| 1649 | I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN); | ||
| 1650 | tv_dac_on = I915_READ(TV_DAC); | ||
| 1651 | |||
| 1652 | I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN); | ||
| 1653 | tv_dac_off = I915_READ(TV_DAC); | ||
| 1654 | |||
| 1655 | I915_WRITE(TV_DAC, save_tv_dac); | ||
| 1656 | |||
| 1657 | /* | ||
| 1658 | * If the register does not hold the state change enable | ||
| 1659 | * bit, (either as a 0 or a 1), assume it doesn't really | ||
| 1660 | * exist | ||
| 1661 | */ | ||
| 1662 | if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 || | ||
| 1663 | (tv_dac_off & TVDAC_STATE_CHG_EN) != 0) | ||
| 1664 | return; | ||
| 1665 | |||
| 1666 | intel_output = drm_calloc(1, sizeof(struct intel_output) + | ||
| 1667 | sizeof(struct intel_tv_priv), DRM_MEM_DRIVER); | ||
| 1668 | if (!intel_output) { | ||
| 1669 | return; | ||
| 1670 | } | ||
| 1671 | connector = &intel_output->base; | ||
| 1672 | |||
| 1673 | drm_connector_init(dev, connector, &intel_tv_connector_funcs, | ||
| 1674 | DRM_MODE_CONNECTOR_SVIDEO); | ||
| 1675 | |||
| 1676 | drm_encoder_init(dev, &intel_output->enc, &intel_tv_enc_funcs, | ||
| 1677 | DRM_MODE_ENCODER_TVDAC); | ||
| 1678 | |||
| 1679 | drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); | ||
| 1680 | tv_priv = (struct intel_tv_priv *)(intel_output + 1); | ||
| 1681 | intel_output->type = INTEL_OUTPUT_TVOUT; | ||
| 1682 | intel_output->enc.possible_crtcs = ((1 << 0) | (1 << 1)); | ||
| 1683 | intel_output->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT); | ||
| 1684 | intel_output->dev_priv = tv_priv; | ||
| 1685 | tv_priv->type = DRM_MODE_CONNECTOR_Unknown; | ||
| 1686 | |||
| 1687 | /* BIOS margin values */ | ||
| 1688 | tv_priv->margin[TV_MARGIN_LEFT] = 54; | ||
| 1689 | tv_priv->margin[TV_MARGIN_TOP] = 36; | ||
| 1690 | tv_priv->margin[TV_MARGIN_RIGHT] = 46; | ||
| 1691 | tv_priv->margin[TV_MARGIN_BOTTOM] = 37; | ||
| 1692 | |||
| 1693 | tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); | ||
| 1694 | |||
| 1695 | drm_encoder_helper_add(&intel_output->enc, &intel_tv_helper_funcs); | ||
| 1696 | drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs); | ||
| 1697 | connector->interlace_allowed = false; | ||
| 1698 | connector->doublescan_allowed = false; | ||
| 1699 | |||
| 1700 | /* Create TV properties then attach current values */ | ||
| 1701 | tv_format_names = drm_alloc(sizeof(char *) * NUM_TV_MODES, | ||
| 1702 | DRM_MEM_DRIVER); | ||
| 1703 | if (!tv_format_names) | ||
| 1704 | goto out; | ||
| 1705 | for (i = 0; i < NUM_TV_MODES; i++) | ||
| 1706 | tv_format_names[i] = tv_modes[i].name; | ||
| 1707 | drm_mode_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); | ||
| 1708 | |||
| 1709 | drm_connector_attach_property(connector, dev->mode_config.tv_mode_property, | ||
| 1710 | initial_mode); | ||
| 1711 | drm_connector_attach_property(connector, | ||
| 1712 | dev->mode_config.tv_left_margin_property, | ||
| 1713 | tv_priv->margin[TV_MARGIN_LEFT]); | ||
| 1714 | drm_connector_attach_property(connector, | ||
| 1715 | dev->mode_config.tv_top_margin_property, | ||
| 1716 | tv_priv->margin[TV_MARGIN_TOP]); | ||
| 1717 | drm_connector_attach_property(connector, | ||
| 1718 | dev->mode_config.tv_right_margin_property, | ||
| 1719 | tv_priv->margin[TV_MARGIN_RIGHT]); | ||
| 1720 | drm_connector_attach_property(connector, | ||
| 1721 | dev->mode_config.tv_bottom_margin_property, | ||
| 1722 | tv_priv->margin[TV_MARGIN_BOTTOM]); | ||
| 1723 | out: | ||
| 1724 | drm_sysfs_connector_add(connector); | ||
| 1725 | } | ||
diff --git a/drivers/gpu/drm/radeon/r300_cmdbuf.c b/drivers/gpu/drm/radeon/r300_cmdbuf.c index 4b27d9abb7bc..cace3964feeb 100644 --- a/drivers/gpu/drm/radeon/r300_cmdbuf.c +++ b/drivers/gpu/drm/radeon/r300_cmdbuf.c | |||
| @@ -860,12 +860,12 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv) | |||
| 860 | * The actual age emit is done by r300_do_cp_cmdbuf, which is why you must | 860 | * The actual age emit is done by r300_do_cp_cmdbuf, which is why you must |
| 861 | * be careful about how this function is called. | 861 | * be careful about how this function is called. |
| 862 | */ | 862 | */ |
| 863 | static void r300_discard_buffer(struct drm_device * dev, struct drm_buf * buf) | 863 | static void r300_discard_buffer(struct drm_device *dev, struct drm_master *master, struct drm_buf *buf) |
| 864 | { | 864 | { |
| 865 | drm_radeon_private_t *dev_priv = dev->dev_private; | ||
| 866 | drm_radeon_buf_priv_t *buf_priv = buf->dev_private; | 865 | drm_radeon_buf_priv_t *buf_priv = buf->dev_private; |
| 866 | struct drm_radeon_master_private *master_priv = master->driver_priv; | ||
| 867 | 867 | ||
| 868 | buf_priv->age = ++dev_priv->sarea_priv->last_dispatch; | 868 | buf_priv->age = ++master_priv->sarea_priv->last_dispatch; |
| 869 | buf->pending = 1; | 869 | buf->pending = 1; |
| 870 | buf->used = 0; | 870 | buf->used = 0; |
| 871 | } | 871 | } |
| @@ -1027,6 +1027,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, | |||
| 1027 | drm_radeon_kcmd_buffer_t *cmdbuf) | 1027 | drm_radeon_kcmd_buffer_t *cmdbuf) |
| 1028 | { | 1028 | { |
| 1029 | drm_radeon_private_t *dev_priv = dev->dev_private; | 1029 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 1030 | struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; | ||
| 1030 | struct drm_device_dma *dma = dev->dma; | 1031 | struct drm_device_dma *dma = dev->dma; |
| 1031 | struct drm_buf *buf = NULL; | 1032 | struct drm_buf *buf = NULL; |
| 1032 | int emit_dispatch_age = 0; | 1033 | int emit_dispatch_age = 0; |
| @@ -1134,7 +1135,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, | |||
| 1134 | } | 1135 | } |
| 1135 | 1136 | ||
| 1136 | emit_dispatch_age = 1; | 1137 | emit_dispatch_age = 1; |
| 1137 | r300_discard_buffer(dev, buf); | 1138 | r300_discard_buffer(dev, file_priv->master, buf); |
| 1138 | break; | 1139 | break; |
| 1139 | 1140 | ||
| 1140 | case R300_CMD_WAIT: | 1141 | case R300_CMD_WAIT: |
| @@ -1189,7 +1190,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, | |||
| 1189 | 1190 | ||
| 1190 | /* Emit the vertex buffer age */ | 1191 | /* Emit the vertex buffer age */ |
| 1191 | BEGIN_RING(2); | 1192 | BEGIN_RING(2); |
| 1192 | RADEON_DISPATCH_AGE(dev_priv->sarea_priv->last_dispatch); | 1193 | RADEON_DISPATCH_AGE(master_priv->sarea_priv->last_dispatch); |
| 1193 | ADVANCE_RING(); | 1194 | ADVANCE_RING(); |
| 1194 | } | 1195 | } |
| 1195 | 1196 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index dcebb4bee7aa..63212d7bbc28 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | 31 | ||
| 32 | #include "drmP.h" | 32 | #include "drmP.h" |
| 33 | #include "drm.h" | 33 | #include "drm.h" |
| 34 | #include "drm_sarea.h" | ||
| 34 | #include "radeon_drm.h" | 35 | #include "radeon_drm.h" |
| 35 | #include "radeon_drv.h" | 36 | #include "radeon_drv.h" |
| 36 | #include "r300_reg.h" | 37 | #include "r300_reg.h" |
| @@ -667,15 +668,14 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, | |||
| 667 | RADEON_WRITE(RADEON_BUS_CNTL, tmp); | 668 | RADEON_WRITE(RADEON_BUS_CNTL, tmp); |
| 668 | } /* PCIE cards appears to not need this */ | 669 | } /* PCIE cards appears to not need this */ |
| 669 | 670 | ||
| 670 | dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0; | 671 | dev_priv->scratch[0] = 0; |
| 671 | RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame); | 672 | RADEON_WRITE(RADEON_LAST_FRAME_REG, 0); |
| 672 | 673 | ||
| 673 | dev_priv->sarea_priv->last_dispatch = dev_priv->scratch[1] = 0; | 674 | dev_priv->scratch[1] = 0; |
| 674 | RADEON_WRITE(RADEON_LAST_DISPATCH_REG, | 675 | RADEON_WRITE(RADEON_LAST_DISPATCH_REG, 0); |
| 675 | dev_priv->sarea_priv->last_dispatch); | ||
| 676 | 676 | ||
| 677 | dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0; | 677 | dev_priv->scratch[2] = 0; |
| 678 | RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear); | 678 | RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0); |
| 679 | 679 | ||
| 680 | radeon_do_wait_for_idle(dev_priv); | 680 | radeon_do_wait_for_idle(dev_priv); |
| 681 | 681 | ||
| @@ -871,9 +871,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) | |||
| 871 | } | 871 | } |
| 872 | } | 872 | } |
| 873 | 873 | ||
| 874 | static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) | 874 | static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, |
| 875 | struct drm_file *file_priv) | ||
| 875 | { | 876 | { |
| 876 | drm_radeon_private_t *dev_priv = dev->dev_private; | 877 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 878 | struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; | ||
| 877 | 879 | ||
| 878 | DRM_DEBUG("\n"); | 880 | DRM_DEBUG("\n"); |
| 879 | 881 | ||
| @@ -998,8 +1000,8 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) | |||
| 998 | dev_priv->buffers_offset = init->buffers_offset; | 1000 | dev_priv->buffers_offset = init->buffers_offset; |
| 999 | dev_priv->gart_textures_offset = init->gart_textures_offset; | 1001 | dev_priv->gart_textures_offset = init->gart_textures_offset; |
| 1000 | 1002 | ||
| 1001 | dev_priv->sarea = drm_getsarea(dev); | 1003 | master_priv->sarea = drm_getsarea(dev); |
| 1002 | if (!dev_priv->sarea) { | 1004 | if (!master_priv->sarea) { |
| 1003 | DRM_ERROR("could not find sarea!\n"); | 1005 | DRM_ERROR("could not find sarea!\n"); |
| 1004 | radeon_do_cleanup_cp(dev); | 1006 | radeon_do_cleanup_cp(dev); |
| 1005 | return -EINVAL; | 1007 | return -EINVAL; |
| @@ -1035,10 +1037,6 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) | |||
| 1035 | } | 1037 | } |
| 1036 | } | 1038 | } |
| 1037 | 1039 | ||
| 1038 | dev_priv->sarea_priv = | ||
| 1039 | (drm_radeon_sarea_t *) ((u8 *) dev_priv->sarea->handle + | ||
| 1040 | init->sarea_priv_offset); | ||
| 1041 | |||
| 1042 | #if __OS_HAS_AGP | 1040 | #if __OS_HAS_AGP |
| 1043 | if (dev_priv->flags & RADEON_IS_AGP) { | 1041 | if (dev_priv->flags & RADEON_IS_AGP) { |
| 1044 | drm_core_ioremap(dev_priv->cp_ring, dev); | 1042 | drm_core_ioremap(dev_priv->cp_ring, dev); |
| @@ -1329,7 +1327,7 @@ int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_pri | |||
| 1329 | case RADEON_INIT_CP: | 1327 | case RADEON_INIT_CP: |
| 1330 | case RADEON_INIT_R200_CP: | 1328 | case RADEON_INIT_R200_CP: |
| 1331 | case RADEON_INIT_R300_CP: | 1329 | case RADEON_INIT_R300_CP: |
| 1332 | return radeon_do_init_cp(dev, init); | 1330 | return radeon_do_init_cp(dev, init, file_priv); |
| 1333 | case RADEON_CLEANUP_CP: | 1331 | case RADEON_CLEANUP_CP: |
| 1334 | return radeon_do_cleanup_cp(dev); | 1332 | return radeon_do_cleanup_cp(dev); |
| 1335 | } | 1333 | } |
| @@ -1768,6 +1766,51 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) | |||
| 1768 | return ret; | 1766 | return ret; |
| 1769 | } | 1767 | } |
| 1770 | 1768 | ||
| 1769 | int radeon_master_create(struct drm_device *dev, struct drm_master *master) | ||
| 1770 | { | ||
| 1771 | struct drm_radeon_master_private *master_priv; | ||
| 1772 | unsigned long sareapage; | ||
| 1773 | int ret; | ||
| 1774 | |||
| 1775 | master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER); | ||
| 1776 | if (!master_priv) | ||
| 1777 | return -ENOMEM; | ||
| 1778 | |||
| 1779 | /* prebuild the SAREA */ | ||
| 1780 | sareapage = max_t(unsigned long, SAREA_MAX, PAGE_SIZE); | ||
| 1781 | ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER, | ||
| 1782 | &master_priv->sarea); | ||
| 1783 | if (ret) { | ||
| 1784 | DRM_ERROR("SAREA setup failed\n"); | ||
| 1785 | return ret; | ||
| 1786 | } | ||
| 1787 | master_priv->sarea_priv = master_priv->sarea->handle + sizeof(struct drm_sarea); | ||
| 1788 | master_priv->sarea_priv->pfCurrentPage = 0; | ||
| 1789 | |||
| 1790 | master->driver_priv = master_priv; | ||
| 1791 | return 0; | ||
| 1792 | } | ||
| 1793 | |||
| 1794 | void radeon_master_destroy(struct drm_device *dev, struct drm_master *master) | ||
| 1795 | { | ||
| 1796 | struct drm_radeon_master_private *master_priv = master->driver_priv; | ||
| 1797 | |||
| 1798 | if (!master_priv) | ||
| 1799 | return; | ||
| 1800 | |||
| 1801 | if (master_priv->sarea_priv && | ||
| 1802 | master_priv->sarea_priv->pfCurrentPage != 0) | ||
| 1803 | radeon_cp_dispatch_flip(dev, master); | ||
| 1804 | |||
| 1805 | master_priv->sarea_priv = NULL; | ||
| 1806 | if (master_priv->sarea) | ||
| 1807 | drm_rmmap_locked(dev, master_priv->sarea); | ||
| 1808 | |||
| 1809 | drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); | ||
| 1810 | |||
| 1811 | master->driver_priv = NULL; | ||
| 1812 | } | ||
| 1813 | |||
| 1771 | /* Create mappings for registers and framebuffer so userland doesn't necessarily | 1814 | /* Create mappings for registers and framebuffer so userland doesn't necessarily |
| 1772 | * have to find them. | 1815 | * have to find them. |
| 1773 | */ | 1816 | */ |
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 71af746a4e47..fef207881f45 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c | |||
| @@ -96,6 +96,8 @@ static struct drm_driver driver = { | |||
| 96 | .enable_vblank = radeon_enable_vblank, | 96 | .enable_vblank = radeon_enable_vblank, |
| 97 | .disable_vblank = radeon_disable_vblank, | 97 | .disable_vblank = radeon_disable_vblank, |
| 98 | .dri_library_name = dri_library_name, | 98 | .dri_library_name = dri_library_name, |
| 99 | .master_create = radeon_master_create, | ||
| 100 | .master_destroy = radeon_master_destroy, | ||
| 99 | .irq_preinstall = radeon_driver_irq_preinstall, | 101 | .irq_preinstall = radeon_driver_irq_preinstall, |
| 100 | .irq_postinstall = radeon_driver_irq_postinstall, | 102 | .irq_postinstall = radeon_driver_irq_postinstall, |
| 101 | .irq_uninstall = radeon_driver_irq_uninstall, | 103 | .irq_uninstall = radeon_driver_irq_uninstall, |
diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index 3bbb871b25d5..490bc7ceef60 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h | |||
| @@ -226,9 +226,13 @@ struct radeon_virt_surface { | |||
| 226 | #define RADEON_FLUSH_EMITED (1 < 0) | 226 | #define RADEON_FLUSH_EMITED (1 < 0) |
| 227 | #define RADEON_PURGE_EMITED (1 < 1) | 227 | #define RADEON_PURGE_EMITED (1 < 1) |
| 228 | 228 | ||
| 229 | struct drm_radeon_master_private { | ||
| 230 | drm_local_map_t *sarea; | ||
| 231 | drm_radeon_sarea_t *sarea_priv; | ||
| 232 | }; | ||
| 233 | |||
| 229 | typedef struct drm_radeon_private { | 234 | typedef struct drm_radeon_private { |
| 230 | drm_radeon_ring_buffer_t ring; | 235 | drm_radeon_ring_buffer_t ring; |
| 231 | drm_radeon_sarea_t *sarea_priv; | ||
| 232 | 236 | ||
| 233 | u32 fb_location; | 237 | u32 fb_location; |
| 234 | u32 fb_size; | 238 | u32 fb_size; |
| @@ -409,6 +413,9 @@ extern int radeon_driver_open(struct drm_device *dev, | |||
| 409 | extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd, | 413 | extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd, |
| 410 | unsigned long arg); | 414 | unsigned long arg); |
| 411 | 415 | ||
| 416 | extern int radeon_master_create(struct drm_device *dev, struct drm_master *master); | ||
| 417 | extern void radeon_master_destroy(struct drm_device *dev, struct drm_master *master); | ||
| 418 | extern void radeon_cp_dispatch_flip(struct drm_device *dev, struct drm_master *master); | ||
| 412 | /* r300_cmdbuf.c */ | 419 | /* r300_cmdbuf.c */ |
| 413 | extern void r300_init_reg_flags(struct drm_device *dev); | 420 | extern void r300_init_reg_flags(struct drm_device *dev); |
| 414 | 421 | ||
| @@ -1335,8 +1342,9 @@ do { \ | |||
| 1335 | } while (0) | 1342 | } while (0) |
| 1336 | 1343 | ||
| 1337 | #define VB_AGE_TEST_WITH_RETURN( dev_priv ) \ | 1344 | #define VB_AGE_TEST_WITH_RETURN( dev_priv ) \ |
| 1338 | do { \ | 1345 | do { \ |
| 1339 | drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; \ | 1346 | struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; \ |
| 1347 | drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; \ | ||
| 1340 | if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) { \ | 1348 | if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) { \ |
| 1341 | int __ret = radeon_do_cp_idle( dev_priv ); \ | 1349 | int __ret = radeon_do_cp_idle( dev_priv ); \ |
| 1342 | if ( __ret ) return __ret; \ | 1350 | if ( __ret ) return __ret; \ |
diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c index 5d7153fcc7b0..ef940a079dcb 100644 --- a/drivers/gpu/drm/radeon/radeon_state.c +++ b/drivers/gpu/drm/radeon/radeon_state.c | |||
| @@ -742,13 +742,14 @@ static struct { | |||
| 742 | */ | 742 | */ |
| 743 | 743 | ||
| 744 | static void radeon_clear_box(drm_radeon_private_t * dev_priv, | 744 | static void radeon_clear_box(drm_radeon_private_t * dev_priv, |
| 745 | struct drm_radeon_master_private *master_priv, | ||
| 745 | int x, int y, int w, int h, int r, int g, int b) | 746 | int x, int y, int w, int h, int r, int g, int b) |
| 746 | { | 747 | { |
| 747 | u32 color; | 748 | u32 color; |
| 748 | RING_LOCALS; | 749 | RING_LOCALS; |
| 749 | 750 | ||
| 750 | x += dev_priv->sarea_priv->boxes[0].x1; | 751 | x += master_priv->sarea_priv->boxes[0].x1; |
| 751 | y += dev_priv->sarea_priv->boxes[0].y1; | 752 | y += master_priv->sarea_priv->boxes[0].y1; |
| 752 | 753 | ||
| 753 | switch (dev_priv->color_fmt) { | 754 | switch (dev_priv->color_fmt) { |
| 754 | case RADEON_COLOR_FORMAT_RGB565: | 755 | case RADEON_COLOR_FORMAT_RGB565: |
| @@ -776,7 +777,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv, | |||
| 776 | RADEON_GMC_SRC_DATATYPE_COLOR | | 777 | RADEON_GMC_SRC_DATATYPE_COLOR | |
| 777 | RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS); | 778 | RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS); |
| 778 | 779 | ||
| 779 | if (dev_priv->sarea_priv->pfCurrentPage == 1) { | 780 | if (master_priv->sarea_priv->pfCurrentPage == 1) { |
| 780 | OUT_RING(dev_priv->front_pitch_offset); | 781 | OUT_RING(dev_priv->front_pitch_offset); |
| 781 | } else { | 782 | } else { |
| 782 | OUT_RING(dev_priv->back_pitch_offset); | 783 | OUT_RING(dev_priv->back_pitch_offset); |
| @@ -790,7 +791,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv, | |||
| 790 | ADVANCE_RING(); | 791 | ADVANCE_RING(); |
| 791 | } | 792 | } |
| 792 | 793 | ||
| 793 | static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) | 794 | static void radeon_cp_performance_boxes(drm_radeon_private_t *dev_priv, struct drm_radeon_master_private *master_priv) |
| 794 | { | 795 | { |
| 795 | /* Collapse various things into a wait flag -- trying to | 796 | /* Collapse various things into a wait flag -- trying to |
| 796 | * guess if userspase slept -- better just to have them tell us. | 797 | * guess if userspase slept -- better just to have them tell us. |
| @@ -807,12 +808,12 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) | |||
| 807 | /* Purple box for page flipping | 808 | /* Purple box for page flipping |
| 808 | */ | 809 | */ |
| 809 | if (dev_priv->stats.boxes & RADEON_BOX_FLIP) | 810 | if (dev_priv->stats.boxes & RADEON_BOX_FLIP) |
| 810 | radeon_clear_box(dev_priv, 4, 4, 8, 8, 255, 0, 255); | 811 | radeon_clear_box(dev_priv, master_priv, 4, 4, 8, 8, 255, 0, 255); |
| 811 | 812 | ||
| 812 | /* Red box if we have to wait for idle at any point | 813 | /* Red box if we have to wait for idle at any point |
| 813 | */ | 814 | */ |
| 814 | if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE) | 815 | if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE) |
| 815 | radeon_clear_box(dev_priv, 16, 4, 8, 8, 255, 0, 0); | 816 | radeon_clear_box(dev_priv, master_priv, 16, 4, 8, 8, 255, 0, 0); |
| 816 | 817 | ||
| 817 | /* Blue box: lost context? | 818 | /* Blue box: lost context? |
| 818 | */ | 819 | */ |
| @@ -820,12 +821,12 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) | |||
| 820 | /* Yellow box for texture swaps | 821 | /* Yellow box for texture swaps |
| 821 | */ | 822 | */ |
| 822 | if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD) | 823 | if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD) |
| 823 | radeon_clear_box(dev_priv, 40, 4, 8, 8, 255, 255, 0); | 824 | radeon_clear_box(dev_priv, master_priv, 40, 4, 8, 8, 255, 255, 0); |
| 824 | 825 | ||
| 825 | /* Green box if hardware never idles (as far as we can tell) | 826 | /* Green box if hardware never idles (as far as we can tell) |
| 826 | */ | 827 | */ |
| 827 | if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE)) | 828 | if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE)) |
| 828 | radeon_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0); | 829 | radeon_clear_box(dev_priv, master_priv, 64, 4, 8, 8, 0, 255, 0); |
| 829 | 830 | ||
| 830 | /* Draw bars indicating number of buffers allocated | 831 | /* Draw bars indicating number of buffers allocated |
| 831 | * (not a great measure, easily confused) | 832 | * (not a great measure, easily confused) |
| @@ -834,7 +835,7 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) | |||
| 834 | if (dev_priv->stats.requested_bufs > 100) | 835 | if (dev_priv->stats.requested_bufs > 100) |
| 835 | dev_priv->stats.requested_bufs = 100; | 836 | dev_priv->stats.requested_bufs = 100; |
| 836 | 837 | ||
| 837 | radeon_clear_box(dev_priv, 4, 16, | 838 | radeon_clear_box(dev_priv, master_priv, 4, 16, |
| 838 | dev_priv->stats.requested_bufs, 4, | 839 | dev_priv->stats.requested_bufs, 4, |
| 839 | 196, 128, 128); | 840 | 196, 128, 128); |
| 840 | } | 841 | } |
| @@ -848,11 +849,13 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) | |||
| 848 | */ | 849 | */ |
| 849 | 850 | ||
| 850 | static void radeon_cp_dispatch_clear(struct drm_device * dev, | 851 | static void radeon_cp_dispatch_clear(struct drm_device * dev, |
| 852 | struct drm_master *master, | ||
| 851 | drm_radeon_clear_t * clear, | 853 | drm_radeon_clear_t * clear, |
| 852 | drm_radeon_clear_rect_t * depth_boxes) | 854 | drm_radeon_clear_rect_t * depth_boxes) |
| 853 | { | 855 | { |
| 854 | drm_radeon_private_t *dev_priv = dev->dev_private; | 856 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 855 | drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; | 857 | struct drm_radeon_master_private *master_priv = master->driver_priv; |
| 858 | drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; | ||
| 856 | drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear; | 859 | drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear; |
| 857 | int nbox = sarea_priv->nbox; | 860 | int nbox = sarea_priv->nbox; |
| 858 | struct drm_clip_rect *pbox = sarea_priv->boxes; | 861 | struct drm_clip_rect *pbox = sarea_priv->boxes; |
| @@ -864,7 +867,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, | |||
| 864 | 867 | ||
| 865 | dev_priv->stats.clears++; | 868 | dev_priv->stats.clears++; |
| 866 | 869 | ||
| 867 | if (dev_priv->sarea_priv->pfCurrentPage == 1) { | 870 | if (sarea_priv->pfCurrentPage == 1) { |
| 868 | unsigned int tmp = flags; | 871 | unsigned int tmp = flags; |
| 869 | 872 | ||
| 870 | flags &= ~(RADEON_FRONT | RADEON_BACK); | 873 | flags &= ~(RADEON_FRONT | RADEON_BACK); |
| @@ -890,7 +893,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, | |||
| 890 | 893 | ||
| 891 | /* Make sure we restore the 3D state next time. | 894 | /* Make sure we restore the 3D state next time. |
| 892 | */ | 895 | */ |
| 893 | dev_priv->sarea_priv->ctx_owner = 0; | 896 | sarea_priv->ctx_owner = 0; |
| 894 | 897 | ||
| 895 | for (i = 0; i < nbox; i++) { | 898 | for (i = 0; i < nbox; i++) { |
| 896 | int x = pbox[i].x1; | 899 | int x = pbox[i].x1; |
| @@ -967,7 +970,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, | |||
| 967 | /* Make sure we restore the 3D state next time. | 970 | /* Make sure we restore the 3D state next time. |
| 968 | * we haven't touched any "normal" state - still need this? | 971 | * we haven't touched any "normal" state - still need this? |
| 969 | */ | 972 | */ |
| 970 | dev_priv->sarea_priv->ctx_owner = 0; | 973 | sarea_priv->ctx_owner = 0; |
| 971 | 974 | ||
| 972 | if ((dev_priv->flags & RADEON_HAS_HIERZ) | 975 | if ((dev_priv->flags & RADEON_HAS_HIERZ) |
| 973 | && (flags & RADEON_USE_HIERZ)) { | 976 | && (flags & RADEON_USE_HIERZ)) { |
| @@ -1214,7 +1217,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, | |||
| 1214 | 1217 | ||
| 1215 | /* Make sure we restore the 3D state next time. | 1218 | /* Make sure we restore the 3D state next time. |
| 1216 | */ | 1219 | */ |
| 1217 | dev_priv->sarea_priv->ctx_owner = 0; | 1220 | sarea_priv->ctx_owner = 0; |
| 1218 | 1221 | ||
| 1219 | for (i = 0; i < nbox; i++) { | 1222 | for (i = 0; i < nbox; i++) { |
| 1220 | 1223 | ||
| @@ -1285,7 +1288,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, | |||
| 1285 | 1288 | ||
| 1286 | /* Make sure we restore the 3D state next time. | 1289 | /* Make sure we restore the 3D state next time. |
| 1287 | */ | 1290 | */ |
| 1288 | dev_priv->sarea_priv->ctx_owner = 0; | 1291 | sarea_priv->ctx_owner = 0; |
| 1289 | 1292 | ||
| 1290 | for (i = 0; i < nbox; i++) { | 1293 | for (i = 0; i < nbox; i++) { |
| 1291 | 1294 | ||
| @@ -1328,20 +1331,21 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, | |||
| 1328 | * wait on this value before performing the clear ioctl. We | 1331 | * wait on this value before performing the clear ioctl. We |
| 1329 | * need this because the card's so damned fast... | 1332 | * need this because the card's so damned fast... |
| 1330 | */ | 1333 | */ |
| 1331 | dev_priv->sarea_priv->last_clear++; | 1334 | sarea_priv->last_clear++; |
| 1332 | 1335 | ||
| 1333 | BEGIN_RING(4); | 1336 | BEGIN_RING(4); |
| 1334 | 1337 | ||
| 1335 | RADEON_CLEAR_AGE(dev_priv->sarea_priv->last_clear); | 1338 | RADEON_CLEAR_AGE(sarea_priv->last_clear); |
| 1336 | RADEON_WAIT_UNTIL_IDLE(); | 1339 | RADEON_WAIT_UNTIL_IDLE(); |
| 1337 | 1340 | ||
| 1338 | ADVANCE_RING(); | 1341 | ADVANCE_RING(); |
| 1339 | } | 1342 | } |
| 1340 | 1343 | ||
| 1341 | static void radeon_cp_dispatch_swap(struct drm_device * dev) | 1344 | static void radeon_cp_dispatch_swap(struct drm_device *dev, struct drm_master *master) |
| 1342 | { | 1345 | { |
| 1343 | drm_radeon_private_t *dev_priv = dev->dev_private; | 1346 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 1344 | drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; | 1347 | struct drm_radeon_master_private *master_priv = master->driver_priv; |
| 1348 | drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; | ||
| 1345 | int nbox = sarea_priv->nbox; | 1349 | int nbox = sarea_priv->nbox; |
| 1346 | struct drm_clip_rect *pbox = sarea_priv->boxes; | 1350 | struct drm_clip_rect *pbox = sarea_priv->boxes; |
| 1347 | int i; | 1351 | int i; |
| @@ -1351,7 +1355,7 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev) | |||
| 1351 | /* Do some trivial performance monitoring... | 1355 | /* Do some trivial performance monitoring... |
| 1352 | */ | 1356 | */ |
| 1353 | if (dev_priv->do_boxes) | 1357 | if (dev_priv->do_boxes) |
| 1354 | radeon_cp_performance_boxes(dev_priv); | 1358 | radeon_cp_performance_boxes(dev_priv, master_priv); |
| 1355 | 1359 | ||
| 1356 | /* Wait for the 3D stream to idle before dispatching the bitblt. | 1360 | /* Wait for the 3D stream to idle before dispatching the bitblt. |
| 1357 | * This will prevent data corruption between the two streams. | 1361 | * This will prevent data corruption between the two streams. |
| @@ -1385,7 +1389,7 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev) | |||
| 1385 | /* Make this work even if front & back are flipped: | 1389 | /* Make this work even if front & back are flipped: |
| 1386 | */ | 1390 | */ |
| 1387 | OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1)); | 1391 | OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1)); |
| 1388 | if (dev_priv->sarea_priv->pfCurrentPage == 0) { | 1392 | if (sarea_priv->pfCurrentPage == 0) { |
| 1389 | OUT_RING(dev_priv->back_pitch_offset); | 1393 | OUT_RING(dev_priv->back_pitch_offset); |
| 1390 | OUT_RING(dev_priv->front_pitch_offset); | 1394 | OUT_RING(dev_priv->front_pitch_offset); |
| 1391 | } else { | 1395 | } else { |
| @@ -1405,31 +1409,32 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev) | |||
| 1405 | * throttle the framerate by waiting for this value before | 1409 | * throttle the framerate by waiting for this value before |
| 1406 | * performing the swapbuffer ioctl. | 1410 | * performing the swapbuffer ioctl. |
| 1407 | */ | 1411 | */ |
| 1408 | dev_priv->sarea_priv->last_frame++; | 1412 | sarea_priv->last_frame++; |
| 1409 | 1413 | ||
| 1410 | BEGIN_RING(4); | 1414 | BEGIN_RING(4); |
| 1411 | 1415 | ||
| 1412 | RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame); | 1416 | RADEON_FRAME_AGE(sarea_priv->last_frame); |
| 1413 | RADEON_WAIT_UNTIL_2D_IDLE(); | 1417 | RADEON_WAIT_UNTIL_2D_IDLE(); |
| 1414 | 1418 | ||
| 1415 | ADVANCE_RING(); | 1419 | ADVANCE_RING(); |
| 1416 | } | 1420 | } |
| 1417 | 1421 | ||
| 1418 | static void radeon_cp_dispatch_flip(struct drm_device * dev) | 1422 | void radeon_cp_dispatch_flip(struct drm_device *dev, struct drm_master *master) |
| 1419 | { | 1423 | { |
| 1420 | drm_radeon_private_t *dev_priv = dev->dev_private; | 1424 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 1421 | struct drm_sarea *sarea = (struct drm_sarea *) dev_priv->sarea->handle; | 1425 | struct drm_radeon_master_private *master_priv = master->driver_priv; |
| 1422 | int offset = (dev_priv->sarea_priv->pfCurrentPage == 1) | 1426 | struct drm_sarea *sarea = (struct drm_sarea *)master_priv->sarea->handle; |
| 1427 | int offset = (master_priv->sarea_priv->pfCurrentPage == 1) | ||
| 1423 | ? dev_priv->front_offset : dev_priv->back_offset; | 1428 | ? dev_priv->front_offset : dev_priv->back_offset; |
| 1424 | RING_LOCALS; | 1429 | RING_LOCALS; |
| 1425 | DRM_DEBUG("pfCurrentPage=%d\n", | 1430 | DRM_DEBUG("pfCurrentPage=%d\n", |
| 1426 | dev_priv->sarea_priv->pfCurrentPage); | 1431 | master_priv->sarea_priv->pfCurrentPage); |
| 1427 | 1432 | ||
| 1428 | /* Do some trivial performance monitoring... | 1433 | /* Do some trivial performance monitoring... |
| 1429 | */ | 1434 | */ |
| 1430 | if (dev_priv->do_boxes) { | 1435 | if (dev_priv->do_boxes) { |
| 1431 | dev_priv->stats.boxes |= RADEON_BOX_FLIP; | 1436 | dev_priv->stats.boxes |= RADEON_BOX_FLIP; |
| 1432 | radeon_cp_performance_boxes(dev_priv); | 1437 | radeon_cp_performance_boxes(dev_priv, master_priv); |
| 1433 | } | 1438 | } |
| 1434 | 1439 | ||
| 1435 | /* Update the frame offsets for both CRTCs | 1440 | /* Update the frame offsets for both CRTCs |
| @@ -1441,7 +1446,7 @@ static void radeon_cp_dispatch_flip(struct drm_device * dev) | |||
| 1441 | ((sarea->frame.y * dev_priv->front_pitch + | 1446 | ((sarea->frame.y * dev_priv->front_pitch + |
| 1442 | sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7) | 1447 | sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7) |
| 1443 | + offset); | 1448 | + offset); |
| 1444 | OUT_RING_REG(RADEON_CRTC2_OFFSET, dev_priv->sarea_priv->crtc2_base | 1449 | OUT_RING_REG(RADEON_CRTC2_OFFSET, master_priv->sarea_priv->crtc2_base |
| 1445 | + offset); | 1450 | + offset); |
| 1446 | 1451 | ||
| 1447 | ADVANCE_RING(); | 1452 | ADVANCE_RING(); |
| @@ -1450,13 +1455,13 @@ static void radeon_cp_dispatch_flip(struct drm_device * dev) | |||
| 1450 | * throttle the framerate by waiting for this value before | 1455 | * throttle the framerate by waiting for this value before |
| 1451 | * performing the swapbuffer ioctl. | 1456 | * performing the swapbuffer ioctl. |
| 1452 | */ | 1457 | */ |
| 1453 | dev_priv->sarea_priv->last_frame++; | 1458 | master_priv->sarea_priv->last_frame++; |
| 1454 | dev_priv->sarea_priv->pfCurrentPage = | 1459 | master_priv->sarea_priv->pfCurrentPage = |
| 1455 | 1 - dev_priv->sarea_priv->pfCurrentPage; | 1460 | 1 - master_priv->sarea_priv->pfCurrentPage; |
| 1456 | 1461 | ||
| 1457 | BEGIN_RING(2); | 1462 | BEGIN_RING(2); |
| 1458 | 1463 | ||
| 1459 | RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame); | 1464 | RADEON_FRAME_AGE(master_priv->sarea_priv->last_frame); |
| 1460 | 1465 | ||
| 1461 | ADVANCE_RING(); | 1466 | ADVANCE_RING(); |
| 1462 | } | 1467 | } |
| @@ -1494,11 +1499,13 @@ typedef struct { | |||
| 1494 | } drm_radeon_tcl_prim_t; | 1499 | } drm_radeon_tcl_prim_t; |
| 1495 | 1500 | ||
| 1496 | static void radeon_cp_dispatch_vertex(struct drm_device * dev, | 1501 | static void radeon_cp_dispatch_vertex(struct drm_device * dev, |
| 1502 | struct drm_file *file_priv, | ||
| 1497 | struct drm_buf * buf, | 1503 | struct drm_buf * buf, |
| 1498 | drm_radeon_tcl_prim_t * prim) | 1504 | drm_radeon_tcl_prim_t * prim) |
| 1499 | { | 1505 | { |
| 1500 | drm_radeon_private_t *dev_priv = dev->dev_private; | 1506 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 1501 | drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; | 1507 | struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; |
| 1508 | drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; | ||
| 1502 | int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start; | 1509 | int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start; |
| 1503 | int numverts = (int)prim->numverts; | 1510 | int numverts = (int)prim->numverts; |
| 1504 | int nbox = sarea_priv->nbox; | 1511 | int nbox = sarea_priv->nbox; |
| @@ -1539,13 +1546,14 @@ static void radeon_cp_dispatch_vertex(struct drm_device * dev, | |||
| 1539 | } while (i < nbox); | 1546 | } while (i < nbox); |
| 1540 | } | 1547 | } |
| 1541 | 1548 | ||
| 1542 | static void radeon_cp_discard_buffer(struct drm_device * dev, struct drm_buf * buf) | 1549 | static void radeon_cp_discard_buffer(struct drm_device *dev, struct drm_master *master, struct drm_buf *buf) |
| 1543 | { | 1550 | { |
| 1544 | drm_radeon_private_t *dev_priv = dev->dev_private; | 1551 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 1552 | struct drm_radeon_master_private *master_priv = master->driver_priv; | ||
| 1545 | drm_radeon_buf_priv_t *buf_priv = buf->dev_private; | 1553 | drm_radeon_buf_priv_t *buf_priv = buf->dev_private; |
| 1546 | RING_LOCALS; | 1554 | RING_LOCALS; |
| 1547 | 1555 | ||
| 1548 | buf_priv->age = ++dev_priv->sarea_priv->last_dispatch; | 1556 | buf_priv->age = ++master_priv->sarea_priv->last_dispatch; |
| 1549 | 1557 | ||
| 1550 | /* Emit the vertex buffer age */ | 1558 | /* Emit the vertex buffer age */ |
| 1551 | BEGIN_RING(2); | 1559 | BEGIN_RING(2); |
| @@ -1590,12 +1598,14 @@ static void radeon_cp_dispatch_indirect(struct drm_device * dev, | |||
| 1590 | } | 1598 | } |
| 1591 | } | 1599 | } |
| 1592 | 1600 | ||
| 1593 | static void radeon_cp_dispatch_indices(struct drm_device * dev, | 1601 | static void radeon_cp_dispatch_indices(struct drm_device *dev, |
| 1602 | struct drm_master *master, | ||
| 1594 | struct drm_buf * elt_buf, | 1603 | struct drm_buf * elt_buf, |
| 1595 | drm_radeon_tcl_prim_t * prim) | 1604 | drm_radeon_tcl_prim_t * prim) |
| 1596 | { | 1605 | { |
| 1597 | drm_radeon_private_t *dev_priv = dev->dev_private; | 1606 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 1598 | drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; | 1607 | struct drm_radeon_master_private *master_priv = master->driver_priv; |
| 1608 | drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; | ||
| 1599 | int offset = dev_priv->gart_buffers_offset + prim->offset; | 1609 | int offset = dev_priv->gart_buffers_offset + prim->offset; |
| 1600 | u32 *data; | 1610 | u32 *data; |
| 1601 | int dwords; | 1611 | int dwords; |
| @@ -1870,7 +1880,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev, | |||
| 1870 | ADVANCE_RING(); | 1880 | ADVANCE_RING(); |
| 1871 | COMMIT_RING(); | 1881 | COMMIT_RING(); |
| 1872 | 1882 | ||
| 1873 | radeon_cp_discard_buffer(dev, buf); | 1883 | radeon_cp_discard_buffer(dev, file_priv->master, buf); |
| 1874 | 1884 | ||
| 1875 | /* Update the input parameters for next time */ | 1885 | /* Update the input parameters for next time */ |
| 1876 | image->y += height; | 1886 | image->y += height; |
| @@ -2110,7 +2120,8 @@ static int radeon_surface_free(struct drm_device *dev, void *data, struct drm_fi | |||
| 2110 | static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) | 2120 | static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) |
| 2111 | { | 2121 | { |
| 2112 | drm_radeon_private_t *dev_priv = dev->dev_private; | 2122 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 2113 | drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; | 2123 | struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; |
| 2124 | drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; | ||
| 2114 | drm_radeon_clear_t *clear = data; | 2125 | drm_radeon_clear_t *clear = data; |
| 2115 | drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS]; | 2126 | drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS]; |
| 2116 | DRM_DEBUG("\n"); | 2127 | DRM_DEBUG("\n"); |
| @@ -2126,7 +2137,7 @@ static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file * | |||
| 2126 | sarea_priv->nbox * sizeof(depth_boxes[0]))) | 2137 | sarea_priv->nbox * sizeof(depth_boxes[0]))) |
| 2127 | return -EFAULT; | 2138 | return -EFAULT; |
| 2128 | 2139 | ||
| 2129 | radeon_cp_dispatch_clear(dev, clear, depth_boxes); | 2140 | radeon_cp_dispatch_clear(dev, file_priv->master, clear, depth_boxes); |
| 2130 | 2141 | ||
| 2131 | COMMIT_RING(); | 2142 | COMMIT_RING(); |
| 2132 | return 0; | 2143 | return 0; |
| @@ -2134,9 +2145,10 @@ static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file * | |||
| 2134 | 2145 | ||
| 2135 | /* Not sure why this isn't set all the time: | 2146 | /* Not sure why this isn't set all the time: |
| 2136 | */ | 2147 | */ |
| 2137 | static int radeon_do_init_pageflip(struct drm_device * dev) | 2148 | static int radeon_do_init_pageflip(struct drm_device *dev, struct drm_master *master) |
| 2138 | { | 2149 | { |
| 2139 | drm_radeon_private_t *dev_priv = dev->dev_private; | 2150 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 2151 | struct drm_radeon_master_private *master_priv = master->driver_priv; | ||
| 2140 | RING_LOCALS; | 2152 | RING_LOCALS; |
| 2141 | 2153 | ||
| 2142 | DRM_DEBUG("\n"); | 2154 | DRM_DEBUG("\n"); |
| @@ -2153,8 +2165,8 @@ static int radeon_do_init_pageflip(struct drm_device * dev) | |||
| 2153 | 2165 | ||
| 2154 | dev_priv->page_flipping = 1; | 2166 | dev_priv->page_flipping = 1; |
| 2155 | 2167 | ||
| 2156 | if (dev_priv->sarea_priv->pfCurrentPage != 1) | 2168 | if (master_priv->sarea_priv->pfCurrentPage != 1) |
| 2157 | dev_priv->sarea_priv->pfCurrentPage = 0; | 2169 | master_priv->sarea_priv->pfCurrentPage = 0; |
| 2158 | 2170 | ||
| 2159 | return 0; | 2171 | return 0; |
| 2160 | } | 2172 | } |
| @@ -2172,9 +2184,9 @@ static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *f | |||
| 2172 | RING_SPACE_TEST_WITH_RETURN(dev_priv); | 2184 | RING_SPACE_TEST_WITH_RETURN(dev_priv); |
| 2173 | 2185 | ||
| 2174 | if (!dev_priv->page_flipping) | 2186 | if (!dev_priv->page_flipping) |
| 2175 | radeon_do_init_pageflip(dev); | 2187 | radeon_do_init_pageflip(dev, file_priv->master); |
| 2176 | 2188 | ||
| 2177 | radeon_cp_dispatch_flip(dev); | 2189 | radeon_cp_dispatch_flip(dev, file_priv->master); |
| 2178 | 2190 | ||
| 2179 | COMMIT_RING(); | 2191 | COMMIT_RING(); |
| 2180 | return 0; | 2192 | return 0; |
| @@ -2183,7 +2195,9 @@ static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *f | |||
| 2183 | static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv) | 2195 | static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv) |
| 2184 | { | 2196 | { |
| 2185 | drm_radeon_private_t *dev_priv = dev->dev_private; | 2197 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 2186 | drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; | 2198 | struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; |
| 2199 | drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; | ||
| 2200 | |||
| 2187 | DRM_DEBUG("\n"); | 2201 | DRM_DEBUG("\n"); |
| 2188 | 2202 | ||
| 2189 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 2203 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
| @@ -2193,8 +2207,8 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f | |||
| 2193 | if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) | 2207 | if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) |
| 2194 | sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; | 2208 | sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; |
| 2195 | 2209 | ||
| 2196 | radeon_cp_dispatch_swap(dev); | 2210 | radeon_cp_dispatch_swap(dev, file_priv->master); |
| 2197 | dev_priv->sarea_priv->ctx_owner = 0; | 2211 | sarea_priv->ctx_owner = 0; |
| 2198 | 2212 | ||
| 2199 | COMMIT_RING(); | 2213 | COMMIT_RING(); |
| 2200 | return 0; | 2214 | return 0; |
| @@ -2203,7 +2217,8 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f | |||
| 2203 | static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv) | 2217 | static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv) |
| 2204 | { | 2218 | { |
| 2205 | drm_radeon_private_t *dev_priv = dev->dev_private; | 2219 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 2206 | drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; | 2220 | struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; |
| 2221 | drm_radeon_sarea_t *sarea_priv; | ||
| 2207 | struct drm_device_dma *dma = dev->dma; | 2222 | struct drm_device_dma *dma = dev->dma; |
| 2208 | struct drm_buf *buf; | 2223 | struct drm_buf *buf; |
| 2209 | drm_radeon_vertex_t *vertex = data; | 2224 | drm_radeon_vertex_t *vertex = data; |
| @@ -2211,6 +2226,8 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file | |||
| 2211 | 2226 | ||
| 2212 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 2227 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
| 2213 | 2228 | ||
| 2229 | sarea_priv = master_priv->sarea_priv; | ||
| 2230 | |||
| 2214 | DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n", | 2231 | DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n", |
| 2215 | DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard); | 2232 | DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard); |
| 2216 | 2233 | ||
| @@ -2263,13 +2280,13 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file | |||
| 2263 | prim.finish = vertex->count; /* unused */ | 2280 | prim.finish = vertex->count; /* unused */ |
| 2264 | prim.prim = vertex->prim; | 2281 | prim.prim = vertex->prim; |
| 2265 | prim.numverts = vertex->count; | 2282 | prim.numverts = vertex->count; |
| 2266 | prim.vc_format = dev_priv->sarea_priv->vc_format; | 2283 | prim.vc_format = sarea_priv->vc_format; |
| 2267 | 2284 | ||
| 2268 | radeon_cp_dispatch_vertex(dev, buf, &prim); | 2285 | radeon_cp_dispatch_vertex(dev, file_priv, buf, &prim); |
| 2269 | } | 2286 | } |
| 2270 | 2287 | ||
| 2271 | if (vertex->discard) { | 2288 | if (vertex->discard) { |
| 2272 | radeon_cp_discard_buffer(dev, buf); | 2289 | radeon_cp_discard_buffer(dev, file_priv->master, buf); |
| 2273 | } | 2290 | } |
| 2274 | 2291 | ||
| 2275 | COMMIT_RING(); | 2292 | COMMIT_RING(); |
| @@ -2279,7 +2296,8 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file | |||
| 2279 | static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv) | 2296 | static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv) |
| 2280 | { | 2297 | { |
| 2281 | drm_radeon_private_t *dev_priv = dev->dev_private; | 2298 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 2282 | drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; | 2299 | struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; |
| 2300 | drm_radeon_sarea_t *sarea_priv; | ||
| 2283 | struct drm_device_dma *dma = dev->dma; | 2301 | struct drm_device_dma *dma = dev->dma; |
| 2284 | struct drm_buf *buf; | 2302 | struct drm_buf *buf; |
| 2285 | drm_radeon_indices_t *elts = data; | 2303 | drm_radeon_indices_t *elts = data; |
| @@ -2288,6 +2306,8 @@ static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file | |||
| 2288 | 2306 | ||
| 2289 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 2307 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
| 2290 | 2308 | ||
| 2309 | sarea_priv = master_priv->sarea_priv; | ||
| 2310 | |||
| 2291 | DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n", | 2311 | DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n", |
| 2292 | DRM_CURRENTPID, elts->idx, elts->start, elts->end, | 2312 | DRM_CURRENTPID, elts->idx, elts->start, elts->end, |
| 2293 | elts->discard); | 2313 | elts->discard); |
| @@ -2353,11 +2373,11 @@ static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file | |||
| 2353 | prim.prim = elts->prim; | 2373 | prim.prim = elts->prim; |
| 2354 | prim.offset = 0; /* offset from start of dma buffers */ | 2374 | prim.offset = 0; /* offset from start of dma buffers */ |
| 2355 | prim.numverts = RADEON_MAX_VB_VERTS; /* duh */ | 2375 | prim.numverts = RADEON_MAX_VB_VERTS; /* duh */ |
| 2356 | prim.vc_format = dev_priv->sarea_priv->vc_format; | 2376 | prim.vc_format = sarea_priv->vc_format; |
| 2357 | 2377 | ||
| 2358 | radeon_cp_dispatch_indices(dev, buf, &prim); | 2378 | radeon_cp_dispatch_indices(dev, file_priv->master, buf, &prim); |
| 2359 | if (elts->discard) { | 2379 | if (elts->discard) { |
| 2360 | radeon_cp_discard_buffer(dev, buf); | 2380 | radeon_cp_discard_buffer(dev, file_priv->master, buf); |
| 2361 | } | 2381 | } |
| 2362 | 2382 | ||
| 2363 | COMMIT_RING(); | 2383 | COMMIT_RING(); |
| @@ -2468,7 +2488,7 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil | |||
| 2468 | */ | 2488 | */ |
| 2469 | radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end); | 2489 | radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end); |
| 2470 | if (indirect->discard) { | 2490 | if (indirect->discard) { |
| 2471 | radeon_cp_discard_buffer(dev, buf); | 2491 | radeon_cp_discard_buffer(dev, file_priv->master, buf); |
| 2472 | } | 2492 | } |
| 2473 | 2493 | ||
| 2474 | COMMIT_RING(); | 2494 | COMMIT_RING(); |
| @@ -2478,7 +2498,8 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil | |||
| 2478 | static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv) | 2498 | static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv) |
| 2479 | { | 2499 | { |
| 2480 | drm_radeon_private_t *dev_priv = dev->dev_private; | 2500 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 2481 | drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; | 2501 | struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; |
| 2502 | drm_radeon_sarea_t *sarea_priv; | ||
| 2482 | struct drm_device_dma *dma = dev->dma; | 2503 | struct drm_device_dma *dma = dev->dma; |
| 2483 | struct drm_buf *buf; | 2504 | struct drm_buf *buf; |
| 2484 | drm_radeon_vertex2_t *vertex = data; | 2505 | drm_radeon_vertex2_t *vertex = data; |
| @@ -2487,6 +2508,8 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file | |||
| 2487 | 2508 | ||
| 2488 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 2509 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
| 2489 | 2510 | ||
| 2511 | sarea_priv = master_priv->sarea_priv; | ||
| 2512 | |||
| 2490 | DRM_DEBUG("pid=%d index=%d discard=%d\n", | 2513 | DRM_DEBUG("pid=%d index=%d discard=%d\n", |
| 2491 | DRM_CURRENTPID, vertex->idx, vertex->discard); | 2514 | DRM_CURRENTPID, vertex->idx, vertex->discard); |
| 2492 | 2515 | ||
| @@ -2547,12 +2570,12 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file | |||
| 2547 | tclprim.offset = prim.numverts * 64; | 2570 | tclprim.offset = prim.numverts * 64; |
| 2548 | tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */ | 2571 | tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */ |
| 2549 | 2572 | ||
| 2550 | radeon_cp_dispatch_indices(dev, buf, &tclprim); | 2573 | radeon_cp_dispatch_indices(dev, file_priv->master, buf, &tclprim); |
| 2551 | } else { | 2574 | } else { |
| 2552 | tclprim.numverts = prim.numverts; | 2575 | tclprim.numverts = prim.numverts; |
| 2553 | tclprim.offset = 0; /* not used */ | 2576 | tclprim.offset = 0; /* not used */ |
| 2554 | 2577 | ||
| 2555 | radeon_cp_dispatch_vertex(dev, buf, &tclprim); | 2578 | radeon_cp_dispatch_vertex(dev, file_priv, buf, &tclprim); |
| 2556 | } | 2579 | } |
| 2557 | 2580 | ||
| 2558 | if (sarea_priv->nbox == 1) | 2581 | if (sarea_priv->nbox == 1) |
| @@ -2560,7 +2583,7 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file | |||
| 2560 | } | 2583 | } |
| 2561 | 2584 | ||
| 2562 | if (vertex->discard) { | 2585 | if (vertex->discard) { |
| 2563 | radeon_cp_discard_buffer(dev, buf); | 2586 | radeon_cp_discard_buffer(dev, file_priv->master, buf); |
| 2564 | } | 2587 | } |
| 2565 | 2588 | ||
| 2566 | COMMIT_RING(); | 2589 | COMMIT_RING(); |
| @@ -2909,7 +2932,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file | |||
| 2909 | goto err; | 2932 | goto err; |
| 2910 | } | 2933 | } |
| 2911 | 2934 | ||
| 2912 | radeon_cp_discard_buffer(dev, buf); | 2935 | radeon_cp_discard_buffer(dev, file_priv->master, buf); |
| 2913 | break; | 2936 | break; |
| 2914 | 2937 | ||
| 2915 | case RADEON_CMD_PACKET3: | 2938 | case RADEON_CMD_PACKET3: |
| @@ -3020,7 +3043,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil | |||
| 3020 | */ | 3043 | */ |
| 3021 | case RADEON_PARAM_SAREA_HANDLE: | 3044 | case RADEON_PARAM_SAREA_HANDLE: |
| 3022 | /* The lock is the first dword in the sarea. */ | 3045 | /* The lock is the first dword in the sarea. */ |
| 3023 | value = (long)dev->lock.hw_lock; | 3046 | /* no users of this parameter */ |
| 3024 | break; | 3047 | break; |
| 3025 | #endif | 3048 | #endif |
| 3026 | case RADEON_PARAM_GART_TEX_HANDLE: | 3049 | case RADEON_PARAM_GART_TEX_HANDLE: |
| @@ -3064,6 +3087,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil | |||
| 3064 | static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv) | 3087 | static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv) |
| 3065 | { | 3088 | { |
| 3066 | drm_radeon_private_t *dev_priv = dev->dev_private; | 3089 | drm_radeon_private_t *dev_priv = dev->dev_private; |
| 3090 | struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; | ||
| 3067 | drm_radeon_setparam_t *sp = data; | 3091 | drm_radeon_setparam_t *sp = data; |
| 3068 | struct drm_radeon_driver_file_fields *radeon_priv; | 3092 | struct drm_radeon_driver_file_fields *radeon_priv; |
| 3069 | 3093 | ||
| @@ -3078,12 +3102,14 @@ static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_fil | |||
| 3078 | DRM_DEBUG("color tiling disabled\n"); | 3102 | DRM_DEBUG("color tiling disabled\n"); |
| 3079 | dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO; | 3103 | dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO; |
| 3080 | dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO; | 3104 | dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO; |
| 3081 | dev_priv->sarea_priv->tiling_enabled = 0; | 3105 | if (master_priv->sarea_priv) |
| 3106 | master_priv->sarea_priv->tiling_enabled = 0; | ||
| 3082 | } else if (sp->value == 1) { | 3107 | } else if (sp->value == 1) { |
| 3083 | DRM_DEBUG("color tiling enabled\n"); | 3108 | DRM_DEBUG("color tiling enabled\n"); |
| 3084 | dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO; | 3109 | dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO; |
| 3085 | dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO; | 3110 | dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO; |
| 3086 | dev_priv->sarea_priv->tiling_enabled = 1; | 3111 | if (master_priv->sarea_priv) |
| 3112 | master_priv->sarea_priv->tiling_enabled = 1; | ||
| 3087 | } | 3113 | } |
| 3088 | break; | 3114 | break; |
| 3089 | case RADEON_SETPARAM_PCIGART_LOCATION: | 3115 | case RADEON_SETPARAM_PCIGART_LOCATION: |
| @@ -3129,14 +3155,6 @@ void radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv) | |||
| 3129 | 3155 | ||
| 3130 | void radeon_driver_lastclose(struct drm_device *dev) | 3156 | void radeon_driver_lastclose(struct drm_device *dev) |
| 3131 | { | 3157 | { |
| 3132 | if (dev->dev_private) { | ||
| 3133 | drm_radeon_private_t *dev_priv = dev->dev_private; | ||
| 3134 | |||
| 3135 | if (dev_priv->sarea_priv && | ||
| 3136 | dev_priv->sarea_priv->pfCurrentPage != 0) | ||
| 3137 | radeon_cp_dispatch_flip(dev); | ||
| 3138 | } | ||
| 3139 | |||
| 3140 | radeon_do_release(dev); | 3158 | radeon_do_release(dev); |
| 3141 | } | 3159 | } |
| 3142 | 3160 | ||
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 448d209a0bf2..e6210725b9ab 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c | |||
| @@ -112,6 +112,23 @@ static int vga_video_font_height; | |||
| 112 | static int vga_scan_lines __read_mostly; | 112 | static int vga_scan_lines __read_mostly; |
| 113 | static unsigned int vga_rolled_over; | 113 | static unsigned int vga_rolled_over; |
| 114 | 114 | ||
| 115 | int vgacon_text_mode_force = 0; | ||
| 116 | |||
| 117 | bool vgacon_text_force(void) | ||
| 118 | { | ||
| 119 | return vgacon_text_mode_force ? true : false; | ||
| 120 | } | ||
| 121 | EXPORT_SYMBOL(vgacon_text_force); | ||
| 122 | |||
| 123 | static int __init text_mode(char *str) | ||
| 124 | { | ||
| 125 | vgacon_text_mode_force = 1; | ||
| 126 | return 1; | ||
| 127 | } | ||
| 128 | |||
| 129 | /* force text mode - used by kernel modesetting */ | ||
| 130 | __setup("nomodeset", text_mode); | ||
| 131 | |||
| 115 | static int __init no_scroll(char *str) | 132 | static int __init no_scroll(char *str) |
| 116 | { | 133 | { |
| 117 | /* | 134 | /* |
diff --git a/include/drm/Kbuild b/include/drm/Kbuild index 82b6983b7fbb..b940fdfa3b25 100644 --- a/include/drm/Kbuild +++ b/include/drm/Kbuild | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | unifdef-y += drm.h drm_sarea.h | 1 | unifdef-y += drm.h drm_sarea.h drm_mode.h |
| 2 | unifdef-y += i810_drm.h | 2 | unifdef-y += i810_drm.h |
| 3 | unifdef-y += i830_drm.h | 3 | unifdef-y += i830_drm.h |
| 4 | unifdef-y += i915_drm.h | 4 | unifdef-y += i915_drm.h |
diff --git a/include/drm/drm.h b/include/drm/drm.h index f46ba4b57da4..32e5096554e9 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h | |||
| @@ -173,6 +173,7 @@ enum drm_map_type { | |||
| 173 | _DRM_AGP = 3, /**< AGP/GART */ | 173 | _DRM_AGP = 3, /**< AGP/GART */ |
| 174 | _DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */ | 174 | _DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */ |
| 175 | _DRM_CONSISTENT = 5, /**< Consistent memory for PCI DMA */ | 175 | _DRM_CONSISTENT = 5, /**< Consistent memory for PCI DMA */ |
| 176 | _DRM_GEM = 6, /**< GEM object */ | ||
| 176 | }; | 177 | }; |
| 177 | 178 | ||
| 178 | /** | 179 | /** |
| @@ -598,6 +599,8 @@ struct drm_gem_open { | |||
| 598 | uint64_t size; | 599 | uint64_t size; |
| 599 | }; | 600 | }; |
| 600 | 601 | ||
| 602 | #include "drm_mode.h" | ||
| 603 | |||
| 601 | #define DRM_IOCTL_BASE 'd' | 604 | #define DRM_IOCTL_BASE 'd' |
| 602 | #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) | 605 | #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) |
| 603 | #define DRM_IOR(nr,type) _IOR(DRM_IOCTL_BASE,nr,type) | 606 | #define DRM_IOR(nr,type) _IOR(DRM_IOCTL_BASE,nr,type) |
| @@ -634,6 +637,9 @@ struct drm_gem_open { | |||
| 634 | #define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, struct drm_ctx_priv_map) | 637 | #define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, struct drm_ctx_priv_map) |
| 635 | #define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, struct drm_ctx_priv_map) | 638 | #define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, struct drm_ctx_priv_map) |
| 636 | 639 | ||
| 640 | #define DRM_IOCTL_SET_MASTER DRM_IO(0x1e) | ||
| 641 | #define DRM_IOCTL_DROP_MASTER DRM_IO(0x1f) | ||
| 642 | |||
| 637 | #define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, struct drm_ctx) | 643 | #define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, struct drm_ctx) |
| 638 | #define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, struct drm_ctx) | 644 | #define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, struct drm_ctx) |
| 639 | #define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, struct drm_ctx) | 645 | #define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, struct drm_ctx) |
| @@ -664,6 +670,24 @@ struct drm_gem_open { | |||
| 664 | 670 | ||
| 665 | #define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, struct drm_update_draw) | 671 | #define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, struct drm_update_draw) |
| 666 | 672 | ||
| 673 | #define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) | ||
| 674 | #define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) | ||
| 675 | #define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA2, struct drm_mode_crtc) | ||
| 676 | #define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xA3, struct drm_mode_cursor) | ||
| 677 | #define DRM_IOCTL_MODE_GETGAMMA DRM_IOWR(0xA4, struct drm_mode_crtc_lut) | ||
| 678 | #define DRM_IOCTL_MODE_SETGAMMA DRM_IOWR(0xA5, struct drm_mode_crtc_lut) | ||
| 679 | #define DRM_IOCTL_MODE_GETENCODER DRM_IOWR(0xA6, struct drm_mode_get_encoder) | ||
| 680 | #define DRM_IOCTL_MODE_GETCONNECTOR DRM_IOWR(0xA7, struct drm_mode_get_connector) | ||
| 681 | #define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA8, struct drm_mode_mode_cmd) | ||
| 682 | #define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) | ||
| 683 | |||
| 684 | #define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAA, struct drm_mode_get_property) | ||
| 685 | #define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xAB, struct drm_mode_connector_set_property) | ||
| 686 | #define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xAC, struct drm_mode_get_blob) | ||
| 687 | #define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xAD, struct drm_mode_fb_cmd) | ||
| 688 | #define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd) | ||
| 689 | #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, unsigned int) | ||
| 690 | |||
| 667 | /** | 691 | /** |
| 668 | * Device specific ioctls should only be in their respective headers | 692 | * Device specific ioctls should only be in their respective headers |
| 669 | * The device specific ioctl range is from 0x40 to 0x99. | 693 | * The device specific ioctl range is from 0x40 to 0x99. |
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index d5e8e5c89548..afb7858c068d 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
| @@ -105,6 +105,7 @@ struct drm_device; | |||
| 105 | #define DRIVER_FB_DMA 0x400 | 105 | #define DRIVER_FB_DMA 0x400 |
| 106 | #define DRIVER_IRQ_VBL2 0x800 | 106 | #define DRIVER_IRQ_VBL2 0x800 |
| 107 | #define DRIVER_GEM 0x1000 | 107 | #define DRIVER_GEM 0x1000 |
| 108 | #define DRIVER_MODESET 0x2000 | ||
| 108 | 109 | ||
| 109 | /***********************************************************************/ | 110 | /***********************************************************************/ |
| 110 | /** \name Begin the DRM... */ | 111 | /** \name Begin the DRM... */ |
| @@ -238,11 +239,11 @@ struct drm_device; | |||
| 238 | */ | 239 | */ |
| 239 | #define LOCK_TEST_WITH_RETURN( dev, file_priv ) \ | 240 | #define LOCK_TEST_WITH_RETURN( dev, file_priv ) \ |
| 240 | do { \ | 241 | do { \ |
| 241 | if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ | 242 | if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock) || \ |
| 242 | dev->lock.file_priv != file_priv ) { \ | 243 | file_priv->master->lock.file_priv != file_priv) { \ |
| 243 | DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\ | 244 | DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\ |
| 244 | __func__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\ | 245 | __func__, _DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock),\ |
| 245 | dev->lock.file_priv, file_priv ); \ | 246 | file_priv->master->lock.file_priv, file_priv); \ |
| 246 | return -EINVAL; \ | 247 | return -EINVAL; \ |
| 247 | } \ | 248 | } \ |
| 248 | } while (0) | 249 | } while (0) |
| @@ -276,6 +277,7 @@ typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd, | |||
| 276 | #define DRM_AUTH 0x1 | 277 | #define DRM_AUTH 0x1 |
| 277 | #define DRM_MASTER 0x2 | 278 | #define DRM_MASTER 0x2 |
| 278 | #define DRM_ROOT_ONLY 0x4 | 279 | #define DRM_ROOT_ONLY 0x4 |
| 280 | #define DRM_CONTROL_ALLOW 0x8 | ||
| 279 | 281 | ||
| 280 | struct drm_ioctl_desc { | 282 | struct drm_ioctl_desc { |
| 281 | unsigned int cmd; | 283 | unsigned int cmd; |
| @@ -379,21 +381,26 @@ struct drm_buf_entry { | |||
| 379 | /** File private data */ | 381 | /** File private data */ |
| 380 | struct drm_file { | 382 | struct drm_file { |
| 381 | int authenticated; | 383 | int authenticated; |
| 382 | int master; | ||
| 383 | pid_t pid; | 384 | pid_t pid; |
| 384 | uid_t uid; | 385 | uid_t uid; |
| 385 | drm_magic_t magic; | 386 | drm_magic_t magic; |
| 386 | unsigned long ioctl_count; | 387 | unsigned long ioctl_count; |
| 387 | struct list_head lhead; | 388 | struct list_head lhead; |
| 388 | struct drm_minor *minor; | 389 | struct drm_minor *minor; |
| 389 | int remove_auth_on_close; | ||
| 390 | unsigned long lock_count; | 390 | unsigned long lock_count; |
| 391 | |||
| 391 | /** Mapping of mm object handles to object pointers. */ | 392 | /** Mapping of mm object handles to object pointers. */ |
| 392 | struct idr object_idr; | 393 | struct idr object_idr; |
| 393 | /** Lock for synchronization of access to object_idr. */ | 394 | /** Lock for synchronization of access to object_idr. */ |
| 394 | spinlock_t table_lock; | 395 | spinlock_t table_lock; |
| 396 | |||
| 395 | struct file *filp; | 397 | struct file *filp; |
| 396 | void *driver_priv; | 398 | void *driver_priv; |
| 399 | |||
| 400 | int is_master; /* this file private is a master for a minor */ | ||
| 401 | struct drm_master *master; /* master this node is currently associated with | ||
| 402 | N.B. not always minor->master */ | ||
| 403 | struct list_head fbs; | ||
| 397 | }; | 404 | }; |
| 398 | 405 | ||
| 399 | /** Wait queue */ | 406 | /** Wait queue */ |
| @@ -523,6 +530,8 @@ struct drm_map_list { | |||
| 523 | struct drm_hash_item hash; | 530 | struct drm_hash_item hash; |
| 524 | struct drm_map *map; /**< mapping */ | 531 | struct drm_map *map; /**< mapping */ |
| 525 | uint64_t user_token; | 532 | uint64_t user_token; |
| 533 | struct drm_master *master; | ||
| 534 | struct drm_mm_node *file_offset_node; /**< fake offset */ | ||
| 526 | }; | 535 | }; |
| 527 | 536 | ||
| 528 | typedef struct drm_map drm_local_map_t; | 537 | typedef struct drm_map drm_local_map_t; |
| @@ -563,6 +572,14 @@ struct drm_ati_pcigart_info { | |||
| 563 | }; | 572 | }; |
| 564 | 573 | ||
| 565 | /** | 574 | /** |
| 575 | * GEM specific mm private for tracking GEM objects | ||
| 576 | */ | ||
| 577 | struct drm_gem_mm { | ||
| 578 | struct drm_mm offset_manager; /**< Offset mgmt for buffer objects */ | ||
| 579 | struct drm_open_hash offset_hash; /**< User token hash table for maps */ | ||
| 580 | }; | ||
| 581 | |||
| 582 | /** | ||
| 566 | * This structure defines the drm_mm memory object, which will be used by the | 583 | * This structure defines the drm_mm memory object, which will be used by the |
| 567 | * DRM for its buffer objects. | 584 | * DRM for its buffer objects. |
| 568 | */ | 585 | */ |
| @@ -579,6 +596,9 @@ struct drm_gem_object { | |||
| 579 | /** File representing the shmem storage */ | 596 | /** File representing the shmem storage */ |
| 580 | struct file *filp; | 597 | struct file *filp; |
| 581 | 598 | ||
| 599 | /* Mapping info for this object */ | ||
| 600 | struct drm_map_list map_list; | ||
| 601 | |||
| 582 | /** | 602 | /** |
| 583 | * Size of the object, in bytes. Immutable over the object's | 603 | * Size of the object, in bytes. Immutable over the object's |
| 584 | * lifetime. | 604 | * lifetime. |
| @@ -612,6 +632,33 @@ struct drm_gem_object { | |||
| 612 | void *driver_private; | 632 | void *driver_private; |
| 613 | }; | 633 | }; |
| 614 | 634 | ||
| 635 | #include "drm_crtc.h" | ||
| 636 | |||
| 637 | /* per-master structure */ | ||
| 638 | struct drm_master { | ||
| 639 | |||
| 640 | struct kref refcount; /* refcount for this master */ | ||
| 641 | |||
| 642 | struct list_head head; /**< each minor contains a list of masters */ | ||
| 643 | struct drm_minor *minor; /**< link back to minor we are a master for */ | ||
| 644 | |||
| 645 | char *unique; /**< Unique identifier: e.g., busid */ | ||
| 646 | int unique_len; /**< Length of unique field */ | ||
| 647 | int unique_size; /**< amount allocated */ | ||
| 648 | |||
| 649 | int blocked; /**< Blocked due to VC switch? */ | ||
| 650 | |||
| 651 | /** \name Authentication */ | ||
| 652 | /*@{ */ | ||
| 653 | struct drm_open_hash magiclist; | ||
| 654 | struct list_head magicfree; | ||
| 655 | /*@} */ | ||
| 656 | |||
| 657 | struct drm_lock_data lock; /**< Information on hardware lock */ | ||
| 658 | |||
| 659 | void *driver_priv; /**< Private structure for driver to use */ | ||
| 660 | }; | ||
| 661 | |||
| 615 | /** | 662 | /** |
| 616 | * DRM driver structure. This structure represent the common code for | 663 | * DRM driver structure. This structure represent the common code for |
| 617 | * a family of cards. There will one drm_device for each card present | 664 | * a family of cards. There will one drm_device for each card present |
| @@ -712,6 +759,10 @@ struct drm_driver { | |||
| 712 | void (*set_version) (struct drm_device *dev, | 759 | void (*set_version) (struct drm_device *dev, |
| 713 | struct drm_set_version *sv); | 760 | struct drm_set_version *sv); |
| 714 | 761 | ||
| 762 | /* Master routines */ | ||
| 763 | int (*master_create)(struct drm_device *dev, struct drm_master *master); | ||
| 764 | void (*master_destroy)(struct drm_device *dev, struct drm_master *master); | ||
| 765 | |||
| 715 | int (*proc_init)(struct drm_minor *minor); | 766 | int (*proc_init)(struct drm_minor *minor); |
| 716 | void (*proc_cleanup)(struct drm_minor *minor); | 767 | void (*proc_cleanup)(struct drm_minor *minor); |
| 717 | 768 | ||
| @@ -724,6 +775,9 @@ struct drm_driver { | |||
| 724 | int (*gem_init_object) (struct drm_gem_object *obj); | 775 | int (*gem_init_object) (struct drm_gem_object *obj); |
| 725 | void (*gem_free_object) (struct drm_gem_object *obj); | 776 | void (*gem_free_object) (struct drm_gem_object *obj); |
| 726 | 777 | ||
| 778 | /* Driver private ops for this object */ | ||
| 779 | struct vm_operations_struct *gem_vm_ops; | ||
| 780 | |||
| 727 | int major; | 781 | int major; |
| 728 | int minor; | 782 | int minor; |
| 729 | int patchlevel; | 783 | int patchlevel; |
| @@ -737,10 +791,14 @@ struct drm_driver { | |||
| 737 | int num_ioctls; | 791 | int num_ioctls; |
| 738 | struct file_operations fops; | 792 | struct file_operations fops; |
| 739 | struct pci_driver pci_driver; | 793 | struct pci_driver pci_driver; |
| 794 | /* List of devices hanging off this driver */ | ||
| 795 | struct list_head device_list; | ||
| 740 | }; | 796 | }; |
| 741 | 797 | ||
| 742 | #define DRM_MINOR_UNASSIGNED 0 | 798 | #define DRM_MINOR_UNASSIGNED 0 |
| 743 | #define DRM_MINOR_LEGACY 1 | 799 | #define DRM_MINOR_LEGACY 1 |
| 800 | #define DRM_MINOR_CONTROL 2 | ||
| 801 | #define DRM_MINOR_RENDER 3 | ||
| 744 | 802 | ||
| 745 | /** | 803 | /** |
| 746 | * DRM minor structure. This structure represents a drm minor number. | 804 | * DRM minor structure. This structure represents a drm minor number. |
| @@ -752,6 +810,9 @@ struct drm_minor { | |||
| 752 | struct device kdev; /**< Linux device */ | 810 | struct device kdev; /**< Linux device */ |
| 753 | struct drm_device *dev; | 811 | struct drm_device *dev; |
| 754 | struct proc_dir_entry *dev_root; /**< proc directory entry */ | 812 | struct proc_dir_entry *dev_root; /**< proc directory entry */ |
| 813 | struct drm_master *master; /* currently active master for this node */ | ||
| 814 | struct list_head master_list; | ||
| 815 | struct drm_mode_group mode_group; | ||
| 755 | }; | 816 | }; |
| 756 | 817 | ||
| 757 | /** | 818 | /** |
| @@ -759,13 +820,10 @@ struct drm_minor { | |||
| 759 | * may contain multiple heads. | 820 | * may contain multiple heads. |
| 760 | */ | 821 | */ |
| 761 | struct drm_device { | 822 | struct drm_device { |
| 762 | char *unique; /**< Unique identifier: e.g., busid */ | 823 | struct list_head driver_item; /**< list of devices per driver */ |
| 763 | int unique_len; /**< Length of unique field */ | ||
| 764 | char *devname; /**< For /proc/interrupts */ | 824 | char *devname; /**< For /proc/interrupts */ |
| 765 | int if_version; /**< Highest interface version set */ | 825 | int if_version; /**< Highest interface version set */ |
| 766 | 826 | ||
| 767 | int blocked; /**< Blocked due to VC switch? */ | ||
| 768 | |||
| 769 | /** \name Locks */ | 827 | /** \name Locks */ |
| 770 | /*@{ */ | 828 | /*@{ */ |
| 771 | spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ | 829 | spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ |
| @@ -788,12 +846,7 @@ struct drm_device { | |||
| 788 | atomic_t counts[15]; | 846 | atomic_t counts[15]; |
| 789 | /*@} */ | 847 | /*@} */ |
| 790 | 848 | ||
| 791 | /** \name Authentication */ | ||
| 792 | /*@{ */ | ||
| 793 | struct list_head filelist; | 849 | struct list_head filelist; |
| 794 | struct drm_open_hash magiclist; /**< magic hash table */ | ||
| 795 | struct list_head magicfree; | ||
| 796 | /*@} */ | ||
| 797 | 850 | ||
| 798 | /** \name Memory management */ | 851 | /** \name Memory management */ |
| 799 | /*@{ */ | 852 | /*@{ */ |
| @@ -810,7 +863,7 @@ struct drm_device { | |||
| 810 | struct idr ctx_idr; | 863 | struct idr ctx_idr; |
| 811 | 864 | ||
| 812 | struct list_head vmalist; /**< List of vmas (for debugging) */ | 865 | struct list_head vmalist; /**< List of vmas (for debugging) */ |
| 813 | struct drm_lock_data lock; /**< Information on hardware lock */ | 866 | |
| 814 | /*@} */ | 867 | /*@} */ |
| 815 | 868 | ||
| 816 | /** \name DMA queues (contexts) */ | 869 | /** \name DMA queues (contexts) */ |
| @@ -858,6 +911,7 @@ struct drm_device { | |||
| 858 | int *vblank_enabled; /* so we don't call enable more than | 911 | int *vblank_enabled; /* so we don't call enable more than |
| 859 | once per disable */ | 912 | once per disable */ |
| 860 | int *vblank_inmodeset; /* Display driver is setting mode */ | 913 | int *vblank_inmodeset; /* Display driver is setting mode */ |
| 914 | u32 *last_vblank_wait; /* Last vblank seqno waited per CRTC */ | ||
| 861 | struct timer_list vblank_disable_timer; | 915 | struct timer_list vblank_disable_timer; |
| 862 | 916 | ||
| 863 | u32 max_vblank_count; /**< size of vblank counter register */ | 917 | u32 max_vblank_count; /**< size of vblank counter register */ |
| @@ -881,12 +935,15 @@ struct drm_device { | |||
| 881 | struct drm_sg_mem *sg; /**< Scatter gather memory */ | 935 | struct drm_sg_mem *sg; /**< Scatter gather memory */ |
| 882 | int num_crtcs; /**< Number of CRTCs on this device */ | 936 | int num_crtcs; /**< Number of CRTCs on this device */ |
| 883 | void *dev_private; /**< device private data */ | 937 | void *dev_private; /**< device private data */ |
| 938 | void *mm_private; | ||
| 939 | struct address_space *dev_mapping; | ||
| 884 | struct drm_sigdata sigdata; /**< For block_all_signals */ | 940 | struct drm_sigdata sigdata; /**< For block_all_signals */ |
| 885 | sigset_t sigmask; | 941 | sigset_t sigmask; |
| 886 | 942 | ||
| 887 | struct drm_driver *driver; | 943 | struct drm_driver *driver; |
| 888 | drm_local_map_t *agp_buffer_map; | 944 | drm_local_map_t *agp_buffer_map; |
| 889 | unsigned int agp_buffer_token; | 945 | unsigned int agp_buffer_token; |
| 946 | struct drm_minor *control; /**< Control node for card */ | ||
| 890 | struct drm_minor *primary; /**< render type primary screen head */ | 947 | struct drm_minor *primary; /**< render type primary screen head */ |
| 891 | 948 | ||
| 892 | /** \name Drawable information */ | 949 | /** \name Drawable information */ |
| @@ -895,6 +952,8 @@ struct drm_device { | |||
| 895 | struct idr drw_idr; | 952 | struct idr drw_idr; |
| 896 | /*@} */ | 953 | /*@} */ |
| 897 | 954 | ||
| 955 | struct drm_mode_config mode_config; /**< Current mode config */ | ||
| 956 | |||
| 898 | /** \name GEM information */ | 957 | /** \name GEM information */ |
| 899 | /*@{ */ | 958 | /*@{ */ |
| 900 | spinlock_t object_name_lock; | 959 | spinlock_t object_name_lock; |
| @@ -997,6 +1056,8 @@ extern int drm_release(struct inode *inode, struct file *filp); | |||
| 997 | 1056 | ||
| 998 | /* Mapping support (drm_vm.h) */ | 1057 | /* Mapping support (drm_vm.h) */ |
| 999 | extern int drm_mmap(struct file *filp, struct vm_area_struct *vma); | 1058 | extern int drm_mmap(struct file *filp, struct vm_area_struct *vma); |
| 1059 | extern int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma); | ||
| 1060 | extern void drm_vm_open_locked(struct vm_area_struct *vma); | ||
| 1000 | extern unsigned long drm_core_get_map_ofs(struct drm_map * map); | 1061 | extern unsigned long drm_core_get_map_ofs(struct drm_map * map); |
| 1001 | extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev); | 1062 | extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev); |
| 1002 | extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); | 1063 | extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); |
| @@ -1153,6 +1214,8 @@ extern int drm_vblank_get(struct drm_device *dev, int crtc); | |||
| 1153 | extern void drm_vblank_put(struct drm_device *dev, int crtc); | 1214 | extern void drm_vblank_put(struct drm_device *dev, int crtc); |
| 1154 | extern void drm_vblank_cleanup(struct drm_device *dev); | 1215 | extern void drm_vblank_cleanup(struct drm_device *dev); |
| 1155 | /* Modesetting support */ | 1216 | /* Modesetting support */ |
| 1217 | extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc); | ||
| 1218 | extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc); | ||
| 1156 | extern int drm_modeset_ctl(struct drm_device *dev, void *data, | 1219 | extern int drm_modeset_ctl(struct drm_device *dev, void *data, |
| 1157 | struct drm_file *file_priv); | 1220 | struct drm_file *file_priv); |
| 1158 | 1221 | ||
| @@ -1189,6 +1252,13 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle); | |||
| 1189 | extern void drm_agp_chipset_flush(struct drm_device *dev); | 1252 | extern void drm_agp_chipset_flush(struct drm_device *dev); |
| 1190 | 1253 | ||
| 1191 | /* Stub support (drm_stub.h) */ | 1254 | /* Stub support (drm_stub.h) */ |
| 1255 | extern int drm_setmaster_ioctl(struct drm_device *dev, void *data, | ||
| 1256 | struct drm_file *file_priv); | ||
| 1257 | extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data, | ||
| 1258 | struct drm_file *file_priv); | ||
| 1259 | struct drm_master *drm_master_create(struct drm_minor *minor); | ||
| 1260 | extern struct drm_master *drm_master_get(struct drm_master *master); | ||
| 1261 | extern void drm_master_put(struct drm_master **master); | ||
| 1192 | extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, | 1262 | extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, |
| 1193 | struct drm_driver *driver); | 1263 | struct drm_driver *driver); |
| 1194 | extern int drm_put_dev(struct drm_device *dev); | 1264 | extern int drm_put_dev(struct drm_device *dev); |
| @@ -1231,7 +1301,11 @@ struct drm_sysfs_class; | |||
| 1231 | extern struct class *drm_sysfs_create(struct module *owner, char *name); | 1301 | extern struct class *drm_sysfs_create(struct module *owner, char *name); |
| 1232 | extern void drm_sysfs_destroy(void); | 1302 | extern void drm_sysfs_destroy(void); |
| 1233 | extern int drm_sysfs_device_add(struct drm_minor *minor); | 1303 | extern int drm_sysfs_device_add(struct drm_minor *minor); |
| 1304 | extern void drm_sysfs_hotplug_event(struct drm_device *dev); | ||
| 1234 | extern void drm_sysfs_device_remove(struct drm_minor *minor); | 1305 | extern void drm_sysfs_device_remove(struct drm_minor *minor); |
| 1306 | extern char *drm_get_connector_status_name(enum drm_connector_status status); | ||
| 1307 | extern int drm_sysfs_connector_add(struct drm_connector *connector); | ||
| 1308 | extern void drm_sysfs_connector_remove(struct drm_connector *connector); | ||
| 1235 | 1309 | ||
| 1236 | /* | 1310 | /* |
| 1237 | * Basic memory manager support (drm_mm.c) | 1311 | * Basic memory manager support (drm_mm.c) |
| @@ -1251,10 +1325,12 @@ extern int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size); | |||
| 1251 | 1325 | ||
| 1252 | /* Graphics Execution Manager library functions (drm_gem.c) */ | 1326 | /* Graphics Execution Manager library functions (drm_gem.c) */ |
| 1253 | int drm_gem_init(struct drm_device *dev); | 1327 | int drm_gem_init(struct drm_device *dev); |
| 1328 | void drm_gem_destroy(struct drm_device *dev); | ||
| 1254 | void drm_gem_object_free(struct kref *kref); | 1329 | void drm_gem_object_free(struct kref *kref); |
| 1255 | struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev, | 1330 | struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev, |
| 1256 | size_t size); | 1331 | size_t size); |
| 1257 | void drm_gem_object_handle_free(struct kref *kref); | 1332 | void drm_gem_object_handle_free(struct kref *kref); |
| 1333 | int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma); | ||
| 1258 | 1334 | ||
| 1259 | static inline void | 1335 | static inline void |
| 1260 | drm_gem_object_reference(struct drm_gem_object *obj) | 1336 | drm_gem_object_reference(struct drm_gem_object *obj) |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h new file mode 100644 index 000000000000..0acb07f31fa4 --- /dev/null +++ b/include/drm/drm_crtc.h | |||
| @@ -0,0 +1,733 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2006 Keith Packard | ||
| 3 | * Copyright © 2007-2008 Dave Airlie | ||
| 4 | * Copyright © 2007-2008 Intel Corporation | ||
| 5 | * Jesse Barnes <jesse.barnes@intel.com> | ||
| 6 | * | ||
| 7 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 8 | * copy of this software and associated documentation files (the "Software"), | ||
| 9 | * to deal in the Software without restriction, including without limitation | ||
| 10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 11 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 12 | * Software is furnished to do so, subject to the following conditions: | ||
| 13 | * | ||
| 14 | * The above copyright notice and this permission notice shall be included in | ||
| 15 | * all copies or substantial portions of the Software. | ||
| 16 | * | ||
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 20 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
| 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
| 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
| 23 | * OTHER DEALINGS IN THE SOFTWARE. | ||
| 24 | */ | ||
| 25 | #ifndef __DRM_CRTC_H__ | ||
| 26 | #define __DRM_CRTC_H__ | ||
| 27 | |||
| 28 | #include <linux/i2c.h> | ||
| 29 | #include <linux/spinlock.h> | ||
| 30 | #include <linux/types.h> | ||
| 31 | #include <linux/idr.h> | ||
| 32 | |||
| 33 | #include <linux/fb.h> | ||
| 34 | |||
| 35 | struct drm_device; | ||
| 36 | struct drm_mode_set; | ||
| 37 | struct drm_framebuffer; | ||
| 38 | |||
| 39 | |||
| 40 | #define DRM_MODE_OBJECT_CRTC 0xcccccccc | ||
| 41 | #define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0 | ||
| 42 | #define DRM_MODE_OBJECT_ENCODER 0xe0e0e0e0 | ||
| 43 | #define DRM_MODE_OBJECT_MODE 0xdededede | ||
| 44 | #define DRM_MODE_OBJECT_PROPERTY 0xb0b0b0b0 | ||
| 45 | #define DRM_MODE_OBJECT_FB 0xfbfbfbfb | ||
| 46 | #define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb | ||
| 47 | |||
| 48 | struct drm_mode_object { | ||
| 49 | uint32_t id; | ||
| 50 | uint32_t type; | ||
| 51 | }; | ||
| 52 | |||
| 53 | /* | ||
| 54 | * Note on terminology: here, for brevity and convenience, we refer to connector | ||
| 55 | * control chips as 'CRTCs'. They can control any type of connector, VGA, LVDS, | ||
| 56 | * DVI, etc. And 'screen' refers to the whole of the visible display, which | ||
| 57 | * may span multiple monitors (and therefore multiple CRTC and connector | ||
| 58 | * structures). | ||
| 59 | */ | ||
| 60 | |||
| 61 | enum drm_mode_status { | ||
| 62 | MODE_OK = 0, /* Mode OK */ | ||
| 63 | MODE_HSYNC, /* hsync out of range */ | ||
| 64 | MODE_VSYNC, /* vsync out of range */ | ||
| 65 | MODE_H_ILLEGAL, /* mode has illegal horizontal timings */ | ||
| 66 | MODE_V_ILLEGAL, /* mode has illegal horizontal timings */ | ||
| 67 | MODE_BAD_WIDTH, /* requires an unsupported linepitch */ | ||
| 68 | MODE_NOMODE, /* no mode with a maching name */ | ||
| 69 | MODE_NO_INTERLACE, /* interlaced mode not supported */ | ||
| 70 | MODE_NO_DBLESCAN, /* doublescan mode not supported */ | ||
| 71 | MODE_NO_VSCAN, /* multiscan mode not supported */ | ||
| 72 | MODE_MEM, /* insufficient video memory */ | ||
| 73 | MODE_VIRTUAL_X, /* mode width too large for specified virtual size */ | ||
| 74 | MODE_VIRTUAL_Y, /* mode height too large for specified virtual size */ | ||
| 75 | MODE_MEM_VIRT, /* insufficient video memory given virtual size */ | ||
| 76 | MODE_NOCLOCK, /* no fixed clock available */ | ||
| 77 | MODE_CLOCK_HIGH, /* clock required is too high */ | ||
| 78 | MODE_CLOCK_LOW, /* clock required is too low */ | ||
| 79 | MODE_CLOCK_RANGE, /* clock/mode isn't in a ClockRange */ | ||
| 80 | MODE_BAD_HVALUE, /* horizontal timing was out of range */ | ||
| 81 | MODE_BAD_VVALUE, /* vertical timing was out of range */ | ||
| 82 | MODE_BAD_VSCAN, /* VScan value out of range */ | ||
| 83 | MODE_HSYNC_NARROW, /* horizontal sync too narrow */ | ||
| 84 | MODE_HSYNC_WIDE, /* horizontal sync too wide */ | ||
| 85 | MODE_HBLANK_NARROW, /* horizontal blanking too narrow */ | ||
| 86 | MODE_HBLANK_WIDE, /* horizontal blanking too wide */ | ||
| 87 | MODE_VSYNC_NARROW, /* vertical sync too narrow */ | ||
| 88 | MODE_VSYNC_WIDE, /* vertical sync too wide */ | ||
| 89 | MODE_VBLANK_NARROW, /* vertical blanking too narrow */ | ||
| 90 | MODE_VBLANK_WIDE, /* vertical blanking too wide */ | ||
| 91 | MODE_PANEL, /* exceeds panel dimensions */ | ||
| 92 | MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */ | ||
| 93 | MODE_ONE_WIDTH, /* only one width is supported */ | ||
| 94 | MODE_ONE_HEIGHT, /* only one height is supported */ | ||
| 95 | MODE_ONE_SIZE, /* only one resolution is supported */ | ||
| 96 | MODE_NO_REDUCED, /* monitor doesn't accept reduced blanking */ | ||
| 97 | MODE_UNVERIFIED = -3, /* mode needs to reverified */ | ||
| 98 | MODE_BAD = -2, /* unspecified reason */ | ||
| 99 | MODE_ERROR = -1 /* error condition */ | ||
| 100 | }; | ||
| 101 | |||
| 102 | #define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \ | ||
| 103 | DRM_MODE_TYPE_CRTC_C) | ||
| 104 | |||
| 105 | #define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \ | ||
| 106 | .name = nm, .status = 0, .type = (t), .clock = (c), \ | ||
| 107 | .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ | ||
| 108 | .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \ | ||
| 109 | .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ | ||
| 110 | .vscan = (vs), .flags = (f), .vrefresh = 0 | ||
| 111 | |||
| 112 | #define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ | ||
| 113 | |||
| 114 | struct drm_display_mode { | ||
| 115 | /* Header */ | ||
| 116 | struct list_head head; | ||
| 117 | struct drm_mode_object base; | ||
| 118 | |||
| 119 | char name[DRM_DISPLAY_MODE_LEN]; | ||
| 120 | |||
| 121 | int connector_count; | ||
| 122 | enum drm_mode_status status; | ||
| 123 | int type; | ||
| 124 | |||
| 125 | /* Proposed mode values */ | ||
| 126 | int clock; | ||
| 127 | int hdisplay; | ||
| 128 | int hsync_start; | ||
| 129 | int hsync_end; | ||
| 130 | int htotal; | ||
| 131 | int hskew; | ||
| 132 | int vdisplay; | ||
| 133 | int vsync_start; | ||
| 134 | int vsync_end; | ||
| 135 | int vtotal; | ||
| 136 | int vscan; | ||
| 137 | unsigned int flags; | ||
| 138 | |||
| 139 | /* Addressable image size (may be 0 for projectors, etc.) */ | ||
| 140 | int width_mm; | ||
| 141 | int height_mm; | ||
| 142 | |||
| 143 | /* Actual mode we give to hw */ | ||
| 144 | int clock_index; | ||
| 145 | int synth_clock; | ||
| 146 | int crtc_hdisplay; | ||
| 147 | int crtc_hblank_start; | ||
| 148 | int crtc_hblank_end; | ||
| 149 | int crtc_hsync_start; | ||
| 150 | int crtc_hsync_end; | ||
| 151 | int crtc_htotal; | ||
| 152 | int crtc_hskew; | ||
| 153 | int crtc_vdisplay; | ||
| 154 | int crtc_vblank_start; | ||
| 155 | int crtc_vblank_end; | ||
| 156 | int crtc_vsync_start; | ||
| 157 | int crtc_vsync_end; | ||
| 158 | int crtc_vtotal; | ||
| 159 | int crtc_hadjusted; | ||
| 160 | int crtc_vadjusted; | ||
| 161 | |||
| 162 | /* Driver private mode info */ | ||
| 163 | int private_size; | ||
| 164 | int *private; | ||
| 165 | int private_flags; | ||
| 166 | |||
| 167 | int vrefresh; | ||
| 168 | float hsync; | ||
| 169 | }; | ||
| 170 | |||
| 171 | enum drm_connector_status { | ||
| 172 | connector_status_connected = 1, | ||
| 173 | connector_status_disconnected = 2, | ||
| 174 | connector_status_unknown = 3, | ||
| 175 | }; | ||
| 176 | |||
| 177 | enum subpixel_order { | ||
| 178 | SubPixelUnknown = 0, | ||
| 179 | SubPixelHorizontalRGB, | ||
| 180 | SubPixelHorizontalBGR, | ||
| 181 | SubPixelVerticalRGB, | ||
| 182 | SubPixelVerticalBGR, | ||
| 183 | SubPixelNone, | ||
| 184 | }; | ||
| 185 | |||
| 186 | |||
| 187 | /* | ||
| 188 | * Describes a given display (e.g. CRT or flat panel) and its limitations. | ||
| 189 | */ | ||
| 190 | struct drm_display_info { | ||
| 191 | char name[DRM_DISPLAY_INFO_LEN]; | ||
| 192 | /* Input info */ | ||
| 193 | bool serration_vsync; | ||
| 194 | bool sync_on_green; | ||
| 195 | bool composite_sync; | ||
| 196 | bool separate_syncs; | ||
| 197 | bool blank_to_black; | ||
| 198 | unsigned char video_level; | ||
| 199 | bool digital; | ||
| 200 | /* Physical size */ | ||
| 201 | unsigned int width_mm; | ||
| 202 | unsigned int height_mm; | ||
| 203 | |||
| 204 | /* Display parameters */ | ||
| 205 | unsigned char gamma; /* FIXME: storage format */ | ||
| 206 | bool gtf_supported; | ||
| 207 | bool standard_color; | ||
| 208 | enum { | ||
| 209 | monochrome = 0, | ||
| 210 | rgb, | ||
| 211 | other, | ||
| 212 | unknown, | ||
| 213 | } display_type; | ||
| 214 | bool active_off_supported; | ||
| 215 | bool suspend_supported; | ||
| 216 | bool standby_supported; | ||
| 217 | |||
| 218 | /* Color info FIXME: storage format */ | ||
| 219 | unsigned short redx, redy; | ||
| 220 | unsigned short greenx, greeny; | ||
| 221 | unsigned short bluex, bluey; | ||
| 222 | unsigned short whitex, whitey; | ||
| 223 | |||
| 224 | /* Clock limits FIXME: storage format */ | ||
| 225 | unsigned int min_vfreq, max_vfreq; | ||
| 226 | unsigned int min_hfreq, max_hfreq; | ||
| 227 | unsigned int pixel_clock; | ||
| 228 | |||
| 229 | /* White point indices FIXME: storage format */ | ||
| 230 | unsigned int wpx1, wpy1; | ||
| 231 | unsigned int wpgamma1; | ||
| 232 | unsigned int wpx2, wpy2; | ||
| 233 | unsigned int wpgamma2; | ||
| 234 | |||
| 235 | enum subpixel_order subpixel_order; | ||
| 236 | |||
| 237 | char *raw_edid; /* if any */ | ||
| 238 | }; | ||
| 239 | |||
| 240 | struct drm_framebuffer_funcs { | ||
| 241 | void (*destroy)(struct drm_framebuffer *framebuffer); | ||
| 242 | int (*create_handle)(struct drm_framebuffer *fb, | ||
| 243 | struct drm_file *file_priv, | ||
| 244 | unsigned int *handle); | ||
| 245 | }; | ||
| 246 | |||
| 247 | struct drm_framebuffer { | ||
| 248 | struct drm_device *dev; | ||
| 249 | struct list_head head; | ||
| 250 | struct drm_mode_object base; | ||
| 251 | const struct drm_framebuffer_funcs *funcs; | ||
| 252 | unsigned int pitch; | ||
| 253 | unsigned int width; | ||
| 254 | unsigned int height; | ||
| 255 | /* depth can be 15 or 16 */ | ||
| 256 | unsigned int depth; | ||
| 257 | int bits_per_pixel; | ||
| 258 | int flags; | ||
| 259 | void *fbdev; | ||
| 260 | u32 pseudo_palette[17]; | ||
| 261 | struct list_head filp_head; | ||
| 262 | }; | ||
| 263 | |||
| 264 | struct drm_property_blob { | ||
| 265 | struct drm_mode_object base; | ||
| 266 | struct list_head head; | ||
| 267 | unsigned int length; | ||
| 268 | void *data; | ||
| 269 | }; | ||
| 270 | |||
| 271 | struct drm_property_enum { | ||
| 272 | uint64_t value; | ||
| 273 | struct list_head head; | ||
| 274 | char name[DRM_PROP_NAME_LEN]; | ||
| 275 | }; | ||
| 276 | |||
| 277 | struct drm_property { | ||
| 278 | struct list_head head; | ||
| 279 | struct drm_mode_object base; | ||
| 280 | uint32_t flags; | ||
| 281 | char name[DRM_PROP_NAME_LEN]; | ||
| 282 | uint32_t num_values; | ||
| 283 | uint64_t *values; | ||
| 284 | |||
| 285 | struct list_head enum_blob_list; | ||
| 286 | }; | ||
| 287 | |||
| 288 | struct drm_crtc; | ||
| 289 | struct drm_connector; | ||
| 290 | struct drm_encoder; | ||
| 291 | |||
| 292 | /** | ||
| 293 | * drm_crtc_funcs - control CRTCs for a given device | ||
| 294 | * @dpms: control display power levels | ||
| 295 | * @save: save CRTC state | ||
| 296 | * @resore: restore CRTC state | ||
| 297 | * @lock: lock the CRTC | ||
| 298 | * @unlock: unlock the CRTC | ||
| 299 | * @shadow_allocate: allocate shadow pixmap | ||
| 300 | * @shadow_create: create shadow pixmap for rotation support | ||
| 301 | * @shadow_destroy: free shadow pixmap | ||
| 302 | * @mode_fixup: fixup proposed mode | ||
| 303 | * @mode_set: set the desired mode on the CRTC | ||
| 304 | * @gamma_set: specify color ramp for CRTC | ||
| 305 | * @destroy: deinit and free object. | ||
| 306 | * | ||
| 307 | * The drm_crtc_funcs structure is the central CRTC management structure | ||
| 308 | * in the DRM. Each CRTC controls one or more connectors (note that the name | ||
| 309 | * CRTC is simply historical, a CRTC may control LVDS, VGA, DVI, TV out, etc. | ||
| 310 | * connectors, not just CRTs). | ||
| 311 | * | ||
| 312 | * Each driver is responsible for filling out this structure at startup time, | ||
| 313 | * in addition to providing other modesetting features, like i2c and DDC | ||
| 314 | * bus accessors. | ||
| 315 | */ | ||
| 316 | struct drm_crtc_funcs { | ||
| 317 | /* Save CRTC state */ | ||
| 318 | void (*save)(struct drm_crtc *crtc); /* suspend? */ | ||
| 319 | /* Restore CRTC state */ | ||
| 320 | void (*restore)(struct drm_crtc *crtc); /* resume? */ | ||
| 321 | |||
| 322 | /* cursor controls */ | ||
| 323 | int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv, | ||
| 324 | uint32_t handle, uint32_t width, uint32_t height); | ||
| 325 | int (*cursor_move)(struct drm_crtc *crtc, int x, int y); | ||
| 326 | |||
| 327 | /* Set gamma on the CRTC */ | ||
| 328 | void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, | ||
| 329 | uint32_t size); | ||
| 330 | /* Object destroy routine */ | ||
| 331 | void (*destroy)(struct drm_crtc *crtc); | ||
| 332 | |||
| 333 | int (*set_config)(struct drm_mode_set *set); | ||
| 334 | }; | ||
| 335 | |||
| 336 | /** | ||
| 337 | * drm_crtc - central CRTC control structure | ||
| 338 | * @enabled: is this CRTC enabled? | ||
| 339 | * @x: x position on screen | ||
| 340 | * @y: y position on screen | ||
| 341 | * @desired_mode: new desired mode | ||
| 342 | * @desired_x: desired x for desired_mode | ||
| 343 | * @desired_y: desired y for desired_mode | ||
| 344 | * @funcs: CRTC control functions | ||
| 345 | * | ||
| 346 | * Each CRTC may have one or more connectors associated with it. This structure | ||
| 347 | * allows the CRTC to be controlled. | ||
| 348 | */ | ||
| 349 | struct drm_crtc { | ||
| 350 | struct drm_device *dev; | ||
| 351 | struct list_head head; | ||
| 352 | |||
| 353 | struct drm_mode_object base; | ||
| 354 | |||
| 355 | /* framebuffer the connector is currently bound to */ | ||
| 356 | struct drm_framebuffer *fb; | ||
| 357 | |||
| 358 | bool enabled; | ||
| 359 | |||
| 360 | struct drm_display_mode mode; | ||
| 361 | |||
| 362 | int x, y; | ||
| 363 | struct drm_display_mode *desired_mode; | ||
| 364 | int desired_x, desired_y; | ||
| 365 | const struct drm_crtc_funcs *funcs; | ||
| 366 | |||
| 367 | /* CRTC gamma size for reporting to userspace */ | ||
| 368 | uint32_t gamma_size; | ||
| 369 | uint16_t *gamma_store; | ||
| 370 | |||
| 371 | /* if you are using the helper */ | ||
| 372 | void *helper_private; | ||
| 373 | }; | ||
| 374 | |||
| 375 | |||
| 376 | /** | ||
| 377 | * drm_connector_funcs - control connectors on a given device | ||
| 378 | * @dpms: set power state (see drm_crtc_funcs above) | ||
| 379 | * @save: save connector state | ||
| 380 | * @restore: restore connector state | ||
| 381 | * @mode_valid: is this mode valid on the given connector? | ||
| 382 | * @mode_fixup: try to fixup proposed mode for this connector | ||
| 383 | * @mode_set: set this mode | ||
| 384 | * @detect: is this connector active? | ||
| 385 | * @get_modes: get mode list for this connector | ||
| 386 | * @set_property: property for this connector may need update | ||
| 387 | * @destroy: make object go away | ||
| 388 | * | ||
| 389 | * Each CRTC may have one or more connectors attached to it. The functions | ||
| 390 | * below allow the core DRM code to control connectors, enumerate available modes, | ||
| 391 | * etc. | ||
| 392 | */ | ||
| 393 | struct drm_connector_funcs { | ||
| 394 | void (*dpms)(struct drm_connector *connector, int mode); | ||
| 395 | void (*save)(struct drm_connector *connector); | ||
| 396 | void (*restore)(struct drm_connector *connector); | ||
| 397 | enum drm_connector_status (*detect)(struct drm_connector *connector); | ||
| 398 | void (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); | ||
| 399 | int (*set_property)(struct drm_connector *connector, struct drm_property *property, | ||
| 400 | uint64_t val); | ||
| 401 | void (*destroy)(struct drm_connector *connector); | ||
| 402 | }; | ||
| 403 | |||
| 404 | struct drm_encoder_funcs { | ||
| 405 | void (*destroy)(struct drm_encoder *encoder); | ||
| 406 | }; | ||
| 407 | |||
| 408 | #define DRM_CONNECTOR_MAX_UMODES 16 | ||
| 409 | #define DRM_CONNECTOR_MAX_PROPERTY 16 | ||
| 410 | #define DRM_CONNECTOR_LEN 32 | ||
| 411 | #define DRM_CONNECTOR_MAX_ENCODER 2 | ||
| 412 | |||
| 413 | /** | ||
| 414 | * drm_encoder - central DRM encoder structure | ||
| 415 | */ | ||
| 416 | struct drm_encoder { | ||
| 417 | struct drm_device *dev; | ||
| 418 | struct list_head head; | ||
| 419 | |||
| 420 | struct drm_mode_object base; | ||
| 421 | int encoder_type; | ||
| 422 | uint32_t possible_crtcs; | ||
| 423 | uint32_t possible_clones; | ||
| 424 | |||
| 425 | struct drm_crtc *crtc; | ||
| 426 | const struct drm_encoder_funcs *funcs; | ||
| 427 | void *helper_private; | ||
| 428 | }; | ||
| 429 | |||
| 430 | /** | ||
| 431 | * drm_connector - central DRM connector control structure | ||
| 432 | * @crtc: CRTC this connector is currently connected to, NULL if none | ||
| 433 | * @interlace_allowed: can this connector handle interlaced modes? | ||
| 434 | * @doublescan_allowed: can this connector handle doublescan? | ||
| 435 | * @available_modes: modes available on this connector (from get_modes() + user) | ||
| 436 | * @initial_x: initial x position for this connector | ||
| 437 | * @initial_y: initial y position for this connector | ||
| 438 | * @status: connector connected? | ||
| 439 | * @funcs: connector control functions | ||
| 440 | * | ||
| 441 | * Each connector may be connected to one or more CRTCs, or may be clonable by | ||
| 442 | * another connector if they can share a CRTC. Each connector also has a specific | ||
| 443 | * position in the broader display (referred to as a 'screen' though it could | ||
| 444 | * span multiple monitors). | ||
| 445 | */ | ||
| 446 | struct drm_connector { | ||
| 447 | struct drm_device *dev; | ||
| 448 | struct device kdev; | ||
| 449 | struct device_attribute *attr; | ||
| 450 | struct list_head head; | ||
| 451 | |||
| 452 | struct drm_mode_object base; | ||
| 453 | |||
| 454 | int connector_type; | ||
| 455 | int connector_type_id; | ||
| 456 | bool interlace_allowed; | ||
| 457 | bool doublescan_allowed; | ||
| 458 | struct list_head modes; /* list of modes on this connector */ | ||
| 459 | |||
| 460 | int initial_x, initial_y; | ||
| 461 | enum drm_connector_status status; | ||
| 462 | |||
| 463 | /* these are modes added by probing with DDC or the BIOS */ | ||
| 464 | struct list_head probed_modes; | ||
| 465 | |||
| 466 | struct drm_display_info display_info; | ||
| 467 | const struct drm_connector_funcs *funcs; | ||
| 468 | |||
| 469 | struct list_head user_modes; | ||
| 470 | struct drm_property_blob *edid_blob_ptr; | ||
| 471 | u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY]; | ||
| 472 | uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY]; | ||
| 473 | |||
| 474 | void *helper_private; | ||
| 475 | |||
| 476 | uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; | ||
| 477 | uint32_t force_encoder_id; | ||
| 478 | struct drm_encoder *encoder; /* currently active encoder */ | ||
| 479 | }; | ||
| 480 | |||
| 481 | /** | ||
| 482 | * struct drm_mode_set | ||
| 483 | * | ||
| 484 | * Represents a single crtc the connectors that it drives with what mode | ||
| 485 | * and from which framebuffer it scans out from. | ||
| 486 | * | ||
| 487 | * This is used to set modes. | ||
| 488 | */ | ||
| 489 | struct drm_mode_set { | ||
| 490 | struct list_head head; | ||
| 491 | |||
| 492 | struct drm_framebuffer *fb; | ||
| 493 | struct drm_crtc *crtc; | ||
| 494 | struct drm_display_mode *mode; | ||
| 495 | |||
| 496 | uint32_t x; | ||
| 497 | uint32_t y; | ||
| 498 | |||
| 499 | struct drm_connector **connectors; | ||
| 500 | size_t num_connectors; | ||
| 501 | }; | ||
| 502 | |||
| 503 | /** | ||
| 504 | * struct drm_mode_config_funcs - configure CRTCs for a given screen layout | ||
| 505 | * @resize: adjust CRTCs as necessary for the proposed layout | ||
| 506 | * | ||
| 507 | * Currently only a resize hook is available. DRM will call back into the | ||
| 508 | * driver with a new screen width and height. If the driver can't support | ||
| 509 | * the proposed size, it can return false. Otherwise it should adjust | ||
| 510 | * the CRTC<->connector mappings as needed and update its view of the screen. | ||
| 511 | */ | ||
| 512 | struct drm_mode_config_funcs { | ||
| 513 | struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd); | ||
| 514 | int (*fb_changed)(struct drm_device *dev); | ||
| 515 | }; | ||
| 516 | |||
| 517 | struct drm_mode_group { | ||
| 518 | uint32_t num_crtcs; | ||
| 519 | uint32_t num_encoders; | ||
| 520 | uint32_t num_connectors; | ||
| 521 | |||
| 522 | /* list of object IDs for this group */ | ||
| 523 | uint32_t *id_list; | ||
| 524 | }; | ||
| 525 | |||
| 526 | /** | ||
| 527 | * drm_mode_config - Mode configuration control structure | ||
| 528 | * | ||
| 529 | */ | ||
| 530 | struct drm_mode_config { | ||
| 531 | struct mutex mutex; /* protects configuration and IDR */ | ||
| 532 | struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ | ||
| 533 | /* this is limited to one for now */ | ||
| 534 | int num_fb; | ||
| 535 | struct list_head fb_list; | ||
| 536 | int num_connector; | ||
| 537 | struct list_head connector_list; | ||
| 538 | int num_encoder; | ||
| 539 | struct list_head encoder_list; | ||
| 540 | |||
| 541 | int num_crtc; | ||
| 542 | struct list_head crtc_list; | ||
| 543 | |||
| 544 | struct list_head property_list; | ||
| 545 | |||
| 546 | /* in-kernel framebuffers - hung of filp_head in drm_framebuffer */ | ||
| 547 | struct list_head fb_kernel_list; | ||
| 548 | |||
| 549 | int min_width, min_height; | ||
| 550 | int max_width, max_height; | ||
| 551 | struct drm_mode_config_funcs *funcs; | ||
| 552 | unsigned long fb_base; | ||
| 553 | |||
| 554 | /* pointers to standard properties */ | ||
| 555 | struct list_head property_blob_list; | ||
| 556 | struct drm_property *edid_property; | ||
| 557 | struct drm_property *dpms_property; | ||
| 558 | |||
| 559 | /* DVI-I properties */ | ||
| 560 | struct drm_property *dvi_i_subconnector_property; | ||
| 561 | struct drm_property *dvi_i_select_subconnector_property; | ||
| 562 | |||
| 563 | /* TV properties */ | ||
| 564 | struct drm_property *tv_subconnector_property; | ||
| 565 | struct drm_property *tv_select_subconnector_property; | ||
| 566 | struct drm_property *tv_mode_property; | ||
| 567 | struct drm_property *tv_left_margin_property; | ||
| 568 | struct drm_property *tv_right_margin_property; | ||
| 569 | struct drm_property *tv_top_margin_property; | ||
| 570 | struct drm_property *tv_bottom_margin_property; | ||
| 571 | |||
| 572 | /* Optional properties */ | ||
| 573 | struct drm_property *scaling_mode_property; | ||
| 574 | struct drm_property *dithering_mode_property; | ||
| 575 | }; | ||
| 576 | |||
| 577 | #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) | ||
| 578 | #define obj_to_connector(x) container_of(x, struct drm_connector, base) | ||
| 579 | #define obj_to_encoder(x) container_of(x, struct drm_encoder, base) | ||
| 580 | #define obj_to_mode(x) container_of(x, struct drm_display_mode, base) | ||
| 581 | #define obj_to_fb(x) container_of(x, struct drm_framebuffer, base) | ||
| 582 | #define obj_to_property(x) container_of(x, struct drm_property, base) | ||
| 583 | #define obj_to_blob(x) container_of(x, struct drm_property_blob, base) | ||
| 584 | |||
| 585 | |||
| 586 | extern void drm_crtc_init(struct drm_device *dev, | ||
| 587 | struct drm_crtc *crtc, | ||
| 588 | const struct drm_crtc_funcs *funcs); | ||
| 589 | extern void drm_crtc_cleanup(struct drm_crtc *crtc); | ||
| 590 | |||
| 591 | extern void drm_connector_init(struct drm_device *dev, | ||
| 592 | struct drm_connector *connector, | ||
| 593 | const struct drm_connector_funcs *funcs, | ||
| 594 | int connector_type); | ||
| 595 | |||
| 596 | extern void drm_connector_cleanup(struct drm_connector *connector); | ||
| 597 | |||
| 598 | extern void drm_encoder_init(struct drm_device *dev, | ||
| 599 | struct drm_encoder *encoder, | ||
| 600 | const struct drm_encoder_funcs *funcs, | ||
| 601 | int encoder_type); | ||
| 602 | |||
| 603 | extern void drm_encoder_cleanup(struct drm_encoder *encoder); | ||
| 604 | |||
| 605 | extern char *drm_get_connector_name(struct drm_connector *connector); | ||
| 606 | extern char *drm_get_dpms_name(int val); | ||
| 607 | extern char *drm_get_dvi_i_subconnector_name(int val); | ||
| 608 | extern char *drm_get_dvi_i_select_name(int val); | ||
| 609 | extern char *drm_get_tv_subconnector_name(int val); | ||
| 610 | extern char *drm_get_tv_select_name(int val); | ||
| 611 | extern void drm_fb_release(struct file *filp); | ||
| 612 | extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); | ||
| 613 | extern struct edid *drm_get_edid(struct drm_connector *connector, | ||
| 614 | struct i2c_adapter *adapter); | ||
| 615 | extern unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter); | ||
| 616 | extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); | ||
| 617 | extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode); | ||
| 618 | extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode); | ||
| 619 | extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, | ||
| 620 | struct drm_display_mode *mode); | ||
| 621 | extern void drm_mode_debug_printmodeline(struct drm_display_mode *mode); | ||
| 622 | extern void drm_mode_config_init(struct drm_device *dev); | ||
| 623 | extern void drm_mode_config_cleanup(struct drm_device *dev); | ||
| 624 | extern void drm_mode_set_name(struct drm_display_mode *mode); | ||
| 625 | extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2); | ||
| 626 | extern int drm_mode_width(struct drm_display_mode *mode); | ||
| 627 | extern int drm_mode_height(struct drm_display_mode *mode); | ||
| 628 | |||
| 629 | /* for us by fb module */ | ||
| 630 | extern int drm_mode_attachmode_crtc(struct drm_device *dev, | ||
| 631 | struct drm_crtc *crtc, | ||
| 632 | struct drm_display_mode *mode); | ||
| 633 | extern int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode); | ||
| 634 | |||
| 635 | extern struct drm_display_mode *drm_mode_create(struct drm_device *dev); | ||
| 636 | extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode); | ||
| 637 | extern void drm_mode_list_concat(struct list_head *head, | ||
| 638 | struct list_head *new); | ||
| 639 | extern void drm_mode_validate_size(struct drm_device *dev, | ||
| 640 | struct list_head *mode_list, | ||
| 641 | int maxX, int maxY, int maxPitch); | ||
| 642 | extern void drm_mode_prune_invalid(struct drm_device *dev, | ||
| 643 | struct list_head *mode_list, bool verbose); | ||
| 644 | extern void drm_mode_sort(struct list_head *mode_list); | ||
| 645 | extern int drm_mode_vrefresh(struct drm_display_mode *mode); | ||
| 646 | extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, | ||
| 647 | int adjust_flags); | ||
| 648 | extern void drm_mode_connector_list_update(struct drm_connector *connector); | ||
| 649 | extern int drm_mode_connector_update_edid_property(struct drm_connector *connector, | ||
| 650 | struct edid *edid); | ||
| 651 | extern int drm_connector_property_set_value(struct drm_connector *connector, | ||
| 652 | struct drm_property *property, | ||
| 653 | uint64_t value); | ||
| 654 | extern int drm_connector_property_get_value(struct drm_connector *connector, | ||
| 655 | struct drm_property *property, | ||
| 656 | uint64_t *value); | ||
| 657 | extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); | ||
| 658 | extern void drm_framebuffer_set_object(struct drm_device *dev, | ||
| 659 | unsigned long handle); | ||
| 660 | extern int drm_framebuffer_init(struct drm_device *dev, | ||
| 661 | struct drm_framebuffer *fb, | ||
| 662 | const struct drm_framebuffer_funcs *funcs); | ||
| 663 | extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb); | ||
| 664 | extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); | ||
| 665 | extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); | ||
| 666 | extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY); | ||
| 667 | extern bool drm_crtc_in_use(struct drm_crtc *crtc); | ||
| 668 | |||
| 669 | extern int drm_connector_attach_property(struct drm_connector *connector, | ||
| 670 | struct drm_property *property, uint64_t init_val); | ||
| 671 | extern struct drm_property *drm_property_create(struct drm_device *dev, int flags, | ||
| 672 | const char *name, int num_values); | ||
| 673 | extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); | ||
| 674 | extern int drm_property_add_enum(struct drm_property *property, int index, | ||
| 675 | uint64_t value, const char *name); | ||
| 676 | extern int drm_mode_create_dvi_i_properties(struct drm_device *dev); | ||
| 677 | extern int drm_mode_create_tv_properties(struct drm_device *dev, int num_formats, | ||
| 678 | char *formats[]); | ||
| 679 | extern int drm_mode_create_scaling_mode_property(struct drm_device *dev); | ||
| 680 | extern int drm_mode_create_dithering_property(struct drm_device *dev); | ||
| 681 | extern char *drm_get_encoder_name(struct drm_encoder *encoder); | ||
| 682 | |||
| 683 | extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, | ||
| 684 | struct drm_encoder *encoder); | ||
| 685 | extern void drm_mode_connector_detach_encoder(struct drm_connector *connector, | ||
| 686 | struct drm_encoder *encoder); | ||
| 687 | extern bool drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, | ||
| 688 | int gamma_size); | ||
| 689 | extern void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type); | ||
| 690 | /* IOCTLs */ | ||
| 691 | extern int drm_mode_getresources(struct drm_device *dev, | ||
| 692 | void *data, struct drm_file *file_priv); | ||
| 693 | |||
| 694 | extern int drm_mode_getcrtc(struct drm_device *dev, | ||
| 695 | void *data, struct drm_file *file_priv); | ||
| 696 | extern int drm_mode_getconnector(struct drm_device *dev, | ||
| 697 | void *data, struct drm_file *file_priv); | ||
| 698 | extern int drm_mode_setcrtc(struct drm_device *dev, | ||
| 699 | void *data, struct drm_file *file_priv); | ||
| 700 | extern int drm_mode_cursor_ioctl(struct drm_device *dev, | ||
| 701 | void *data, struct drm_file *file_priv); | ||
| 702 | extern int drm_mode_addfb(struct drm_device *dev, | ||
| 703 | void *data, struct drm_file *file_priv); | ||
| 704 | extern int drm_mode_rmfb(struct drm_device *dev, | ||
| 705 | void *data, struct drm_file *file_priv); | ||
| 706 | extern int drm_mode_getfb(struct drm_device *dev, | ||
| 707 | void *data, struct drm_file *file_priv); | ||
| 708 | extern int drm_mode_addmode_ioctl(struct drm_device *dev, | ||
| 709 | void *data, struct drm_file *file_priv); | ||
| 710 | extern int drm_mode_rmmode_ioctl(struct drm_device *dev, | ||
| 711 | void *data, struct drm_file *file_priv); | ||
| 712 | extern int drm_mode_attachmode_ioctl(struct drm_device *dev, | ||
| 713 | void *data, struct drm_file *file_priv); | ||
| 714 | extern int drm_mode_detachmode_ioctl(struct drm_device *dev, | ||
| 715 | void *data, struct drm_file *file_priv); | ||
| 716 | |||
| 717 | extern int drm_mode_getproperty_ioctl(struct drm_device *dev, | ||
| 718 | void *data, struct drm_file *file_priv); | ||
| 719 | extern int drm_mode_getblob_ioctl(struct drm_device *dev, | ||
| 720 | void *data, struct drm_file *file_priv); | ||
| 721 | extern int drm_mode_connector_property_set_ioctl(struct drm_device *dev, | ||
| 722 | void *data, struct drm_file *file_priv); | ||
| 723 | extern int drm_mode_hotplug_ioctl(struct drm_device *dev, | ||
| 724 | void *data, struct drm_file *file_priv); | ||
| 725 | extern int drm_mode_replacefb(struct drm_device *dev, | ||
| 726 | void *data, struct drm_file *file_priv); | ||
| 727 | extern int drm_mode_getencoder(struct drm_device *dev, | ||
| 728 | void *data, struct drm_file *file_priv); | ||
| 729 | extern int drm_mode_gamma_get_ioctl(struct drm_device *dev, | ||
| 730 | void *data, struct drm_file *file_priv); | ||
| 731 | extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, | ||
| 732 | void *data, struct drm_file *file_priv); | ||
| 733 | #endif /* __DRM_CRTC_H__ */ | ||
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h new file mode 100644 index 000000000000..4bc04cf460a7 --- /dev/null +++ b/include/drm/drm_crtc_helper.h | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2006 Keith Packard | ||
| 3 | * Copyright © 2007-2008 Dave Airlie | ||
| 4 | * Copyright © 2007-2008 Intel Corporation | ||
| 5 | * Jesse Barnes <jesse.barnes@intel.com> | ||
| 6 | * | ||
| 7 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 8 | * copy of this software and associated documentation files (the "Software"), | ||
| 9 | * to deal in the Software without restriction, including without limitation | ||
| 10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 11 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 12 | * Software is furnished to do so, subject to the following conditions: | ||
| 13 | * | ||
| 14 | * The above copyright notice and this permission notice shall be included in | ||
| 15 | * all copies or substantial portions of the Software. | ||
| 16 | * | ||
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 20 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
| 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
| 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
| 23 | * OTHER DEALINGS IN THE SOFTWARE. | ||
| 24 | */ | ||
| 25 | |||
| 26 | /* | ||
| 27 | * The DRM mode setting helper functions are common code for drivers to use if | ||
| 28 | * they wish. Drivers are not forced to use this code in their | ||
| 29 | * implementations but it would be useful if they code they do use at least | ||
| 30 | * provides a consistent interface and operation to userspace | ||
| 31 | */ | ||
| 32 | |||
| 33 | #ifndef __DRM_CRTC_HELPER_H__ | ||
| 34 | #define __DRM_CRTC_HELPER_H__ | ||
| 35 | |||
| 36 | #include <linux/i2c.h> | ||
| 37 | #include <linux/spinlock.h> | ||
| 38 | #include <linux/types.h> | ||
| 39 | #include <linux/idr.h> | ||
| 40 | |||
| 41 | #include <linux/fb.h> | ||
| 42 | |||
| 43 | struct drm_crtc_helper_funcs { | ||
| 44 | /* | ||
| 45 | * Control power levels on the CRTC. If the mode passed in is | ||
| 46 | * unsupported, the provider must use the next lowest power level. | ||
| 47 | */ | ||
| 48 | void (*dpms)(struct drm_crtc *crtc, int mode); | ||
| 49 | void (*prepare)(struct drm_crtc *crtc); | ||
| 50 | void (*commit)(struct drm_crtc *crtc); | ||
| 51 | |||
| 52 | /* Provider can fixup or change mode timings before modeset occurs */ | ||
| 53 | bool (*mode_fixup)(struct drm_crtc *crtc, | ||
| 54 | struct drm_display_mode *mode, | ||
| 55 | struct drm_display_mode *adjusted_mode); | ||
| 56 | /* Actually set the mode */ | ||
| 57 | void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, | ||
| 58 | struct drm_display_mode *adjusted_mode, int x, int y, | ||
| 59 | struct drm_framebuffer *old_fb); | ||
| 60 | |||
| 61 | /* Move the crtc on the current fb to the given position *optional* */ | ||
| 62 | void (*mode_set_base)(struct drm_crtc *crtc, int x, int y, | ||
| 63 | struct drm_framebuffer *old_fb); | ||
| 64 | }; | ||
| 65 | |||
| 66 | struct drm_encoder_helper_funcs { | ||
| 67 | void (*dpms)(struct drm_encoder *encoder, int mode); | ||
| 68 | void (*save)(struct drm_encoder *encoder); | ||
| 69 | void (*restore)(struct drm_encoder *encoder); | ||
| 70 | |||
| 71 | bool (*mode_fixup)(struct drm_encoder *encoder, | ||
| 72 | struct drm_display_mode *mode, | ||
| 73 | struct drm_display_mode *adjusted_mode); | ||
| 74 | void (*prepare)(struct drm_encoder *encoder); | ||
| 75 | void (*commit)(struct drm_encoder *encoder); | ||
| 76 | void (*mode_set)(struct drm_encoder *encoder, | ||
| 77 | struct drm_display_mode *mode, | ||
| 78 | struct drm_display_mode *adjusted_mode); | ||
| 79 | /* detect for DAC style encoders */ | ||
| 80 | enum drm_connector_status (*detect)(struct drm_encoder *encoder, | ||
| 81 | struct drm_connector *connector); | ||
| 82 | }; | ||
| 83 | |||
| 84 | struct drm_connector_helper_funcs { | ||
| 85 | int (*get_modes)(struct drm_connector *connector); | ||
| 86 | int (*mode_valid)(struct drm_connector *connector, | ||
| 87 | struct drm_display_mode *mode); | ||
| 88 | struct drm_encoder *(*best_encoder)(struct drm_connector *connector); | ||
| 89 | }; | ||
| 90 | |||
| 91 | extern void drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); | ||
| 92 | extern void drm_helper_disable_unused_functions(struct drm_device *dev); | ||
| 93 | extern int drm_helper_hotplug_stage_two(struct drm_device *dev); | ||
| 94 | extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow); | ||
| 95 | extern int drm_crtc_helper_set_config(struct drm_mode_set *set); | ||
| 96 | extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, | ||
| 97 | struct drm_display_mode *mode, | ||
| 98 | int x, int y, | ||
| 99 | struct drm_framebuffer *old_fb); | ||
| 100 | extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc); | ||
| 101 | |||
| 102 | extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, | ||
| 103 | struct drm_mode_fb_cmd *mode_cmd); | ||
| 104 | |||
| 105 | static inline void drm_crtc_helper_add(struct drm_crtc *crtc, | ||
| 106 | const struct drm_crtc_helper_funcs *funcs) | ||
| 107 | { | ||
| 108 | crtc->helper_private = (void *)funcs; | ||
| 109 | } | ||
| 110 | |||
| 111 | static inline void drm_encoder_helper_add(struct drm_encoder *encoder, | ||
| 112 | const struct drm_encoder_helper_funcs *funcs) | ||
| 113 | { | ||
| 114 | encoder->helper_private = (void *)funcs; | ||
| 115 | } | ||
| 116 | |||
| 117 | static inline void drm_connector_helper_add(struct drm_connector *connector, | ||
| 118 | const struct drm_connector_helper_funcs *funcs) | ||
| 119 | { | ||
| 120 | connector->helper_private = (void *)funcs; | ||
| 121 | } | ||
| 122 | |||
| 123 | extern int drm_helper_resume_force_mode(struct drm_device *dev); | ||
| 124 | #endif | ||
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h new file mode 100644 index 000000000000..c707c15f5164 --- /dev/null +++ b/include/drm/drm_edid.h | |||
| @@ -0,0 +1,202 @@ | |||
| 1 | /* | ||
| 2 | * Copyright © 2007-2008 Intel Corporation | ||
| 3 | * Jesse Barnes <jesse.barnes@intel.com> | ||
| 4 | * | ||
| 5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 6 | * copy of this software and associated documentation files (the "Software"), | ||
| 7 | * to deal in the Software without restriction, including without limitation | ||
| 8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 9 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 10 | * Software is furnished to do so, subject to the following conditions: | ||
| 11 | * | ||
| 12 | * The above copyright notice and this permission notice shall be included in | ||
| 13 | * all copies or substantial portions of the Software. | ||
| 14 | * | ||
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 18 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
| 19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
| 20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
| 21 | * OTHER DEALINGS IN THE SOFTWARE. | ||
| 22 | */ | ||
| 23 | #ifndef __DRM_EDID_H__ | ||
| 24 | #define __DRM_EDID_H__ | ||
| 25 | |||
| 26 | #include <linux/types.h> | ||
| 27 | |||
| 28 | #define EDID_LENGTH 128 | ||
| 29 | #define DDC_ADDR 0x50 | ||
| 30 | |||
| 31 | #ifdef BIG_ENDIAN | ||
| 32 | #error "EDID structure is little endian, need big endian versions" | ||
| 33 | #else | ||
| 34 | |||
| 35 | struct est_timings { | ||
| 36 | u8 t1; | ||
| 37 | u8 t2; | ||
| 38 | u8 mfg_rsvd; | ||
| 39 | } __attribute__((packed)); | ||
| 40 | |||
| 41 | struct std_timing { | ||
| 42 | u8 hsize; /* need to multiply by 8 then add 248 */ | ||
| 43 | u8 vfreq:6; /* need to add 60 */ | ||
| 44 | u8 aspect_ratio:2; /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */ | ||
| 45 | } __attribute__((packed)); | ||
| 46 | |||
| 47 | /* If detailed data is pixel timing */ | ||
| 48 | struct detailed_pixel_timing { | ||
| 49 | u8 hactive_lo; | ||
| 50 | u8 hblank_lo; | ||
| 51 | u8 hblank_hi:4; | ||
| 52 | u8 hactive_hi:4; | ||
| 53 | u8 vactive_lo; | ||
| 54 | u8 vblank_lo; | ||
| 55 | u8 vblank_hi:4; | ||
| 56 | u8 vactive_hi:4; | ||
| 57 | u8 hsync_offset_lo; | ||
| 58 | u8 hsync_pulse_width_lo; | ||
| 59 | u8 vsync_pulse_width_lo:4; | ||
| 60 | u8 vsync_offset_lo:4; | ||
| 61 | u8 hsync_pulse_width_hi:2; | ||
| 62 | u8 hsync_offset_hi:2; | ||
| 63 | u8 vsync_pulse_width_hi:2; | ||
| 64 | u8 vsync_offset_hi:2; | ||
| 65 | u8 width_mm_lo; | ||
| 66 | u8 height_mm_lo; | ||
| 67 | u8 height_mm_hi:4; | ||
| 68 | u8 width_mm_hi:4; | ||
| 69 | u8 hborder; | ||
| 70 | u8 vborder; | ||
| 71 | u8 unknown0:1; | ||
| 72 | u8 vsync_positive:1; | ||
| 73 | u8 hsync_positive:1; | ||
| 74 | u8 separate_sync:2; | ||
| 75 | u8 stereo:1; | ||
| 76 | u8 unknown6:1; | ||
| 77 | u8 interlaced:1; | ||
| 78 | } __attribute__((packed)); | ||
| 79 | |||
| 80 | /* If it's not pixel timing, it'll be one of the below */ | ||
| 81 | struct detailed_data_string { | ||
| 82 | u8 str[13]; | ||
| 83 | } __attribute__((packed)); | ||
| 84 | |||
| 85 | struct detailed_data_monitor_range { | ||
| 86 | u8 min_vfreq; | ||
| 87 | u8 max_vfreq; | ||
| 88 | u8 min_hfreq_khz; | ||
| 89 | u8 max_hfreq_khz; | ||
| 90 | u8 pixel_clock_mhz; /* need to multiply by 10 */ | ||
| 91 | u16 sec_gtf_toggle; /* A000=use above, 20=use below */ /* FIXME: byte order */ | ||
| 92 | u8 hfreq_start_khz; /* need to multiply by 2 */ | ||
| 93 | u8 c; /* need to divide by 2 */ | ||
| 94 | u16 m; /* FIXME: byte order */ | ||
| 95 | u8 k; | ||
| 96 | u8 j; /* need to divide by 2 */ | ||
| 97 | } __attribute__((packed)); | ||
| 98 | |||
| 99 | struct detailed_data_wpindex { | ||
| 100 | u8 white_y_lo:2; | ||
| 101 | u8 white_x_lo:2; | ||
| 102 | u8 pad:4; | ||
| 103 | u8 white_x_hi; | ||
| 104 | u8 white_y_hi; | ||
| 105 | u8 gamma; /* need to divide by 100 then add 1 */ | ||
| 106 | } __attribute__((packed)); | ||
| 107 | |||
| 108 | struct detailed_data_color_point { | ||
| 109 | u8 windex1; | ||
| 110 | u8 wpindex1[3]; | ||
| 111 | u8 windex2; | ||
| 112 | u8 wpindex2[3]; | ||
| 113 | } __attribute__((packed)); | ||
| 114 | |||
| 115 | struct detailed_non_pixel { | ||
| 116 | u8 pad1; | ||
| 117 | u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name | ||
| 118 | fb=color point data, fa=standard timing data, | ||
| 119 | f9=undefined, f8=mfg. reserved */ | ||
| 120 | u8 pad2; | ||
| 121 | union { | ||
| 122 | struct detailed_data_string str; | ||
| 123 | struct detailed_data_monitor_range range; | ||
| 124 | struct detailed_data_wpindex color; | ||
| 125 | struct std_timing timings[5]; | ||
| 126 | } data; | ||
| 127 | } __attribute__((packed)); | ||
| 128 | |||
| 129 | #define EDID_DETAIL_STD_MODES 0xfa | ||
| 130 | #define EDID_DETAIL_MONITOR_CPDATA 0xfb | ||
| 131 | #define EDID_DETAIL_MONITOR_NAME 0xfc | ||
| 132 | #define EDID_DETAIL_MONITOR_RANGE 0xfd | ||
| 133 | #define EDID_DETAIL_MONITOR_STRING 0xfe | ||
| 134 | #define EDID_DETAIL_MONITOR_SERIAL 0xff | ||
| 135 | |||
| 136 | struct detailed_timing { | ||
| 137 | u16 pixel_clock; /* need to multiply by 10 KHz */ /* FIXME: byte order */ | ||
| 138 | union { | ||
| 139 | struct detailed_pixel_timing pixel_data; | ||
| 140 | struct detailed_non_pixel other_data; | ||
| 141 | } data; | ||
| 142 | } __attribute__((packed)); | ||
| 143 | |||
| 144 | struct edid { | ||
| 145 | u8 header[8]; | ||
| 146 | /* Vendor & product info */ | ||
| 147 | u8 mfg_id[2]; | ||
| 148 | u8 prod_code[2]; | ||
| 149 | u32 serial; /* FIXME: byte order */ | ||
| 150 | u8 mfg_week; | ||
| 151 | u8 mfg_year; | ||
| 152 | /* EDID version */ | ||
| 153 | u8 version; | ||
| 154 | u8 revision; | ||
| 155 | /* Display info: */ | ||
| 156 | /* input definition */ | ||
| 157 | u8 serration_vsync:1; | ||
| 158 | u8 sync_on_green:1; | ||
| 159 | u8 composite_sync:1; | ||
| 160 | u8 separate_syncs:1; | ||
| 161 | u8 blank_to_black:1; | ||
| 162 | u8 video_level:2; | ||
| 163 | u8 digital:1; /* bits below must be zero if set */ | ||
| 164 | u8 width_cm; | ||
| 165 | u8 height_cm; | ||
| 166 | u8 gamma; | ||
| 167 | /* feature support */ | ||
| 168 | u8 default_gtf:1; | ||
| 169 | u8 preferred_timing:1; | ||
| 170 | u8 standard_color:1; | ||
| 171 | u8 display_type:2; /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */ | ||
| 172 | u8 pm_active_off:1; | ||
| 173 | u8 pm_suspend:1; | ||
| 174 | u8 pm_standby:1; | ||
| 175 | /* Color characteristics */ | ||
| 176 | u8 red_green_lo; | ||
| 177 | u8 black_white_lo; | ||
| 178 | u8 red_x; | ||
| 179 | u8 red_y; | ||
| 180 | u8 green_x; | ||
| 181 | u8 green_y; | ||
| 182 | u8 blue_x; | ||
| 183 | u8 blue_y; | ||
| 184 | u8 white_x; | ||
| 185 | u8 white_y; | ||
| 186 | /* Est. timings and mfg rsvd timings*/ | ||
| 187 | struct est_timings established_timings; | ||
| 188 | /* Standard timings 1-8*/ | ||
| 189 | struct std_timing standard_timings[8]; | ||
| 190 | /* Detailing timings 1-4 */ | ||
| 191 | struct detailed_timing detailed_timings[4]; | ||
| 192 | /* Number of 128 byte ext. blocks */ | ||
| 193 | u8 extensions; | ||
| 194 | /* Checksum */ | ||
| 195 | u8 checksum; | ||
| 196 | } __attribute__((packed)); | ||
| 197 | |||
| 198 | #endif /* little endian structs */ | ||
| 199 | |||
| 200 | #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8)) | ||
| 201 | |||
| 202 | #endif /* __DRM_EDID_H__ */ | ||
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h new file mode 100644 index 000000000000..601d2bd839f6 --- /dev/null +++ b/include/drm/drm_mode.h | |||
| @@ -0,0 +1,271 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> | ||
| 3 | * Copyright (c) 2007 Jakob Bornecrantz <wallbraker@gmail.com> | ||
| 4 | * Copyright (c) 2008 Red Hat Inc. | ||
| 5 | * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA | ||
| 6 | * Copyright (c) 2007-2008 Intel Corporation | ||
| 7 | * | ||
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
| 9 | * copy of this software and associated documentation files (the "Software"), | ||
| 10 | * to deal in the Software without restriction, including without limitation | ||
| 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
| 12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
| 13 | * Software is furnished to do so, subject to the following conditions: | ||
| 14 | * | ||
| 15 | * The above copyright notice and this permission notice shall be included in | ||
| 16 | * all copies or substantial portions of the Software. | ||
| 17 | * | ||
| 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 23 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
| 24 | * IN THE SOFTWARE. | ||
| 25 | */ | ||
| 26 | |||
| 27 | #ifndef _DRM_MODE_H | ||
| 28 | #define _DRM_MODE_H | ||
| 29 | |||
| 30 | #if !defined(__KERNEL__) && !defined(_KERNEL) | ||
| 31 | #include <stdint.h> | ||
| 32 | #else | ||
| 33 | #include <linux/kernel.h> | ||
| 34 | #endif | ||
| 35 | |||
| 36 | #define DRM_DISPLAY_INFO_LEN 32 | ||
| 37 | #define DRM_CONNECTOR_NAME_LEN 32 | ||
| 38 | #define DRM_DISPLAY_MODE_LEN 32 | ||
| 39 | #define DRM_PROP_NAME_LEN 32 | ||
| 40 | |||
| 41 | #define DRM_MODE_TYPE_BUILTIN (1<<0) | ||
| 42 | #define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) | ||
| 43 | #define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN) | ||
| 44 | #define DRM_MODE_TYPE_PREFERRED (1<<3) | ||
| 45 | #define DRM_MODE_TYPE_DEFAULT (1<<4) | ||
| 46 | #define DRM_MODE_TYPE_USERDEF (1<<5) | ||
| 47 | #define DRM_MODE_TYPE_DRIVER (1<<6) | ||
| 48 | |||
| 49 | /* Video mode flags */ | ||
| 50 | /* bit compatible with the xorg definitions. */ | ||
| 51 | #define DRM_MODE_FLAG_PHSYNC (1<<0) | ||
| 52 | #define DRM_MODE_FLAG_NHSYNC (1<<1) | ||
| 53 | #define DRM_MODE_FLAG_PVSYNC (1<<2) | ||
| 54 | #define DRM_MODE_FLAG_NVSYNC (1<<3) | ||
| 55 | #define DRM_MODE_FLAG_INTERLACE (1<<4) | ||
| 56 | #define DRM_MODE_FLAG_DBLSCAN (1<<5) | ||
| 57 | #define DRM_MODE_FLAG_CSYNC (1<<6) | ||
| 58 | #define DRM_MODE_FLAG_PCSYNC (1<<7) | ||
| 59 | #define DRM_MODE_FLAG_NCSYNC (1<<8) | ||
| 60 | #define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */ | ||
| 61 | #define DRM_MODE_FLAG_BCAST (1<<10) | ||
| 62 | #define DRM_MODE_FLAG_PIXMUX (1<<11) | ||
| 63 | #define DRM_MODE_FLAG_DBLCLK (1<<12) | ||
| 64 | #define DRM_MODE_FLAG_CLKDIV2 (1<<13) | ||
| 65 | |||
| 66 | /* DPMS flags */ | ||
| 67 | /* bit compatible with the xorg definitions. */ | ||
| 68 | #define DRM_MODE_DPMS_ON 0 | ||
| 69 | #define DRM_MODE_DPMS_STANDBY 1 | ||
| 70 | #define DRM_MODE_DPMS_SUSPEND 2 | ||
| 71 | #define DRM_MODE_DPMS_OFF 3 | ||
| 72 | |||
| 73 | /* Scaling mode options */ | ||
| 74 | #define DRM_MODE_SCALE_NON_GPU 0 | ||
| 75 | #define DRM_MODE_SCALE_FULLSCREEN 1 | ||
| 76 | #define DRM_MODE_SCALE_NO_SCALE 2 | ||
| 77 | #define DRM_MODE_SCALE_ASPECT 3 | ||
| 78 | |||
| 79 | /* Dithering mode options */ | ||
| 80 | #define DRM_MODE_DITHERING_OFF 0 | ||
| 81 | #define DRM_MODE_DITHERING_ON 1 | ||
| 82 | |||
| 83 | struct drm_mode_modeinfo { | ||
| 84 | uint32_t clock; | ||
| 85 | uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew; | ||
| 86 | uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan; | ||
| 87 | |||
| 88 | uint32_t vrefresh; /* vertical refresh * 1000 */ | ||
| 89 | |||
| 90 | uint32_t flags; | ||
| 91 | uint32_t type; | ||
| 92 | char name[DRM_DISPLAY_MODE_LEN]; | ||
| 93 | }; | ||
| 94 | |||
| 95 | struct drm_mode_card_res { | ||
| 96 | uint64_t fb_id_ptr; | ||
| 97 | uint64_t crtc_id_ptr; | ||
| 98 | uint64_t connector_id_ptr; | ||
| 99 | uint64_t encoder_id_ptr; | ||
| 100 | uint32_t count_fbs; | ||
| 101 | uint32_t count_crtcs; | ||
| 102 | uint32_t count_connectors; | ||
| 103 | uint32_t count_encoders; | ||
| 104 | uint32_t min_width, max_width; | ||
| 105 | uint32_t min_height, max_height; | ||
| 106 | }; | ||
| 107 | |||
| 108 | struct drm_mode_crtc { | ||
| 109 | uint64_t set_connectors_ptr; | ||
| 110 | uint32_t count_connectors; | ||
| 111 | |||
| 112 | uint32_t crtc_id; /**< Id */ | ||
| 113 | uint32_t fb_id; /**< Id of framebuffer */ | ||
| 114 | |||
| 115 | uint32_t x, y; /**< Position on the frameuffer */ | ||
| 116 | |||
| 117 | uint32_t gamma_size; | ||
| 118 | uint32_t mode_valid; | ||
| 119 | struct drm_mode_modeinfo mode; | ||
| 120 | }; | ||
| 121 | |||
| 122 | #define DRM_MODE_ENCODER_NONE 0 | ||
| 123 | #define DRM_MODE_ENCODER_DAC 1 | ||
| 124 | #define DRM_MODE_ENCODER_TMDS 2 | ||
| 125 | #define DRM_MODE_ENCODER_LVDS 3 | ||
| 126 | #define DRM_MODE_ENCODER_TVDAC 4 | ||
| 127 | |||
| 128 | struct drm_mode_get_encoder { | ||
| 129 | uint32_t encoder_id; | ||
| 130 | uint32_t encoder_type; | ||
| 131 | |||
| 132 | uint32_t crtc_id; /**< Id of crtc */ | ||
| 133 | |||
| 134 | uint32_t possible_crtcs; | ||
| 135 | uint32_t possible_clones; | ||
| 136 | }; | ||
| 137 | |||
| 138 | /* This is for connectors with multiple signal types. */ | ||
| 139 | /* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ | ||
| 140 | #define DRM_MODE_SUBCONNECTOR_Automatic 0 | ||
| 141 | #define DRM_MODE_SUBCONNECTOR_Unknown 0 | ||
| 142 | #define DRM_MODE_SUBCONNECTOR_DVID 3 | ||
| 143 | #define DRM_MODE_SUBCONNECTOR_DVIA 4 | ||
| 144 | #define DRM_MODE_SUBCONNECTOR_Composite 5 | ||
| 145 | #define DRM_MODE_SUBCONNECTOR_SVIDEO 6 | ||
| 146 | #define DRM_MODE_SUBCONNECTOR_Component 8 | ||
| 147 | |||
| 148 | #define DRM_MODE_CONNECTOR_Unknown 0 | ||
| 149 | #define DRM_MODE_CONNECTOR_VGA 1 | ||
| 150 | #define DRM_MODE_CONNECTOR_DVII 2 | ||
| 151 | #define DRM_MODE_CONNECTOR_DVID 3 | ||
| 152 | #define DRM_MODE_CONNECTOR_DVIA 4 | ||
| 153 | #define DRM_MODE_CONNECTOR_Composite 5 | ||
| 154 | #define DRM_MODE_CONNECTOR_SVIDEO 6 | ||
| 155 | #define DRM_MODE_CONNECTOR_LVDS 7 | ||
| 156 | #define DRM_MODE_CONNECTOR_Component 8 | ||
| 157 | #define DRM_MODE_CONNECTOR_9PinDIN 9 | ||
| 158 | #define DRM_MODE_CONNECTOR_DisplayPort 10 | ||
| 159 | #define DRM_MODE_CONNECTOR_HDMIA 11 | ||
| 160 | #define DRM_MODE_CONNECTOR_HDMIB 12 | ||
| 161 | |||
| 162 | struct drm_mode_get_connector { | ||
| 163 | |||
| 164 | uint64_t encoders_ptr; | ||
| 165 | uint64_t modes_ptr; | ||
| 166 | uint64_t props_ptr; | ||
| 167 | uint64_t prop_values_ptr; | ||
| 168 | |||
| 169 | uint32_t count_modes; | ||
| 170 | uint32_t count_props; | ||
| 171 | uint32_t count_encoders; | ||
| 172 | |||
| 173 | uint32_t encoder_id; /**< Current Encoder */ | ||
| 174 | uint32_t connector_id; /**< Id */ | ||
| 175 | uint32_t connector_type; | ||
| 176 | uint32_t connector_type_id; | ||
| 177 | |||
| 178 | uint32_t connection; | ||
| 179 | uint32_t mm_width, mm_height; /**< HxW in millimeters */ | ||
| 180 | uint32_t subpixel; | ||
| 181 | }; | ||
| 182 | |||
| 183 | #define DRM_MODE_PROP_PENDING (1<<0) | ||
| 184 | #define DRM_MODE_PROP_RANGE (1<<1) | ||
| 185 | #define DRM_MODE_PROP_IMMUTABLE (1<<2) | ||
| 186 | #define DRM_MODE_PROP_ENUM (1<<3) /* enumerated type with text strings */ | ||
| 187 | #define DRM_MODE_PROP_BLOB (1<<4) | ||
| 188 | |||
| 189 | struct drm_mode_property_enum { | ||
| 190 | uint64_t value; | ||
| 191 | char name[DRM_PROP_NAME_LEN]; | ||
| 192 | }; | ||
| 193 | |||
| 194 | struct drm_mode_get_property { | ||
| 195 | uint64_t values_ptr; /* values and blob lengths */ | ||
| 196 | uint64_t enum_blob_ptr; /* enum and blob id ptrs */ | ||
| 197 | |||
| 198 | uint32_t prop_id; | ||
| 199 | uint32_t flags; | ||
| 200 | char name[DRM_PROP_NAME_LEN]; | ||
| 201 | |||
| 202 | uint32_t count_values; | ||
| 203 | uint32_t count_enum_blobs; | ||
| 204 | }; | ||
| 205 | |||
| 206 | struct drm_mode_connector_set_property { | ||
| 207 | uint64_t value; | ||
| 208 | uint32_t prop_id; | ||
| 209 | uint32_t connector_id; | ||
| 210 | }; | ||
| 211 | |||
| 212 | struct drm_mode_get_blob { | ||
| 213 | uint32_t blob_id; | ||
| 214 | uint32_t length; | ||
| 215 | uint64_t data; | ||
| 216 | }; | ||
| 217 | |||
| 218 | struct drm_mode_fb_cmd { | ||
| 219 | uint32_t fb_id; | ||
| 220 | uint32_t width, height; | ||
| 221 | uint32_t pitch; | ||
| 222 | uint32_t bpp; | ||
| 223 | uint32_t depth; | ||
| 224 | /* driver specific handle */ | ||
| 225 | uint32_t handle; | ||
| 226 | }; | ||
| 227 | |||
| 228 | struct drm_mode_mode_cmd { | ||
| 229 | uint32_t connector_id; | ||
| 230 | struct drm_mode_modeinfo mode; | ||
| 231 | }; | ||
| 232 | |||
| 233 | #define DRM_MODE_CURSOR_BO (1<<0) | ||
| 234 | #define DRM_MODE_CURSOR_MOVE (1<<1) | ||
| 235 | |||
| 236 | /* | ||
| 237 | * depending on the value in flags diffrent members are used. | ||
| 238 | * | ||
| 239 | * CURSOR_BO uses | ||
| 240 | * crtc | ||
| 241 | * width | ||
| 242 | * height | ||
| 243 | * handle - if 0 turns the cursor of | ||
| 244 | * | ||
| 245 | * CURSOR_MOVE uses | ||
| 246 | * crtc | ||
| 247 | * x | ||
| 248 | * y | ||
| 249 | */ | ||
| 250 | struct drm_mode_cursor { | ||
| 251 | uint32_t flags; | ||
| 252 | uint32_t crtc_id; | ||
| 253 | int32_t x; | ||
| 254 | int32_t y; | ||
| 255 | uint32_t width; | ||
| 256 | uint32_t height; | ||
| 257 | /* driver specific handle */ | ||
| 258 | uint32_t handle; | ||
| 259 | }; | ||
| 260 | |||
| 261 | struct drm_mode_crtc_lut { | ||
| 262 | uint32_t crtc_id; | ||
| 263 | uint32_t gamma_size; | ||
| 264 | |||
| 265 | /* pointers to arrays */ | ||
| 266 | uint64_t red; | ||
| 267 | uint64_t green; | ||
| 268 | uint64_t blue; | ||
| 269 | }; | ||
| 270 | |||
| 271 | #endif | ||
diff --git a/include/drm/drm_sarea.h b/include/drm/drm_sarea.h index 480037331e4e..ee5389d22c64 100644 --- a/include/drm/drm_sarea.h +++ b/include/drm/drm_sarea.h | |||
| @@ -36,12 +36,12 @@ | |||
| 36 | 36 | ||
| 37 | /* SAREA area needs to be at least a page */ | 37 | /* SAREA area needs to be at least a page */ |
| 38 | #if defined(__alpha__) | 38 | #if defined(__alpha__) |
| 39 | #define SAREA_MAX 0x2000 | 39 | #define SAREA_MAX 0x2000U |
| 40 | #elif defined(__ia64__) | 40 | #elif defined(__ia64__) |
| 41 | #define SAREA_MAX 0x10000 /* 64kB */ | 41 | #define SAREA_MAX 0x10000U /* 64kB */ |
| 42 | #else | 42 | #else |
| 43 | /* Intel 830M driver needs at least 8k SAREA */ | 43 | /* Intel 830M driver needs at least 8k SAREA */ |
| 44 | #define SAREA_MAX 0x2000 | 44 | #define SAREA_MAX 0x2000U |
| 45 | #endif | 45 | #endif |
| 46 | 46 | ||
| 47 | /** Maximum number of drawables in the SAREA */ | 47 | /** Maximum number of drawables in the SAREA */ |
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index 152b34da927c..b3bcf72dc656 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h | |||
| @@ -113,8 +113,31 @@ typedef struct _drm_i915_sarea { | |||
| 113 | int pipeB_y; | 113 | int pipeB_y; |
| 114 | int pipeB_w; | 114 | int pipeB_w; |
| 115 | int pipeB_h; | 115 | int pipeB_h; |
| 116 | |||
| 117 | /* fill out some space for old userspace triple buffer */ | ||
| 118 | drm_handle_t unused_handle; | ||
| 119 | uint32_t unused1, unused2, unused3; | ||
| 120 | |||
| 121 | /* buffer object handles for static buffers. May change | ||
| 122 | * over the lifetime of the client. | ||
| 123 | */ | ||
| 124 | uint32_t front_bo_handle; | ||
| 125 | uint32_t back_bo_handle; | ||
| 126 | uint32_t unused_bo_handle; | ||
| 127 | uint32_t depth_bo_handle; | ||
| 128 | |||
| 116 | } drm_i915_sarea_t; | 129 | } drm_i915_sarea_t; |
| 117 | 130 | ||
| 131 | /* due to userspace building against these headers we need some compat here */ | ||
| 132 | #define planeA_x pipeA_x | ||
| 133 | #define planeA_y pipeA_y | ||
| 134 | #define planeA_w pipeA_w | ||
| 135 | #define planeA_h pipeA_h | ||
| 136 | #define planeB_x pipeB_x | ||
| 137 | #define planeB_y pipeB_y | ||
| 138 | #define planeB_w pipeB_w | ||
| 139 | #define planeB_h pipeB_h | ||
| 140 | |||
| 118 | /* Flags for perf_boxes | 141 | /* Flags for perf_boxes |
| 119 | */ | 142 | */ |
| 120 | #define I915_BOX_RING_EMPTY 0x1 | 143 | #define I915_BOX_RING_EMPTY 0x1 |
| @@ -160,6 +183,7 @@ typedef struct _drm_i915_sarea { | |||
| 160 | #define DRM_I915_GEM_SET_TILING 0x21 | 183 | #define DRM_I915_GEM_SET_TILING 0x21 |
| 161 | #define DRM_I915_GEM_GET_TILING 0x22 | 184 | #define DRM_I915_GEM_GET_TILING 0x22 |
| 162 | #define DRM_I915_GEM_GET_APERTURE 0x23 | 185 | #define DRM_I915_GEM_GET_APERTURE 0x23 |
| 186 | #define DRM_I915_GEM_MMAP_GTT 0x24 | ||
| 163 | 187 | ||
| 164 | #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) | 188 | #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) |
| 165 | #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) | 189 | #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) |
| @@ -177,6 +201,8 @@ typedef struct _drm_i915_sarea { | |||
| 177 | #define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t) | 201 | #define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t) |
| 178 | #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) | 202 | #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) |
| 179 | #define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) | 203 | #define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) |
| 204 | #define DRM_IOCTL_I915_GEM_INIT DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_INIT, struct drm_i915_gem_init) | ||
| 205 | #define DRM_IOCTL_I915_GEM_EXECBUFFER DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer) | ||
| 180 | #define DRM_IOCTL_I915_GEM_PIN DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_PIN, struct drm_i915_gem_pin) | 206 | #define DRM_IOCTL_I915_GEM_PIN DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_PIN, struct drm_i915_gem_pin) |
| 181 | #define DRM_IOCTL_I915_GEM_UNPIN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_UNPIN, struct drm_i915_gem_unpin) | 207 | #define DRM_IOCTL_I915_GEM_UNPIN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_UNPIN, struct drm_i915_gem_unpin) |
| 182 | #define DRM_IOCTL_I915_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy) | 208 | #define DRM_IOCTL_I915_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy) |
| @@ -187,6 +213,7 @@ typedef struct _drm_i915_sarea { | |||
| 187 | #define DRM_IOCTL_I915_GEM_PREAD DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread) | 213 | #define DRM_IOCTL_I915_GEM_PREAD DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread) |
| 188 | #define DRM_IOCTL_I915_GEM_PWRITE DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite) | 214 | #define DRM_IOCTL_I915_GEM_PWRITE DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite) |
| 189 | #define DRM_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap) | 215 | #define DRM_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap) |
| 216 | #define DRM_IOCTL_I915_GEM_MMAP_GTT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_GTT, struct drm_i915_gem_mmap_gtt) | ||
| 190 | #define DRM_IOCTL_I915_GEM_SET_DOMAIN DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SET_DOMAIN, struct drm_i915_gem_set_domain) | 217 | #define DRM_IOCTL_I915_GEM_SET_DOMAIN DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SET_DOMAIN, struct drm_i915_gem_set_domain) |
| 191 | #define DRM_IOCTL_I915_GEM_SW_FINISH DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SW_FINISH, struct drm_i915_gem_sw_finish) | 218 | #define DRM_IOCTL_I915_GEM_SW_FINISH DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SW_FINISH, struct drm_i915_gem_sw_finish) |
| 192 | #define DRM_IOCTL_I915_GEM_SET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_SET_TILING, struct drm_i915_gem_set_tiling) | 219 | #define DRM_IOCTL_I915_GEM_SET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_SET_TILING, struct drm_i915_gem_set_tiling) |
| @@ -196,7 +223,7 @@ typedef struct _drm_i915_sarea { | |||
| 196 | /* Allow drivers to submit batchbuffers directly to hardware, relying | 223 | /* Allow drivers to submit batchbuffers directly to hardware, relying |
| 197 | * on the security mechanisms provided by hardware. | 224 | * on the security mechanisms provided by hardware. |
| 198 | */ | 225 | */ |
| 199 | typedef struct _drm_i915_batchbuffer { | 226 | typedef struct drm_i915_batchbuffer { |
| 200 | int start; /* agp offset */ | 227 | int start; /* agp offset */ |
| 201 | int used; /* nr bytes in use */ | 228 | int used; /* nr bytes in use */ |
| 202 | int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ | 229 | int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ |
| @@ -382,6 +409,18 @@ struct drm_i915_gem_mmap { | |||
| 382 | uint64_t addr_ptr; | 409 | uint64_t addr_ptr; |
| 383 | }; | 410 | }; |
| 384 | 411 | ||
| 412 | struct drm_i915_gem_mmap_gtt { | ||
| 413 | /** Handle for the object being mapped. */ | ||
| 414 | uint32_t handle; | ||
| 415 | uint32_t pad; | ||
| 416 | /** | ||
| 417 | * Fake offset to use for subsequent mmap call | ||
| 418 | * | ||
| 419 | * This is a fixed-size type for 32/64 compatibility. | ||
| 420 | */ | ||
| 421 | uint64_t offset; | ||
| 422 | }; | ||
| 423 | |||
| 385 | struct drm_i915_gem_set_domain { | 424 | struct drm_i915_gem_set_domain { |
| 386 | /** Handle for the object */ | 425 | /** Handle for the object */ |
| 387 | uint32_t handle; | 426 | uint32_t handle; |
diff --git a/include/linux/console.h b/include/linux/console.h index 248e6e3b9b73..a67a90cf8268 100644 --- a/include/linux/console.h +++ b/include/linux/console.h | |||
| @@ -153,4 +153,8 @@ void vcs_remove_sysfs(struct tty_struct *tty); | |||
| 153 | #define VESA_HSYNC_SUSPEND 2 | 153 | #define VESA_HSYNC_SUSPEND 2 |
| 154 | #define VESA_POWERDOWN 3 | 154 | #define VESA_POWERDOWN 3 |
| 155 | 155 | ||
| 156 | #ifdef CONFIG_VGA_CONSOLE | ||
| 157 | extern bool vgacon_text_force(void); | ||
| 158 | #endif | ||
| 159 | |||
| 156 | #endif /* _LINUX_CONSOLE_H */ | 160 | #endif /* _LINUX_CONSOLE_H */ |
