diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-12-30 20:25:49 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-12-30 20:25:49 -0500 |
commit | 3f4b5c5d275608d42ff54c4981307f9a5c75ea4a (patch) | |
tree | 748b347885b1b62d1a135892cb025d3485444215 | |
parent | a4ba2e9e36d10ace6f5ca222c1ff3e5024d75f1a (diff) | |
parent | aa5966296675a5092505f68d72563d5939a92353 (diff) |
Merge branch 'drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6
* 'drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (37 commits)
drm/i915: fix modeset devname allocation + agp init return check.
drm/i915: Remove redundant test in error path.
drm: Add a debug node for vblank state.
drm: Avoid use-before-null-test on dev in drm_cleanup().
drm/i915: Don't print to dmesg when taking signal during object_pin.
drm: pin new and unpin old buffer when setting a mode.
drm/i915: un-EXPORT and make 'intelfb_panic' static
drm/i915: Delete unused, pointless i915_driver_firstopen.
drm/i915: fix sparse warnings: returning void-valued expression
drm/i915: fix sparse warnings: move 'extern' decls to header file
drm/i915: fix sparse warnings: make symbols static
drm/i915: fix sparse warnings: declare one-bit bitfield as unsigned
drm/i915: Don't double-unpin buffers if we take a signal in evict_everything().
drm/i915: Fix fbcon setup to align display pitch to 64b.
drm/i915: Add missing userland definitions for gem init/execbuffer.
i915/drm: provide compat defines for userspace for certain struct members.
drm: drop DRM_IOCTL_MODE_REPLACEFB, add+remove works just as well.
drm: sanitise drm modesetting API + remove unused hotplug
drm: fix allowing master ioctls on non-master fds.
drm/radeon: use locked rmmap to remove sarea mapping.
...
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 */ |